v0.10.5.1
This commit is contained in:
9
.github/ISSUE_TEMPLATE/release-checklist.md
vendored
9
.github/ISSUE_TEMPLATE/release-checklist.md
vendored
@@ -7,11 +7,18 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**QA**
|
||||
- [ ] Play through tutorials and verify that they are working.
|
||||
- [ ] Do a smoketest on all game modes
|
||||
- [ ] Smoketest server hosting (dedicated and client)
|
||||
- [ ] Install Trick or Trauma and check you can start a round with no obvious issues/errors (to make sure we didn't unintentionally break compatibility with older mods).
|
||||
- [ ] Play through one single player campaign round.
|
||||
- [ ] Do a smoketest in a language other than English.
|
||||
|
||||
**Code:**
|
||||
- [ ] Build and upload dedicated server
|
||||
- [ ] Verify that Vanilla content package hashes match between Windows/Mac/Linux
|
||||
- [ ] Run "checkmissingloca" command to make sure localization files are up-to-date.
|
||||
- [ ] Install Trick or Trauma and check you can start a round with no obvious issues/errors (to make sure we didn't unintentionally break compatibility with older mods).
|
||||
- [ ] Prepare new main menu content (changelog)
|
||||
- [ ] Prepare public github repo for pushing the new changes
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ namespace Barotrauma
|
||||
if (targetPos == Vector2.Zero)
|
||||
{
|
||||
Vector2 moveInput = Vector2.Zero;
|
||||
if (allowMove)
|
||||
if (allowMove && !Freeze)
|
||||
{
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using FarseerPhysics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -64,6 +63,27 @@ namespace Barotrauma
|
||||
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60 + offset), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ObjectiveManager.Objectives.Count; i++)
|
||||
{
|
||||
var objective = ObjectiveManager.Objectives[i];
|
||||
int offsetMultiplier;
|
||||
if (ObjectiveManager.CurrentOrder == null)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
offsetMultiplier = i - 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offsetMultiplier = i + 1;
|
||||
}
|
||||
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(120, offsetMultiplier * 18 + 100), $"{objective.DebugTag} ({objective.Priority.FormatZeroDecimal()})", Color.White, Color.Black * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
if (steeringManager is IndoorsSteeringManager pathSteering)
|
||||
|
||||
@@ -409,11 +409,6 @@ namespace Barotrauma
|
||||
|
||||
emitter.Emit(1.0f, limb.WorldPosition, character.CurrentHull, amountMultiplier: gibParticleAmount);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(character.BloodDecalName))
|
||||
{
|
||||
character.CurrentHull?.AddDecal(character.BloodDecalName, limb.WorldPosition, MathHelper.Clamp(limb.Mass, 0.5f, 2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
if (playSound)
|
||||
|
||||
@@ -97,8 +97,6 @@ namespace Barotrauma
|
||||
set { chromaticAberrationStrength = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public string BloodDecalName => Params.BloodDecal;
|
||||
|
||||
private readonly List<ParticleEmitter> bloodEmitters = new List<ParticleEmitter>();
|
||||
public IEnumerable<ParticleEmitter> BloodEmitters
|
||||
{
|
||||
@@ -617,7 +615,7 @@ namespace Barotrauma
|
||||
|
||||
partial void SetOrderProjSpecific(Order order, string orderOption)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption);
|
||||
GameMain.GameSession?.CrewManager?.AddCurrentOrderIcon(this, order, orderOption);
|
||||
}
|
||||
|
||||
public static void AddAllToGUIUpdateList()
|
||||
@@ -786,7 +784,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + CampaignInteractionType);
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
|
||||
if (iconStyle != null)
|
||||
{
|
||||
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
|
||||
@@ -825,15 +823,19 @@ namespace Barotrauma
|
||||
/// Creates a progress bar that's "linked" to the specified object (or updates an existing one if there's one already linked to the object)
|
||||
/// The progress bar will automatically fade out after 1 sec if the method hasn't been called during that time
|
||||
/// </summary>
|
||||
public HUDProgressBar UpdateHUDProgressBar(object linkedObject, Vector2 worldPosition, float progress, Color emptyColor, Color fullColor)
|
||||
public HUDProgressBar UpdateHUDProgressBar(object linkedObject, Vector2 worldPosition, float progress, Color emptyColor, Color fullColor, string textTag = "")
|
||||
{
|
||||
if (controlled != this) return null;
|
||||
if (controlled != this) { return null; }
|
||||
|
||||
if (!hudProgressBars.TryGetValue(linkedObject, out HUDProgressBar progressBar))
|
||||
{
|
||||
progressBar = new HUDProgressBar(worldPosition, Submarine, emptyColor, fullColor);
|
||||
progressBar = new HUDProgressBar(worldPosition, Submarine, emptyColor, fullColor, textTag);
|
||||
hudProgressBars.Add(linkedObject, progressBar);
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar.TextTag = textTag;
|
||||
}
|
||||
|
||||
progressBar.WorldPosition = worldPosition;
|
||||
progressBar.FadeTimer = Math.Max(progressBar.FadeTimer, 1.0f);
|
||||
@@ -859,7 +861,7 @@ namespace Barotrauma
|
||||
}
|
||||
var selectedSound = matchingSounds.GetRandom();
|
||||
if (selectedSound?.Sound == null) { return; }
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, CurrentHull);
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, AnimController.WorldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: CurrentHull);
|
||||
soundTimer = soundInterval;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ namespace Barotrauma
|
||||
return
|
||||
character?.Inventory != null &&
|
||||
character.AllowInput &&
|
||||
!character.LockHands &&
|
||||
(controller?.User != character || !controller.HideHUD) &&
|
||||
!IsCampaignInterfaceOpen &&
|
||||
!ConversationAction.FadeScreenToBlack;
|
||||
@@ -227,7 +226,7 @@ namespace Barotrauma
|
||||
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
|
||||
}
|
||||
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen)
|
||||
if (!character.IsIncapacitated && character.Stun <= 0.0f && !IsCampaignInterfaceOpen && (!character.IsKeyDown(InputType.Aim) || character.SelectedItems.Any(it => it?.GetComponent<Sprayer>() == null)))
|
||||
{
|
||||
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
|
||||
{
|
||||
@@ -307,6 +306,14 @@ namespace Barotrauma
|
||||
{
|
||||
progressBar.Draw(spriteBatch, cam);
|
||||
}
|
||||
|
||||
foreach (Character npc in Character.CharacterList)
|
||||
{
|
||||
if (npc.CampaignInteractionType == CampaignMode.InteractionType.None || npc.Submarine != character.Submarine || npc.IsDead || npc.IsIncapacitated) { continue; }
|
||||
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionIcon." + npc.CampaignInteractionType);
|
||||
GUI.DrawIndicator(spriteBatch, npc.WorldPosition, cam, 500.0f, iconStyle.GetDefaultSprite(), iconStyle.Color);
|
||||
}
|
||||
}
|
||||
|
||||
if (character.SelectedConstruction != null &&
|
||||
@@ -355,7 +362,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (ShouldDrawInventory(character))
|
||||
{
|
||||
character.Inventory.Locked = LockInventory(character);
|
||||
character.Inventory.Locked = character == Character.Controlled && LockInventory(character);
|
||||
character.Inventory.DrawOwn(spriteBatch);
|
||||
character.Inventory.CurrentLayout = CharacterHealth.OpenHealthWindow == null && character.SelectedCharacter == null ?
|
||||
CharacterInventory.Layout.Default :
|
||||
@@ -369,14 +376,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.SelectedCharacter.CanInventoryBeAccessed)
|
||||
{
|
||||
///character.Inventory.CurrentLayout = Alignment.Left;
|
||||
character.SelectedCharacter.Inventory.Locked = false;
|
||||
character.SelectedCharacter.Inventory.CurrentLayout = CharacterInventory.Layout.Left;
|
||||
character.SelectedCharacter.Inventory.DrawOwn(spriteBatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
//character.Inventory.CurrentLayout = (CharacterHealth.OpenHealthWindow == null) ? Alignment.Center : Alignment.Left;
|
||||
}
|
||||
if (CharacterHealth.OpenHealthWindow == character.SelectedCharacter.CharacterHealth)
|
||||
{
|
||||
character.SelectedCharacter.CharacterHealth.Alignment = Alignment.Left;
|
||||
@@ -450,7 +453,6 @@ namespace Barotrauma
|
||||
private static bool LockInventory(Character character)
|
||||
{
|
||||
if (character?.Inventory == null || !character.AllowInput || character.LockHands || IsCampaignInterfaceOpen) { return true; }
|
||||
|
||||
return character.ShouldLockHud();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (this != Controlled)
|
||||
{
|
||||
if (GameMain.Client.EndCinematic != null) // Freezes the characters during the ending cinematic
|
||||
if (GameMain.Client.EndCinematic != null &&
|
||||
GameMain.Client.EndCinematic.Running) // Freezes the characters during the ending cinematic
|
||||
{
|
||||
AnimController.Frozen = true;
|
||||
memState.Clear();
|
||||
|
||||
@@ -38,25 +38,43 @@ namespace Barotrauma
|
||||
|
||||
public Vector2 Size;
|
||||
|
||||
private Submarine parentSub;
|
||||
private readonly Submarine parentSub;
|
||||
public string Text
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine = null)
|
||||
: this(worldPosition, parentSubmarine, GUI.Style.Red, GUI.Style.Green)
|
||||
private string textTag;
|
||||
public string TextTag
|
||||
{
|
||||
get { return textTag; }
|
||||
set
|
||||
{
|
||||
if (textTag == value) { return; }
|
||||
textTag = value;
|
||||
Text = string.IsNullOrEmpty(textTag) ? string.Empty : TextManager.Get(textTag);
|
||||
}
|
||||
}
|
||||
|
||||
public HUDProgressBar(Vector2 worldPosition, string textTag, Submarine parentSubmarine = null)
|
||||
: this(worldPosition, parentSubmarine, GUI.Style.Red, GUI.Style.Green, textTag)
|
||||
{
|
||||
}
|
||||
|
||||
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine, Color emptyColor, Color fullColor)
|
||||
public HUDProgressBar(Vector2 worldPosition, Submarine parentSubmarine, Color emptyColor, Color fullColor, string textTag)
|
||||
{
|
||||
this.emptyColor = emptyColor;
|
||||
this.fullColor = fullColor;
|
||||
|
||||
parentSub = parentSubmarine;
|
||||
|
||||
WorldPosition = worldPosition;
|
||||
|
||||
Size = new Vector2(100.0f, 20.0f);
|
||||
|
||||
FadeTimer = 1.0f;
|
||||
if (!string.IsNullOrEmpty(textTag))
|
||||
{
|
||||
textTag = textTag;
|
||||
Text = TextManager.Get(textTag);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltatime)
|
||||
@@ -76,12 +94,21 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
pos = cam.WorldToScreen(pos);
|
||||
|
||||
Color color = Color.Lerp(emptyColor, fullColor, progress);
|
||||
GUI.DrawProgressBar(spriteBatch,
|
||||
new Vector2(pos.X, -pos.Y),
|
||||
Size, progress,
|
||||
Color.Lerp(emptyColor, fullColor, progress) * a,
|
||||
Size, progress,
|
||||
color * a,
|
||||
Color.White * a * 0.8f);
|
||||
|
||||
if (!string.IsNullOrEmpty(Text))
|
||||
{
|
||||
Vector2 textSize = GUI.SmallFont.MeasureString(Text);
|
||||
Vector2 textPos = new Vector2(pos.X + (Size.X - textSize.X) / 2, pos.Y - textSize.Y * 1.2f);
|
||||
GUI.DrawString(spriteBatch, textPos - Vector2.One, Text, Color.Black * a, font: GUI.SmallFont);
|
||||
GUI.DrawString(spriteBatch, textPos, Text, Color.White * a, font: GUI.SmallFont);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private GUIButton suicideButton;
|
||||
public GUIButton SuicideButton { get; private set; }
|
||||
|
||||
// healthbars
|
||||
private GUIProgressBar healthBar;
|
||||
@@ -247,22 +247,6 @@ namespace Barotrauma
|
||||
|
||||
private GUIFrame healthBarHolder;
|
||||
|
||||
private Point healthBarOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Point(Math.Max(2, GUI.IntScaleCeiling(1.5f)), Math.Min(GUI.IntScaleFloor(18f), 19));
|
||||
}
|
||||
}
|
||||
|
||||
private Point healthBarSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Point(healthBarHolder.Rect.Width - Math.Min(GUI.IntScale(45f), 47), GUI.IntScale(15f));
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element, Character character)
|
||||
{
|
||||
DisplayedVitality = MaxVitality;
|
||||
@@ -290,29 +274,22 @@ namespace Barotrauma
|
||||
healthBarHolder.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size;
|
||||
healthBarHolder.RectTransform.RelativeOffset = Vector2.Zero;
|
||||
|
||||
GUIFrame healthBarBG = new GUIFrame(new RectTransform(Vector2.One, healthBarHolder.RectTransform), style: "CharacterHealthBarBG")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
healthBarShadow = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight),
|
||||
barSize: 1.0f, color: Color.Green, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
|
||||
healthBarShadow = new GUIProgressBar(new RectTransform(Vector2.One, healthBarHolder.RectTransform, Anchor.BottomRight),
|
||||
barSize: 1.0f, color: Color.Green, style: horizontal ? "CharacterHealthBar" : "GUIProgressBarVertical", showFrame: false)
|
||||
{
|
||||
IsHorizontal = horizontal
|
||||
};
|
||||
healthBarShadow.Visible = false;
|
||||
healthShadowSize = 1.0f;
|
||||
|
||||
healthBar = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight),
|
||||
barSize: 1.0f, color: GUI.Style.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
|
||||
healthBar = new GUIProgressBar(new RectTransform(Vector2.One, healthBarHolder.RectTransform, Anchor.BottomRight),
|
||||
barSize: 1.0f, color: GUI.Style.HealthBarColorHigh, style: horizontal ? "CharacterHealthBar" : "GUIProgressBarVertical")
|
||||
{
|
||||
HoverCursor = CursorState.Hand,
|
||||
Enabled = true,
|
||||
IsHorizontal = horizontal
|
||||
};
|
||||
|
||||
healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = healthBarOffset;
|
||||
|
||||
healthInterfaceFrame = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.55f), GUI.Canvas, anchor: Anchor.Center, scaleBasis: ScaleBasis.Smallest), style: "ItemUI");
|
||||
|
||||
var healthInterfaceLayout = new GUILayoutGroup(new RectTransform(Vector2.One / 1.05f, healthInterfaceFrame.RectTransform, anchor: Anchor.Center), true);
|
||||
@@ -519,7 +496,7 @@ namespace Barotrauma
|
||||
|
||||
UpdateAlignment();
|
||||
|
||||
suicideButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.02f), GUI.Canvas, Anchor.TopCenter)
|
||||
SuicideButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.02f), GUI.Canvas, Anchor.TopCenter)
|
||||
{
|
||||
MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f)
|
||||
},
|
||||
@@ -546,7 +523,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
suicideButton.TextBlock.AutoScaleHorizontal = true;
|
||||
SuicideButton.TextBlock.AutoScaleHorizontal = true;
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
@@ -591,9 +568,6 @@ namespace Barotrauma
|
||||
healthBarHolder.RectTransform.NonScaledSize = HUDLayoutSettings.HealthBarArea.Size;
|
||||
healthBarHolder.RectTransform.RelativeOffset = Vector2.Zero;
|
||||
|
||||
healthBar.RectTransform.NonScaledSize = healthBarShadow.RectTransform.NonScaledSize = healthBarSize;
|
||||
healthBar.RectTransform.AbsoluteOffset = healthBarShadow.RectTransform.AbsoluteOffset = healthBarOffset;
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case Alignment.Left:
|
||||
@@ -943,23 +917,7 @@ namespace Barotrauma
|
||||
healthBar.State = GUIComponent.ComponentState.None;
|
||||
}
|
||||
|
||||
suicideButton.Visible = Character == Character.Controlled && !Character.IsDead && Character.IsIncapacitated;
|
||||
|
||||
if (GameMain.GameSession?.Campaign is { } campaign)
|
||||
{
|
||||
RectTransform endRoundButton = campaign?.EndRoundButton.RectTransform;
|
||||
if (endRoundButton != null)
|
||||
{
|
||||
if (suicideButton.Visible)
|
||||
{
|
||||
endRoundButton.ScreenSpaceOffset = new Point(0, suicideButton.Rect.Height);
|
||||
}
|
||||
else if (endRoundButton.ScreenSpaceOffset != Point.Zero)
|
||||
{
|
||||
endRoundButton.ScreenSpaceOffset = Point.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
SuicideButton.Visible = Character == Character.Controlled && !Character.IsDead && Character.IsIncapacitated;
|
||||
|
||||
cprButton.Visible =
|
||||
Character == Character.Controlled?.SelectedCharacter
|
||||
@@ -992,9 +950,9 @@ namespace Barotrauma
|
||||
{
|
||||
healthBarHolder.AddToGUIUpdateList();
|
||||
}
|
||||
if (suicideButton.Visible && Character == Character.Controlled)
|
||||
if (SuicideButton.Visible && Character == Character.Controlled)
|
||||
{
|
||||
suicideButton.AddToGUIUpdateList();
|
||||
SuicideButton.AddToGUIUpdateList();
|
||||
}
|
||||
if (cprButton != null && cprButton.Visible)
|
||||
{
|
||||
@@ -1907,6 +1865,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
|
||||
private readonly List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
|
||||
private readonly List<Pair<AfflictionPrefab.PeriodicEffect, float>> newPeriodicEffects = new List<Pair<AfflictionPrefab.PeriodicEffect, float>>();
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
newAfflictions.Clear();
|
||||
@@ -1920,9 +1880,20 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while reading character health data: affliction with the uint ID " + afflictionID + " not found.");
|
||||
//read the 8 bytes for affliction strength anyway to prevent messing up reading rest of the message
|
||||
_ = inc.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
int _periodicAfflictionCount = inc.ReadByte();
|
||||
for (int j = 0; j < _periodicAfflictionCount; j++)
|
||||
{
|
||||
_ = inc.ReadByte();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8);
|
||||
int periodicAfflictionCount = inc.ReadByte();
|
||||
for (int j = 0; j < periodicAfflictionCount; j++)
|
||||
{
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add(new Pair<AfflictionPrefab.PeriodicEffect, float>(afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newAfflictions.Add(new Pair<AfflictionPrefab, float>(afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
@@ -1940,12 +1911,26 @@ namespace Barotrauma
|
||||
Affliction existingAffliction = afflictions.Find(a => a.Prefab == newAffliction.First);
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
afflictions.Add(newAffliction.First.Instantiate(newAffliction.Second));
|
||||
existingAffliction = newAffliction.First.Instantiate(newAffliction.Second);
|
||||
afflictions.Add(existingAffliction);
|
||||
}
|
||||
else
|
||||
existingAffliction.SetStrength(newAffliction.Second);
|
||||
if (existingAffliction == stunAffliction)
|
||||
{
|
||||
existingAffliction.Strength = newAffliction.Second;
|
||||
if (existingAffliction == stunAffliction) Character.SetStun(existingAffliction.Strength, true, true);
|
||||
Character.SetStun(existingAffliction.Strength, true, true);
|
||||
}
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.First)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.Second - existingAffliction.PeriodicEffectTimers[periodicEffect.First] > periodicEffect.First.MinInterval / 2)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
||||
{
|
||||
existingAffliction.ApplyStatusEffect(effect, deltaTime: 1.0f, this, targetLimb: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1961,9 +1946,20 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while reading character health data: affliction with the uint ID " + afflictionID + " not found.");
|
||||
//read the 8 bytes for affliction strength anyway to prevent messing up reading rest of the message
|
||||
_ = inc.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
int _periodicAfflictionCount = inc.ReadByte();
|
||||
for (int j = 0; j < _periodicAfflictionCount; j++)
|
||||
{
|
||||
_ = inc.ReadByte();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
float afflictionStrength = inc.ReadRangedSingle(0.0f, afflictionPrefab.MaxStrength, 8);
|
||||
int periodicAfflictionCount = inc.ReadByte();
|
||||
for (int j = 0; j < periodicAfflictionCount; j++)
|
||||
{
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add(new Pair<AfflictionPrefab.PeriodicEffect, float>(afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newLimbAfflictions.Add(new Triplet<LimbHealth, AfflictionPrefab, float>(limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
@@ -1980,15 +1976,28 @@ namespace Barotrauma
|
||||
|
||||
foreach (Triplet<LimbHealth, AfflictionPrefab, float> newAffliction in newLimbAfflictions)
|
||||
{
|
||||
if (newAffliction.First != limbHealth) continue;
|
||||
if (newAffliction.First != limbHealth) { continue; }
|
||||
Affliction existingAffliction = limbHealth.Afflictions.Find(a => a.Prefab == newAffliction.Second);
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
limbHealth.Afflictions.Add(newAffliction.Second.Instantiate(newAffliction.Third));
|
||||
existingAffliction = newAffliction.Second.Instantiate(newAffliction.Third);
|
||||
limbHealth.Afflictions.Add(existingAffliction);
|
||||
}
|
||||
else
|
||||
existingAffliction.SetStrength(newAffliction.Third);
|
||||
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
existingAffliction.Strength = newAffliction.Third;
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.First)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.Second - existingAffliction.PeriodicEffectTimers[periodicEffect.First] > periodicEffect.First.MinInterval / 2)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.First] = periodicEffect.Second;
|
||||
foreach (StatusEffect effect in periodicEffect.First.StatusEffects)
|
||||
{
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(newAffliction.First));
|
||||
existingAffliction.ApplyStatusEffect(effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (affliction is AfflictionBleeding)
|
||||
{
|
||||
bleedingDamage += affliction.GetVitalityDecrease(character.CharacterHealth);
|
||||
bleedingDamage += affliction.GetVitalityDecrease(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,7 +455,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (affliction.Prefab.AfflictionType == "damage")
|
||||
{
|
||||
damage += affliction.GetVitalityDecrease(character.CharacterHealth);
|
||||
damage += affliction.GetVitalityDecrease(null);
|
||||
}
|
||||
}
|
||||
float damageMultiplier = 1;
|
||||
@@ -488,7 +488,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// spawn damage particles
|
||||
float damageParticleAmount = Math.Min(damage / 10, 1.0f) * damageMultiplier;
|
||||
float damageParticleAmount = Math.Min(damage / 5, 1.0f) * damageMultiplier;
|
||||
if (damageParticleAmount > 0.001f)
|
||||
{
|
||||
foreach (ParticleEmitter emitter in character.DamageEmitters)
|
||||
@@ -510,11 +510,6 @@ namespace Barotrauma
|
||||
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, sizeMultiplier: bloodParticleSize, amountMultiplier: bloodParticleAmount);
|
||||
}
|
||||
|
||||
if (bloodParticleAmount > 0 && character.CurrentHull != null && !string.IsNullOrEmpty(character.BloodDecalName))
|
||||
{
|
||||
character.CurrentHull.AddDecal(character.BloodDecalName, WorldPosition, MathHelper.Clamp(bloodParticleSize, 0.5f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1086,17 +1086,6 @@ namespace Barotrauma
|
||||
AssignRelayToServer("water|editwater", false);
|
||||
AssignRelayToServer("fire|editfire", false);
|
||||
|
||||
commands.Add(new Command("togglecampaignteleport", "togglecampaignteleport: Toggle on/off teleportation between campaign locations by double clicking on the campaign map.", (string[] args) =>
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign == null)
|
||||
{
|
||||
ThrowError("No campaign active.");
|
||||
return;
|
||||
}
|
||||
GameMain.GameSession.Map.AllowDebugTeleport = !GameMain.GameSession.Map.AllowDebugTeleport;
|
||||
NewMessage((GameMain.GameSession.Map.AllowDebugTeleport ? "Enabled" : "Disabled") + " teleportation on the campaign map.", Color.White);
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("mute", "mute [name]: Prevent the client from speaking to anyone through the voice chat. Using this command requires a permission from the server host.",
|
||||
null,
|
||||
() =>
|
||||
@@ -1136,7 +1125,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||
{
|
||||
int? ingredientPrice = ingredient.ItemPrefab.GetMinPrice();
|
||||
int? ingredientPrice = ingredient.ItemPrefabs.Min(ip => ip.GetMinPrice());
|
||||
if (ingredientPrice.HasValue)
|
||||
{
|
||||
if (!fabricationCost.HasValue) { fabricationCost = 0; }
|
||||
@@ -1163,14 +1152,14 @@ namespace Barotrauma
|
||||
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
var ingredient = fabricationRecipe.RequiredItems.Find(r => r.ItemPrefab == targetItem);
|
||||
var ingredient = fabricationRecipe.RequiredItems.Find(r => r.ItemPrefabs.Contains(targetItem));
|
||||
if (ingredient == null)
|
||||
{
|
||||
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Red);
|
||||
}
|
||||
else if (ingredient.UseCondition && ingredient.MinCondition < deconstructItem.OutCondition)
|
||||
{
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {ingredient.ItemPrefab.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(deconstructItem.OutCondition * 100)}%)", Color.Red);
|
||||
NewMessage($"Deconstructing \"{itemPrefab.Name}\" produces more \"{deconstructItem.ItemIdentifier}\", than what's required to fabricate the item (required: {targetItem.Name} {(int)(ingredient.MinCondition * 100)}%, output: {deconstructItem.ItemIdentifier} {(int)(deconstructItem.OutCondition * 100)}%)", Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1389,6 +1378,39 @@ namespace Barotrauma
|
||||
ToolBox.OpenFileWithShell(Path.GetFullPath(filePath));
|
||||
}));
|
||||
#if DEBUG
|
||||
commands.Add(new Command("setplanthealth", "setplanthealth [value]: Sets the health of the selected plant in sub editor.", (string[] args) =>
|
||||
{
|
||||
if (1 > args.Length || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
|
||||
string arg = args[0];
|
||||
|
||||
if (!float.TryParse(arg, out float value))
|
||||
{
|
||||
ThrowError($"{arg} is not a valid value.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (MapEntity me in MapEntity.SelectedList)
|
||||
{
|
||||
if (me is Item it)
|
||||
{
|
||||
if (it.GetComponent<Planter>() is { } planter)
|
||||
{
|
||||
foreach (Growable seed in planter.GrowableSeeds.Where(s => s != null))
|
||||
{
|
||||
NewMessage($"Set the health of {seed.Name} to {value} (from {seed.Health})");
|
||||
seed.Health = value;
|
||||
}
|
||||
}
|
||||
else if (it.GetComponent<Growable>() is { } seed)
|
||||
{
|
||||
NewMessage($"Set the health of {seed.Name} to {value} (from {seed.Health})");
|
||||
seed.Health = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("printreceivertransfers", "", (string[] args) =>
|
||||
{
|
||||
GameMain.Client.PrintReceiverTransters();
|
||||
@@ -2012,7 +2034,7 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
GameMain.Config.SelectCorePackage(GameMain.Config.SelectedContentPackages.First(cp => cp.CorePackage), true);
|
||||
GameMain.Config.SelectCorePackage(GameMain.Config.CurrentCorePackage, true);
|
||||
}));
|
||||
|
||||
commands.Add(new Command("ingamemodswap", "", (string[] args) =>
|
||||
@@ -2041,7 +2063,7 @@ namespace Barotrauma
|
||||
}
|
||||
ShowQuestionPrompt("Permission to grant to client " + args[0] + "?", (perm) =>
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("giveperm " + args[0] + " " + perm);
|
||||
GameMain.Client?.SendConsoleCommand("giveperm \"" + args[0] + "\" " + perm);
|
||||
}, args, 1);
|
||||
}
|
||||
);
|
||||
@@ -2060,7 +2082,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Permission to revoke from client " + args[0] + "?", (perm) =>
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("revokeperm " + args[0] + " " + perm);
|
||||
GameMain.Client?.SendConsoleCommand("revokeperm \"" + args[0] + "\" " + perm);
|
||||
}, args, 1);
|
||||
}
|
||||
);
|
||||
@@ -2078,7 +2100,7 @@ namespace Barotrauma
|
||||
}
|
||||
ShowQuestionPrompt("Rank to grant to client " + args[0] + "?", (rank) =>
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("giverank " + args[0] + " " + rank);
|
||||
GameMain.Client?.SendConsoleCommand("giverank \"" + args[0] + "\" " + rank);
|
||||
}, args, 1);
|
||||
}
|
||||
);
|
||||
@@ -2091,7 +2113,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Console command permissions to grant to client " + args[0] + "? You may enter multiple commands separated with a space or use \"all\" to give the permission to use all console commands.", (commandNames) =>
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("givecommandperm " + args[0] + " " + commandNames);
|
||||
GameMain.Client?.SendConsoleCommand("givecommandperm \"" + args[0] + "\" " + commandNames);
|
||||
}, args, 1);
|
||||
}
|
||||
);
|
||||
@@ -2104,7 +2126,7 @@ namespace Barotrauma
|
||||
|
||||
ShowQuestionPrompt("Console command permissions to revoke from client " + args[0] + "? You may enter multiple commands separated with a space or use \"all\" to revoke the permission to use any console commands.", (commandNames) =>
|
||||
{
|
||||
GameMain.Client?.SendConsoleCommand("revokecommandperm " + args[0] + " " + commandNames);
|
||||
GameMain.Client?.SendConsoleCommand("revokecommandperm \"" + args[0] + "\" " + commandNames);
|
||||
}, args, 1);
|
||||
}
|
||||
);
|
||||
@@ -2505,7 +2527,7 @@ namespace Barotrauma
|
||||
}
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("spawnsub", "spawnsub [subname]: Spawn a submarine at the position of the cursor", (string[] args) =>
|
||||
commands.Add(new Command("spawnsub", "spawnsub [subname] [is thalamus]: Spawn a submarine at the position of the cursor", (string[] args) =>
|
||||
{
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
@@ -2528,6 +2550,25 @@ namespace Barotrauma
|
||||
{
|
||||
Submarine spawnedSub = Submarine.Load(subInfo, false);
|
||||
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
if (subInfo.Type == SubmarineType.Wreck)
|
||||
{
|
||||
spawnedSub.MakeWreck();
|
||||
if (args.Length > 1 && bool.TryParse(args[1], out bool isThalamus))
|
||||
{
|
||||
if (isThalamus)
|
||||
{
|
||||
spawnedSub.CreateWreckAI();
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnedSub.DisableWreckAI();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnedSub.DisableWreckAI();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
33
Barotrauma/BarotraumaClient/ClientSource/Decals/Decal.cs
Normal file
33
Barotrauma/BarotraumaClient/ClientSource/Decals/Decal.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Decal
|
||||
{
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Hull hull, float depth)
|
||||
{
|
||||
Vector2 drawPos = position + hull.Rect.Location.ToVector2();
|
||||
if (hull.Submarine != null) { drawPos += hull.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
spriteBatch.Draw(Sprite.Texture, drawPos, clippedSourceRect, Color * GetAlpha(), 0, Vector2.Zero, Scale, SpriteEffects.None, depth);
|
||||
|
||||
if (GameMain.DebugDraw && affectedSections != null && affectedSections.Count > 0)
|
||||
{
|
||||
Vector2 drawOffset = hull.Submarine == null ? Vector2.Zero : hull.Submarine.DrawPosition;
|
||||
Point sectionSize = affectedSections.First().Rect.Size;
|
||||
Rectangle drawPositionRect = new Rectangle((int)(drawOffset.X + hull.Rect.X), (int)(drawOffset.Y + hull.Rect.Y), sectionSize.X, sectionSize.Y);
|
||||
|
||||
foreach (var section in affectedSections)
|
||||
{
|
||||
// Draw colors
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(drawPositionRect.X + section.Rect.X, -(drawPositionRect.Y + section.Rect.Y)), new Vector2(sectionSize.X, sectionSize.Y), Color.Red, false, 0.0f, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace Barotrauma
|
||||
|
||||
GUIListBox conversationList = lastMessageBox.FindChild("conversationlist", true) as GUIListBox;
|
||||
Debug.Assert(conversationList != null);
|
||||
|
||||
|
||||
// gray out the last text block
|
||||
if (conversationList.Content.Children.LastOrDefault() is GUILayoutGroup lastElement)
|
||||
{
|
||||
@@ -132,17 +132,19 @@ namespace Barotrauma
|
||||
};
|
||||
shadow.SetAsFirstChild();
|
||||
|
||||
void RecalculateLastMessage(GUIListBox conversationList, bool append)
|
||||
static void RecalculateLastMessage(GUIListBox conversationList, bool append)
|
||||
{
|
||||
if (conversationList.Content.Children.LastOrDefault() is GUILayoutGroup lastElement)
|
||||
{
|
||||
GUILayoutGroup textLayout = lastElement.GetChild<GUILayoutGroup>();
|
||||
if (lastElement.Rect.Size.Y < textLayout.Rect.Size.Y && !append)
|
||||
{
|
||||
lastElement.RectTransform.MinSize = textLayout.Rect.Size;
|
||||
}
|
||||
|
||||
if (textLayout != null)
|
||||
{
|
||||
if (lastElement.Rect.Size.Y < textLayout.Rect.Size.Y && !append)
|
||||
{
|
||||
lastElement.RectTransform.MinSize = textLayout.Rect.Size;
|
||||
}
|
||||
|
||||
int textHeight = textLayout.Children.Sum(c => c.Rect.Height);
|
||||
textLayout.RectTransform.MaxSize = new Point(lastElement.RectTransform.MaxSize.X, textHeight);
|
||||
textLayout.Recalculate();
|
||||
@@ -323,7 +325,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height + textContent.AbsoluteSpacing) + GUI.IntScale(16));
|
||||
// content.RectTransform.MinSize = new Point(0, textContent.Rect.Height);
|
||||
|
||||
// Recalculate the text size as it is scaled up and no longer matching the text height due to the textContent's minSize increasing
|
||||
textBlock.CalculateHeightFromText();
|
||||
//content.RectTransform.MinSize = new Point(0, textContent.Rect.Height);
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@ namespace Barotrauma
|
||||
private float intensityGraphUpdateInterval;
|
||||
private float lastIntensityUpdate;
|
||||
|
||||
private Event? pinnedEvent;
|
||||
private Vector2 pinnedPosition = new Vector2(256, 128);
|
||||
private bool isDragging;
|
||||
|
||||
public Event? PinnedEvent { get; set; }
|
||||
|
||||
public void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
foreach (Event ev in activeEvents)
|
||||
@@ -104,12 +105,21 @@ namespace Barotrauma
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), "New event (ID " + eventSet.DebugIdentifier + ") after: ", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
|
||||
if ((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) &&
|
||||
roundDuration < eventSet.MinMissionTime)
|
||||
if (eventSet.PerWreck)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " submarine near the wreck", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
}
|
||||
if (eventSet.PerRuin)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y), " submarine near the ruins", Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
}
|
||||
if (roundDuration < eventSet.MinMissionTime)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||
" " + (int) (eventSet.MinDistanceTraveled * 100.0f) + "% travelled (current: " + (int) (distanceTraveled * 100.0f) + " %)",
|
||||
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
((Submarine.MainSub == null || distanceTraveled < eventSet.MinDistanceTraveled) ? Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, eventSet.MinDistanceTraveled - distanceTraveled) : GUI.Style.Green) * 0.8f, null, 0, GUI.SmallFont);
|
||||
y += 12;
|
||||
}
|
||||
|
||||
@@ -125,7 +135,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(graphRect.X, y),
|
||||
" " + (int) (eventSet.MinMissionTime - roundDuration) + " s",
|
||||
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
|
||||
Color.Lerp(GUI.Style.Yellow, GUI.Style.Red, (eventSet.MinMissionTime - roundDuration)), null, 0, GUI.SmallFont);
|
||||
}
|
||||
|
||||
y += 15;
|
||||
@@ -143,25 +153,25 @@ namespace Barotrauma
|
||||
Rectangle outlineRect = new Rectangle(rect.Location, rect.Size);
|
||||
outlineRect.Inflate(4, 4);
|
||||
|
||||
if (pinnedEvent == ev) { GUI.DrawRectangle(spriteBatch, outlineRect, Color.White); }
|
||||
if (PinnedEvent == ev) { GUI.DrawRectangle(spriteBatch, outlineRect, Color.White); }
|
||||
|
||||
if (rect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
GUI.MouseCursor = CursorState.Hand;
|
||||
GUI.DrawRectangle(spriteBatch, outlineRect, Color.White);
|
||||
|
||||
if (ev != pinnedEvent)
|
||||
if (ev != PinnedEvent)
|
||||
{
|
||||
DrawEvent(spriteBatch, ev, rect);
|
||||
}
|
||||
else if (PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown())
|
||||
{
|
||||
pinnedEvent = null;
|
||||
PinnedEvent = null;
|
||||
}
|
||||
|
||||
if (PlayerInput.PrimaryMouseButtonHeld() || PlayerInput.PrimaryMouseButtonDown())
|
||||
{
|
||||
pinnedEvent = ev;
|
||||
PinnedEvent = ev;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,9 +181,9 @@ namespace Barotrauma
|
||||
|
||||
public void DrawPinnedEvent(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (pinnedEvent != null)
|
||||
if (PinnedEvent != null)
|
||||
{
|
||||
Rectangle rect = DrawEvent(spriteBatch, pinnedEvent, null);
|
||||
Rectangle rect = DrawEvent(spriteBatch, PinnedEvent, null);
|
||||
|
||||
if (rect != Rectangle.Empty)
|
||||
{
|
||||
@@ -187,7 +197,7 @@ namespace Barotrauma
|
||||
|
||||
if (PlayerInput.SecondaryMouseButtonClicked() || PlayerInput.SecondaryMouseButtonHeld())
|
||||
{
|
||||
pinnedEvent = null;
|
||||
PinnedEvent = null;
|
||||
isDragging = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -14,7 +12,7 @@ namespace Barotrauma
|
||||
{
|
||||
public const string RadioChatString = "r; ";
|
||||
|
||||
private GUIListBox chatBox;
|
||||
private readonly GUIListBox chatBox;
|
||||
private Point screenResolution;
|
||||
|
||||
public readonly ChatManager ChatManager = new ChatManager();
|
||||
@@ -37,10 +35,17 @@ namespace Barotrauma
|
||||
|
||||
private float prevUIScale;
|
||||
|
||||
private readonly GUIFrame channelSettingsFrame;
|
||||
private readonly GUITextBox channelText;
|
||||
private readonly GUILayoutGroup channelPickerContent;
|
||||
private readonly GUIButton memButton;
|
||||
private WifiComponent prevRadio;
|
||||
|
||||
private bool channelMemPending;
|
||||
|
||||
//individual message texts that pop up when the chatbox is hidden
|
||||
const float PopupMessageDuration = 5.0f;
|
||||
private float popupMessageTimer;
|
||||
private Queue<GUIComponent> popupMessages = new Queue<GUIComponent>();
|
||||
private readonly List<GUIComponent> popupMessages = new List<GUIComponent>();
|
||||
|
||||
public GUITextBox.OnEnterHandler OnEnterMessage
|
||||
{
|
||||
@@ -67,9 +72,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private GUIButton showNewMessagesButton;
|
||||
private readonly GUIButton showNewMessagesButton;
|
||||
|
||||
private GUIFrame hideableElements;
|
||||
private readonly GUIFrame hideableElements;
|
||||
|
||||
public const int ToggleButtonWidthRaw = 30;
|
||||
private int popupMessageOffset;
|
||||
@@ -88,6 +93,133 @@ namespace Barotrauma
|
||||
var chatBoxHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.875f), hideableElements.RectTransform), style: "ChatBox");
|
||||
chatBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.95f), chatBoxHolder.RectTransform, Anchor.CenterRight), style: null);
|
||||
|
||||
// channel settings -----------------------------------------------------------------------------
|
||||
|
||||
channelSettingsFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), chatBoxHolder.RectTransform, Anchor.TopCenter, Pivot.BottomCenter) { MinSize = new Point(0, 25) }, style: "GUIFrameBottom");
|
||||
var channelSettingsContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), channelSettingsFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
var buttonLeft = new GUIButton(new RectTransform(new Vector2(0.1f, 0.8f), channelSettingsContent.RectTransform), style: "DeviceButton")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
SetChannel(radio.Channel - 1, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var arrowIcon = new GUIImage(new RectTransform(new Vector2(0.4f), buttonLeft.RectTransform, Anchor.Center), style: "GUIButtonHorizontalArrow", scaleToFit: true)
|
||||
{
|
||||
Color = new Color(51, 59, 46),
|
||||
SpriteEffects = Microsoft.Xna.Framework.Graphics.SpriteEffects.FlipHorizontally
|
||||
};
|
||||
arrowIcon.HoverColor = arrowIcon.PressedColor = arrowIcon.PressedColor = arrowIcon.Color;
|
||||
|
||||
channelText = new GUITextBox(new RectTransform(new Vector2(0.25f, 0.8f), channelSettingsContent.RectTransform), style: "DigitalFrameLight", textAlignment: Alignment.Center, font: GUI.DigitalFont)
|
||||
{
|
||||
textFilterFunction = text =>
|
||||
{
|
||||
var str = new string(text.Where(c => char.IsNumber(c)).ToArray());
|
||||
if (str.Length > 4) { str = str.Substring(0, 4); }
|
||||
return str;
|
||||
},
|
||||
OnEnterPressed = (tb, text) =>
|
||||
{
|
||||
tb.Deselect();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Vector2 textSize = channelText.Font.MeasureString("0000");
|
||||
channelText.TextBlock.ToolTip = TextManager.Get("currentradiochannel");
|
||||
channelText.TextBlock.TextScale = Math.Min(channelText.Rect.Height / textSize.Y * 0.9f, 1.0f);
|
||||
channelText.OnDeselected += (sender, key) =>
|
||||
{
|
||||
int.TryParse(channelText.Text, out int newChannel);
|
||||
SetChannel(newChannel, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
};
|
||||
|
||||
var buttonRight = new GUIButton(new RectTransform(new Vector2(0.1f, 0.8f), channelSettingsContent.RectTransform), style: "DeviceButton")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
SetChannel(radio.Channel + 1, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
arrowIcon = new GUIImage(new RectTransform(new Vector2(0.4f), buttonRight.RectTransform, Anchor.Center), style: "GUIButtonHorizontalArrow", scaleToFit: true)
|
||||
{
|
||||
Color = new Color(51, 59, 46)
|
||||
};
|
||||
arrowIcon.HoverColor = arrowIcon.PressedColor = arrowIcon.PressedColor = arrowIcon.Color;
|
||||
|
||||
var channelPicker = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.6f), channelSettingsContent.RectTransform), "InnerFrame");
|
||||
channelPickerContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), channelPicker.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), channelPickerContent.RectTransform), i.ToString(), style: "GUITextBlock")
|
||||
{
|
||||
TextColor = new Color(51, 59, 46),
|
||||
SelectedTextColor = GUI.Style.Green,
|
||||
UserData = i,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
int index = (int)userdata;
|
||||
if (channelMemPending)
|
||||
{
|
||||
int.TryParse(channelText.Text, out int newChannel);
|
||||
radio.SetChannelMemory(index, newChannel);
|
||||
btn.ToolTip = TextManager.GetWithVariables("radiochannelpreset",
|
||||
new string[] { "[index]", "[channel]" },
|
||||
new string[] { index.ToString(), radio.GetChannelMemory(index).ToString() });
|
||||
channelMemPending = false;
|
||||
channelPickerContent.Children.First().CanBeFocused = true;
|
||||
memButton.Enabled = true;
|
||||
channelPickerContent.Flash(GUI.Style.Green);
|
||||
channelText.Flash(GUI.Style.Green);
|
||||
}
|
||||
SetChannel(radio.GetChannelMemory(index), setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
memButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.9f), channelSettingsContent.RectTransform), style: "DeviceButton", text: TextManager.Get("saveradiochannelbutton"))
|
||||
{
|
||||
ToolTip = TextManager.Get("saveradiochannelbuttontooltip"),
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
channelMemPending = true;
|
||||
//don't allow storing a value in the first preset
|
||||
channelPickerContent.Children.First().CanBeFocused = false;
|
||||
foreach (GUIComponent channelButton in channelPickerContent.Children)
|
||||
{
|
||||
channelButton.Selected = false;
|
||||
}
|
||||
btn.Enabled = false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
InputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.125f), hideableElements.RectTransform, Anchor.BottomLeft),
|
||||
style: "ChatTextBox")
|
||||
{
|
||||
@@ -148,7 +280,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Color textColor = textBox.Color;
|
||||
Color textColor;
|
||||
switch (command)
|
||||
{
|
||||
case "r":
|
||||
@@ -235,7 +367,7 @@ namespace Barotrauma
|
||||
},
|
||||
Text = senderName
|
||||
};
|
||||
|
||||
|
||||
senderNameBlock.RectTransform.NonScaledSize = senderNameBlock.TextBlock.TextSize.ToPoint();
|
||||
senderNameBlock.TextBlock.OverrideTextColor(senderColor);
|
||||
if (senderNameBlock.UserData != null)
|
||||
@@ -244,7 +376,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
var msgText =new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), msgHolder.RectTransform)
|
||||
var msgText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), msgHolder.RectTransform)
|
||||
{ AbsoluteOffset = new Point((int)(10 * GUI.Scale), senderNameTimestamp == null ? 0 : senderNameTimestamp.Rect.Height) },
|
||||
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.TopLeft, style: null, wrap: true,
|
||||
color: ((chatBox.Content.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f)
|
||||
@@ -296,7 +428,7 @@ namespace Barotrauma
|
||||
{
|
||||
var popupMsg = new GUIFrame(new RectTransform(Vector2.One, GUIFrame.RectTransform), style: "GUIToolTip")
|
||||
{
|
||||
Visible = false,
|
||||
UserData = 0.0f,
|
||||
CanBeFocused = false
|
||||
};
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), popupMsg.RectTransform, Anchor.Center));
|
||||
@@ -322,10 +454,10 @@ namespace Barotrauma
|
||||
popupMsg.RectTransform.Resize(new Point((int)(textWidth / content.RectTransform.RelativeSize.X) , (int)((senderTextSize.Y + msgSize.Y) / content.RectTransform.RelativeSize.Y)), resizeChildren: true);
|
||||
popupMsg.RectTransform.IsFixedSize = true;
|
||||
content.Recalculate();
|
||||
popupMessages.Enqueue(popupMsg);
|
||||
popupMessages.Add(popupMsg);
|
||||
}
|
||||
|
||||
if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f;
|
||||
if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) { chatBox.BarScroll = 1.0f; }
|
||||
|
||||
GUISoundType soundType = GUISoundType.ChatMessage;
|
||||
if (message.Type == ChatMessageType.Radio)
|
||||
@@ -372,7 +504,7 @@ namespace Barotrauma
|
||||
GUIFrame.RectTransform.NonScaledSize -= new Point(toggleButtonWidth, 0);
|
||||
GUIFrame.RectTransform.AbsoluteOffset += new Point(toggleButtonWidth, 0);
|
||||
|
||||
popupMessageOffset = GameMain.GameSession.CrewManager.ReportButtonFrame.Rect.Width + GUIFrame.Rect.Width + (int)(20 * GUI.Scale);
|
||||
popupMessageOffset = GameMain.GameSession.CrewManager.ReportButtonFrame.Rect.Width + GUIFrame.Rect.Width + (int)(35 * GUI.Scale);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
@@ -394,22 +526,93 @@ namespace Barotrauma
|
||||
ToggleButton.RectTransform.AbsoluteOffset = new Point(GUIFrame.Rect.Right, GUIFrame.Rect.Y + HUDLayoutSettings.ChatBoxArea.Height - ToggleButton.Rect.Height);
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
if (prevRadio != radio)
|
||||
{
|
||||
foreach (GUIComponent presetButton in channelPickerContent.Children)
|
||||
{
|
||||
int index = (int)presetButton.UserData;
|
||||
presetButton.ToolTip = TextManager.GetWithVariables("radiochannelpreset",
|
||||
new string[] { "[index]", "[channel]" },
|
||||
new string[] { index.ToString(), radio.GetChannelMemory(index).ToString() });
|
||||
}
|
||||
SetChannel(radio.Channel, setText: true);
|
||||
prevRadio = radio;
|
||||
}
|
||||
if (channelMemPending)
|
||||
{
|
||||
if (channelPickerContent.FlashTimer <= 0)
|
||||
{
|
||||
channelPickerContent.Flash(GUI.Style.Green, flashRectInflate: new Vector2(GUI.Scale * 5.0f));
|
||||
}
|
||||
if (PlayerInput.PrimaryMouseButtonClicked() && !GUI.IsMouseOn(channelPickerContent))
|
||||
{
|
||||
channelPickerContent.Children.First().CanBeFocused = true;
|
||||
channelMemPending = false;
|
||||
memButton.Enabled = true;
|
||||
SetChannel(radio.Channel, setText: true);
|
||||
}
|
||||
}
|
||||
channelSettingsFrame.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
channelSettingsFrame.Visible = false;
|
||||
channelPickerContent.Children.First().CanBeFocused = true;
|
||||
channelMemPending = false;
|
||||
memButton.Enabled = true;
|
||||
}
|
||||
|
||||
if (ToggleOpen)
|
||||
{
|
||||
openState += deltaTime * 5.0f;
|
||||
//delete all popup messages when the chatbox is open
|
||||
while (popupMessages.Count > 0)
|
||||
foreach (var popupMsg in popupMessages)
|
||||
{
|
||||
var popupMsg = popupMessages.Dequeue();
|
||||
popupMsg.Parent.RemoveChild(popupMsg);
|
||||
}
|
||||
popupMessages.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
openState -= deltaTime * 5.0f;
|
||||
|
||||
int yOffset = 0;
|
||||
foreach (var popupMsg in popupMessages)
|
||||
{
|
||||
float msgTimer = (float)popupMsg.UserData;
|
||||
|
||||
int targetYOffset = (int)MathHelper.Lerp(popupMsg.RectTransform.ScreenSpaceOffset.Y, yOffset, deltaTime * 10.0f);
|
||||
|
||||
if (popupMsg == popupMessages.First())
|
||||
{
|
||||
popupMsg.UserData = msgTimer + deltaTime * Math.Max(popupMessages.Count / 2, 1);
|
||||
if (msgTimer > PopupMessageDuration)
|
||||
{
|
||||
//move the message out of the screen and delete it
|
||||
popupMsg.RectTransform.ScreenSpaceOffset =
|
||||
new Point((int)MathHelper.SmoothStep(popupMessageOffset, 10, (msgTimer - PopupMessageDuration) * 5.0f), targetYOffset);
|
||||
if (msgTimer > PopupMessageDuration + 0.2f)
|
||||
{
|
||||
popupMsg.Parent?.RemoveChild(popupMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msgTimer < PopupMessageDuration)
|
||||
{
|
||||
if (popupMsg != popupMessages.First()) { popupMsg.UserData = Math.Min(msgTimer + deltaTime, 1.0f); }
|
||||
//move the message on the screen
|
||||
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
|
||||
(int)MathHelper.SmoothStep(0, popupMessageOffset, msgTimer * 5.0f), targetYOffset);
|
||||
}
|
||||
yOffset += popupMsg.Rect.Height + GUI.IntScale(10);
|
||||
}
|
||||
|
||||
popupMessages.RemoveAll(p => p.Parent == null);
|
||||
|
||||
//make the first popup message visible
|
||||
var popupMsg = popupMessages.Count > 0 ? popupMessages.Peek() : null;
|
||||
/*var popupMsg = popupMessages.Count > 0 ? popupMessages.Peek() : null;
|
||||
if (popupMsg != null)
|
||||
{
|
||||
popupMsg.Visible = true;
|
||||
@@ -433,7 +636,7 @@ namespace Barotrauma
|
||||
popupMsg.RectTransform.ScreenSpaceOffset = new Point(
|
||||
(int)MathHelper.SmoothStep(0, popupMessageOffset, popupMessageTimer * 5.0f), 0);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
openState = MathHelper.Clamp(openState, 0.0f, 1.0f);
|
||||
int hiddenBoxOffset = -(GUIFrame.Rect.Width);
|
||||
@@ -441,5 +644,27 @@ namespace Barotrauma
|
||||
new Point((int)MathHelper.SmoothStep(hiddenBoxOffset, 0, openState), 0);
|
||||
hideableElements.Visible = openState > 0.0f;
|
||||
}
|
||||
|
||||
private void SetChannel(int channel, bool setText)
|
||||
{
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
radio.Channel = channel;
|
||||
if (setText)
|
||||
{
|
||||
string text = radio.Channel.ToString().PadLeft(4, '0');
|
||||
if (channelText.Text != text) { channelText.Text = text; }
|
||||
|
||||
}
|
||||
if (!channelMemPending)
|
||||
{
|
||||
foreach (GUIComponent channelButton in channelPickerContent.Children)
|
||||
{
|
||||
int buttonIndex = (int)channelButton.UserData;
|
||||
channelButton.Selected = radio.GetChannelMemory(buttonIndex) == channel;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ namespace Barotrauma
|
||||
|
||||
if (Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
yOffset = -HUDLayoutSettings.ChatBoxArea.Height;
|
||||
yOffset = (int)(-HUDLayoutSettings.ChatBoxArea.Height * 1.2f);
|
||||
watermarkRect.Y += yOffset;
|
||||
}
|
||||
|
||||
@@ -609,7 +609,7 @@ namespace Barotrauma
|
||||
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
if (!Character.Controlled.LockHands && Character.Controlled.Stun < 0.1f && !Character.Controlled.IsDead)
|
||||
if (Character.Controlled.Stun < 0.1f && !Character.Controlled.IsDead)
|
||||
{
|
||||
Inventory.DrawFront(spriteBatch);
|
||||
}
|
||||
@@ -1267,7 +1267,7 @@ namespace Barotrauma
|
||||
Vector2 diff = worldPosition - cam.WorldViewCenter;
|
||||
float dist = diff.Length();
|
||||
|
||||
float symbolScale = 64.0f / sprite.size.X;
|
||||
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f);
|
||||
|
||||
if (dist > hideDist)
|
||||
{
|
||||
@@ -2089,8 +2089,8 @@ namespace Barotrauma
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
var button = new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
|
||||
"", style: "GUIBugButton")
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
@@ -2098,12 +2098,12 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
|
||||
};
|
||||
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"))
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"))
|
||||
{
|
||||
OnClicked = TogglePauseMenu
|
||||
};
|
||||
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"))
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"))
|
||||
{
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
@@ -2117,8 +2117,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
|
||||
{
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"));
|
||||
button.OnClicked += (btn, userData) =>
|
||||
var retryButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"));
|
||||
retryButton.OnClicked += (btn, userData) =>
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuRetryVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
||||
{
|
||||
@@ -2131,6 +2131,7 @@ namespace Barotrauma
|
||||
GUIMessageBox.MessageBoxes.Remove(GameMain.GameSession.RoundSummary.Frame);
|
||||
}
|
||||
|
||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction");
|
||||
TogglePauseMenu(btn, userData);
|
||||
GameMain.GameSession.LoadPreviousSave();
|
||||
return true;
|
||||
@@ -2144,24 +2145,57 @@ namespace Barotrauma
|
||||
};
|
||||
return true;
|
||||
};
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
|
||||
var saveAndQuitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
|
||||
{
|
||||
UserData = "save"
|
||||
};
|
||||
button.OnClicked += QuitClicked;
|
||||
button.OnClicked += TogglePauseMenu;
|
||||
saveAndQuitButton.OnClicked += (btn, userdata) =>
|
||||
{
|
||||
//Only allow saving mid-round in outpost levels. Quitting in the middle of a mission reset progress to the start of the round.
|
||||
if (GameMain.GameSession == null)
|
||||
{
|
||||
pauseMenuOpen = false;
|
||||
|
||||
}
|
||||
else if (GameMain.GameSession?.Campaign == null || Level.IsLoadedOutpost)
|
||||
{
|
||||
pauseMenuOpen = false;
|
||||
GameMain.QuitToMainMenu(save: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuSaveAndQuitVerification", fallBackTag: "pausemenuquitverification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
|
||||
{
|
||||
UserData = "verificationprompt"
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (_, userdata) =>
|
||||
{
|
||||
pauseMenuOpen = false;
|
||||
GameMain.QuitToMainMenu(save: false);
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = (_, userdata) =>
|
||||
{
|
||||
pauseMenuOpen = false;
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else if (GameMain.GameSession.GameMode is TestGameMode)
|
||||
{
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.GameSession.EndRound("");
|
||||
pauseMenuOpen = false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
button.OnClicked += TogglePauseMenu;
|
||||
}
|
||||
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
|
||||
{
|
||||
@@ -2181,7 +2215,7 @@ namespace Barotrauma
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (_, __) =>
|
||||
{
|
||||
TogglePauseMenu(btn, userdata);
|
||||
pauseMenuOpen = false;
|
||||
GameMain.Client.RequestRoundEnd();
|
||||
return true;
|
||||
};
|
||||
@@ -2190,7 +2224,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
TogglePauseMenu(btn, userdata);
|
||||
pauseMenuOpen = false;
|
||||
GameMain.Client.RequestRoundEnd();
|
||||
}
|
||||
return true;
|
||||
@@ -2199,10 +2233,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"));
|
||||
button.OnClicked += (btn, userData) =>
|
||||
var quitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"));
|
||||
quitButton.OnClicked += (btn, userData) =>
|
||||
{
|
||||
var quitButton = button;
|
||||
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen))
|
||||
{
|
||||
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
|
||||
@@ -2212,21 +2245,21 @@ namespace Barotrauma
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
|
||||
{
|
||||
QuitClicked(quitButton, quitButton.UserData);
|
||||
GameMain.QuitToMainMenu(save: false);
|
||||
pauseMenuOpen = false;
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = (_, userdata) =>
|
||||
{
|
||||
TogglePauseMenu(btn, userData);
|
||||
pauseMenuOpen = false;
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
QuitClicked(quitButton, quitButton.UserData);
|
||||
GameMain.QuitToMainMenu(save: false);
|
||||
pauseMenuOpen = false;
|
||||
}
|
||||
return true;
|
||||
@@ -2242,12 +2275,6 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool QuitClicked(GUIButton button, object obj)
|
||||
{
|
||||
GameMain.QuitToMainMenu(button.UserData as string == "save");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Displays a message at the center of the screen, automatically preventing overlapping with other centered messages. TODO: Allow to show messages at the middle of the screen (instead of the top center).
|
||||
/// </summary>
|
||||
|
||||
@@ -104,6 +104,12 @@ namespace Barotrauma
|
||||
set { textBlock.HoverTextColor = value; }
|
||||
}
|
||||
|
||||
public Color SelectedTextColor
|
||||
{
|
||||
get { return textBlock.SelectedTextColor; }
|
||||
set { textBlock.SelectedTextColor = value; }
|
||||
}
|
||||
|
||||
public override float FlashTimer
|
||||
{
|
||||
get { return Frame.FlashTimer; }
|
||||
|
||||
@@ -756,9 +756,9 @@ namespace Barotrauma
|
||||
flashColor = (color == null) ? GUI.Style.Red : (Color)color;
|
||||
}
|
||||
|
||||
public void FadeOut(float duration, bool removeAfter)
|
||||
public void FadeOut(float duration, bool removeAfter, float wait = 0.0f)
|
||||
{
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(0.0f, duration, removeAfter));
|
||||
CoroutineManager.StartCoroutine(LerpAlpha(0.0f, duration, removeAfter, wait));
|
||||
}
|
||||
|
||||
public void FadeIn(float wait, float duration)
|
||||
|
||||
@@ -239,7 +239,7 @@ namespace Barotrauma
|
||||
{
|
||||
activeTextureLoads.Add(Sprite.FullPath);
|
||||
}
|
||||
Sprite.EnsureLazyLoaded();
|
||||
await Sprite.LazyLoadAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace Barotrauma
|
||||
//dragging
|
||||
if (CanDragElements && draggedElement != null)
|
||||
{
|
||||
if (!PlayerInput.LeftButtonHeld())
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
OnRearranged?.Invoke(this, draggedElement.UserData);
|
||||
draggedElement = null;
|
||||
@@ -533,7 +533,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (CanDragElements && PlayerInput.LeftButtonDown() && GUI.MouseOn == child)
|
||||
if (CanDragElements && PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
|
||||
{
|
||||
draggedElement = child;
|
||||
draggedReferenceRectangle = child.Rect;
|
||||
@@ -970,7 +970,6 @@ namespace Barotrauma
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
}
|
||||
|
||||
var children = Content.Children;
|
||||
int lastVisible = 0;
|
||||
|
||||
int i = 0;
|
||||
|
||||
@@ -180,13 +180,13 @@ namespace Barotrauma
|
||||
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), iconStyle, scaleToFit: true);
|
||||
}
|
||||
|
||||
Content = new GUILayoutGroup(new RectTransform(new Vector2(icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
|
||||
Content = new GUILayoutGroup(new RectTransform(new Vector2(Icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
|
||||
|
||||
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(0.15f, 1.0f), horizontalLayoutGroup.RectTransform), style: null);
|
||||
Buttons = new List<GUIButton>(1)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
|
||||
style: "GUIButtonHorizontalArrow")
|
||||
new GUIButton(new RectTransform(new Vector2(0.3f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
|
||||
style: "UIToggleButton")
|
||||
{
|
||||
OnClicked = Close
|
||||
}
|
||||
@@ -221,7 +221,7 @@ namespace Barotrauma
|
||||
Content.RectTransform.NonScaledSize =
|
||||
new Point(Content.Rect.Width, height);
|
||||
}
|
||||
Buttons[0].RectTransform.MaxSize = new Point(Math.Min(Buttons[0].Rect.Width, Buttons[0].Rect.Height));
|
||||
Buttons[0].RectTransform.MaxSize = new Point((int)(0.4f * Buttons[0].Rect.Y), Buttons[0].Rect.Y);
|
||||
}
|
||||
|
||||
MessageBoxes.Add(this);
|
||||
@@ -271,99 +271,92 @@ namespace Barotrauma
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (type == Type.InGame)
|
||||
if (type != Type.InGame) { return; }
|
||||
|
||||
Vector2 initialPos = new Vector2(0.0f, GameMain.GraphicsHeight);
|
||||
Vector2 defaultPos = new Vector2(0.0f, HUDLayoutSettings.InventoryAreaLower.Y - InnerFrame.Rect.Height - 20 * GUI.Scale);
|
||||
Vector2 endPos = new Vector2(GameMain.GraphicsWidth, defaultPos.Y);
|
||||
|
||||
if (!closing)
|
||||
{
|
||||
Vector2 initialPos = new Vector2(0.0f, GameMain.GraphicsHeight);
|
||||
Vector2 defaultPos = new Vector2(0.0f, HUDLayoutSettings.InventoryAreaLower.Y - InnerFrame.Rect.Height - 20 * GUI.Scale);
|
||||
Vector2 endPos = new Vector2(GameMain.GraphicsWidth, defaultPos.Y);
|
||||
|
||||
/*for (int i = MessageBoxes.IndexOf(this); i >= 0; i--)
|
||||
Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
if (MessageBoxes[i] is GUIMessageBox otherMsgBox && otherMsgBox != this && otherMsgBox.type == type && !otherMsgBox.closing)
|
||||
BackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (BackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - BackgroundIcon.Rect.Size.Y / 2);
|
||||
if (!MathUtils.NearlyEqual(openState, 1.0f))
|
||||
{
|
||||
defaultPos = new Vector2(
|
||||
Math.Max(otherMsgBox.InnerFrame.RectTransform.AbsoluteOffset.X + 10 * GUI.Scale, defaultPos.X),
|
||||
Math.Max(otherMsgBox.InnerFrame.RectTransform.AbsoluteOffset.Y + 10 * GUI.Scale, defaultPos.Y));
|
||||
}
|
||||
}*/
|
||||
|
||||
if (!closing)
|
||||
{
|
||||
Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (BackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - BackgroundIcon.Rect.Size.Y / 2);
|
||||
if (!MathUtils.NearlyEqual(openState, 1.0f))
|
||||
{
|
||||
BackgroundIcon.Color = ToolBox.GradientLerp(openState, Color.Transparent, Color.White);
|
||||
}
|
||||
}
|
||||
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
|
||||
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn) && AutoClose)
|
||||
{
|
||||
inGameCloseTimer += deltaTime;
|
||||
}
|
||||
|
||||
if (inGameCloseTimer >= inGameCloseTime)
|
||||
{
|
||||
Close();
|
||||
BackgroundIcon.Color = ToolBox.GradientLerp(openState, Color.Transparent, Color.White);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!(Screen.Selected is RoundSummaryScreen) && !MessageBoxes.Any(mb => mb.UserData is RoundSummary))
|
||||
{
|
||||
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn) && AutoClose)
|
||||
{
|
||||
inGameCloseTimer += deltaTime;
|
||||
}
|
||||
|
||||
if (inGameCloseTimer >= inGameCloseTime)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
openState += deltaTime * 2.0f;
|
||||
Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
}
|
||||
if (openState >= 2.0f)
|
||||
{
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
}
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
if (!iconSwitching)
|
||||
{
|
||||
openState += deltaTime * 2.0f;
|
||||
Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
||||
InnerFrame.RectTransform.AbsoluteOffset = step;
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
}
|
||||
if (openState >= 2.0f)
|
||||
{
|
||||
if (Parent != null) { Parent.RemoveChild(this); }
|
||||
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
||||
}
|
||||
}
|
||||
|
||||
if (newBackgroundIcon != null)
|
||||
{
|
||||
if (!iconSwitching)
|
||||
{
|
||||
if (BackgroundIcon != null)
|
||||
{
|
||||
BackgroundIcon.Color *= 0.9f;
|
||||
if (BackgroundIcon.Color.A == 0)
|
||||
{
|
||||
BackgroundIcon = null;
|
||||
iconSwitching = true;
|
||||
RemoveChild(BackgroundIcon);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (BackgroundIcon.Color.A == 0)
|
||||
{
|
||||
BackgroundIcon = null;
|
||||
iconSwitching = true;
|
||||
RemoveChild(BackgroundIcon);
|
||||
}
|
||||
iconState = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newBackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
|
||||
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
|
||||
if (newBackgroundIcon.Color.A == 255)
|
||||
{
|
||||
BackgroundIcon = newBackgroundIcon;
|
||||
BackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon = null;
|
||||
iconSwitching = false;
|
||||
}
|
||||
|
||||
iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
|
||||
iconSwitching = true;
|
||||
}
|
||||
iconState = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
newBackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
|
||||
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
|
||||
if (newBackgroundIcon.Color.A == 255)
|
||||
{
|
||||
BackgroundIcon = newBackgroundIcon;
|
||||
BackgroundIcon.SetAsFirstChild();
|
||||
newBackgroundIcon = null;
|
||||
iconSwitching = false;
|
||||
}
|
||||
|
||||
iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -380,16 +380,18 @@ namespace Barotrauma
|
||||
|
||||
private void ClampIntValue()
|
||||
{
|
||||
if (MinValueInt != null)
|
||||
if (MinValueInt != null && intValue < MinValueInt.Value)
|
||||
{
|
||||
intValue = Math.Max(intValue, MinValueInt.Value);
|
||||
minusButton.Enabled = intValue > MinValueInt;
|
||||
UpdateText();
|
||||
}
|
||||
if (MaxValueInt != null)
|
||||
if (MaxValueInt != null && intValue > MaxValueInt.Value)
|
||||
{
|
||||
intValue = Math.Min(intValue, MaxValueInt.Value);
|
||||
plusButton.Enabled = intValue < MaxValueInt;
|
||||
UpdateText();
|
||||
}
|
||||
plusButton.Enabled = intValue < MaxValueInt;
|
||||
minusButton.Enabled = intValue > MinValueInt;
|
||||
}
|
||||
|
||||
private void UpdateText()
|
||||
|
||||
@@ -462,7 +462,7 @@ namespace Barotrauma
|
||||
|
||||
protected List<Tuple<Vector2, int>> GetAllPositions()
|
||||
{
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f;
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
|
||||
string textDrawn = Censor ? CensoredText : WrappedText;
|
||||
var positions = new List<Tuple<Vector2, int>>();
|
||||
if (textDrawn.Contains("\n"))
|
||||
@@ -474,10 +474,10 @@ namespace Barotrauma
|
||||
{
|
||||
string line = lines[i];
|
||||
totalIndex += line.Length;
|
||||
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y;
|
||||
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * textScale;
|
||||
for (int j = 0; j <= line.Length; j++)
|
||||
{
|
||||
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j));
|
||||
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j)) * textScale;
|
||||
Vector2 indexPos = new Vector2(lineTextSize.X + Padding.X, totalTextHeight + Padding.Y - halfHeight);
|
||||
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
|
||||
@@ -490,8 +490,8 @@ namespace Barotrauma
|
||||
textDrawn = Censor ? CensoredText : Text;
|
||||
for (int i = 0; i <= Text.Length; i++)
|
||||
{
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i));
|
||||
Vector2 indexPos = new Vector2(textSize.X + Padding.X, textSize.Y + Padding.Y - halfHeight) + TextPos - Origin;
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i)) * textScale;
|
||||
Vector2 indexPos = new Vector2(textSize.X + Padding.X, textSize.Y + Padding.Y - halfHeight) + TextPos - Origin * textScale;
|
||||
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, i));
|
||||
}
|
||||
@@ -508,7 +508,7 @@ namespace Barotrauma
|
||||
{
|
||||
var positions = GetAllPositions();
|
||||
if (positions.Count == 0) { return 0; }
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f;
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
|
||||
|
||||
var currPosition = positions[0];
|
||||
|
||||
@@ -522,7 +522,8 @@ namespace Barotrauma
|
||||
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
|
||||
if (diffY < -3.0f)
|
||||
{
|
||||
currPosition = p1; continue;
|
||||
currPosition = p1;
|
||||
continue;
|
||||
}
|
||||
else if (diffY > 3.0f)
|
||||
{
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
while (ClampText && textBlock.Text.Length>0 && Font.MeasureString(textBlock.Text).X > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z))
|
||||
while (ClampText && textBlock.Text.Length > 0 && Font.MeasureString(textBlock.Text).X * TextBlock.TextScale > (int)(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z))
|
||||
{
|
||||
textBlock.Text = textBlock.Text.Substring(0, textBlock.Text.Length - 1);
|
||||
}
|
||||
@@ -354,10 +354,10 @@ namespace Barotrauma
|
||||
{
|
||||
int diff = totalIndex - CaretIndex;
|
||||
int index = currentLineLength - diff;
|
||||
Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index));
|
||||
Vector2 lastLineSize = Font.MeasureString(lines[i]);
|
||||
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y;
|
||||
caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin;
|
||||
Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index)) * TextBlock.TextScale;
|
||||
Vector2 lastLineSize = Font.MeasureString(lines[i]) * TextBlock.TextScale;
|
||||
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * TextBlock.TextScale;
|
||||
caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -366,8 +366,8 @@ namespace Barotrauma
|
||||
{
|
||||
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
|
||||
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex));
|
||||
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin;
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex)) * TextBlock.TextScale;
|
||||
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
|
||||
}
|
||||
caretPosDirty = false;
|
||||
}
|
||||
@@ -506,7 +506,7 @@ namespace Barotrauma
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(Rect.X + (int)caretPos.X + 2, Rect.Y + caretPos.Y + 3),
|
||||
new Vector2(Rect.X + (int)caretPos.X + 2, Rect.Y + caretPos.Y + Font.MeasureString("I").Y - 3),
|
||||
new Vector2(Rect.X + (int)caretPos.X + 2, Rect.Y + caretPos.Y + Font.MeasureString("I").Y * textBlock.TextScale - 3),
|
||||
CaretColor ?? textBlock.TextColor * (textBlock.TextColor.A / 255.0f));
|
||||
}
|
||||
if (selectedCharacters > 0)
|
||||
@@ -544,7 +544,7 @@ namespace Barotrauma
|
||||
: selectionEndIndex < totalIndex && selectionStartIndex > previousCharacters;
|
||||
if (containsSelection)
|
||||
{
|
||||
Vector2 currentLineSize = Font.MeasureString(currentLine);
|
||||
Vector2 currentLineSize = Font.MeasureString(currentLine) * TextBlock.TextScale;
|
||||
if ((IsLeftToRight && selectionStartIndex < previousCharacters && selectionEndIndex > totalIndex)
|
||||
|| !IsLeftToRight && selectionEndIndex < previousCharacters && selectionStartIndex > totalIndex)
|
||||
{
|
||||
@@ -560,7 +560,7 @@ namespace Barotrauma
|
||||
int startIndex = selectFromTheBeginning ? 0 : Math.Abs(selectionStartIndex - previousCharacters);
|
||||
int endIndex = Math.Abs(selectionEndIndex - previousCharacters);
|
||||
int characters = Math.Min(endIndex - startIndex, currentLineLength - startIndex);
|
||||
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(startIndex, characters));
|
||||
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(startIndex, characters)) * TextBlock.TextScale;
|
||||
Vector2 topLeft = selectFromTheBeginning
|
||||
? new Vector2(offset.X, offset.Y + currentLineSize.Y * i)
|
||||
: new Vector2(selectionStartPos.X, offset.Y + currentLineSize.Y * i);
|
||||
@@ -573,7 +573,7 @@ namespace Barotrauma
|
||||
int startIndex = selectFromTheBeginning ? currentLineLength : Math.Abs(selectionStartIndex - previousCharacters);
|
||||
int endIndex = selectFromTheStart ? 0 : Math.Abs(selectionEndIndex - previousCharacters);
|
||||
int characters = Math.Min(Math.Abs(endIndex - startIndex), currentLineLength);
|
||||
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(endIndex, characters));
|
||||
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(endIndex, characters)) * TextBlock.TextScale;
|
||||
Vector2 topLeft = selectFromTheBeginning
|
||||
? new Vector2(offset.X + currentLineSize.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i)
|
||||
: new Vector2(selectionStartPos.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i);
|
||||
@@ -612,7 +612,7 @@ namespace Barotrauma
|
||||
OnTextChanged?.Invoke(this, Text);
|
||||
if (textBlock.OverflowClipActive && wasOverflowClipActive && !MathUtils.NearlyEqual(textBlock.TextPos, textPos))
|
||||
{
|
||||
textBlock.TextPos = textPos + Vector2.UnitX * Font.MeasureString(input).X;
|
||||
textBlock.TextPos = textPos + Vector2.UnitX * Font.MeasureString(input).X * TextBlock.TextScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -714,8 +714,8 @@ namespace Barotrauma
|
||||
{
|
||||
InitSelectionStart();
|
||||
}
|
||||
float lineHeight = Font.MeasureString("T").Y;
|
||||
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y-lineHeight));
|
||||
float lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
|
||||
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y - lineHeight));
|
||||
CaretIndex = newIndex;
|
||||
caretTimer = 0;
|
||||
HandleSelection();
|
||||
@@ -725,8 +725,8 @@ namespace Barotrauma
|
||||
{
|
||||
InitSelectionStart();
|
||||
}
|
||||
lineHeight = Font.MeasureString("T").Y;
|
||||
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y+lineHeight));
|
||||
lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
|
||||
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y + lineHeight));
|
||||
CaretIndex = newIndex;
|
||||
caretTimer = 0;
|
||||
HandleSelection();
|
||||
@@ -865,18 +865,18 @@ namespace Barotrauma
|
||||
{
|
||||
string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText;
|
||||
InitSelectionStart();
|
||||
selectionEndIndex = CaretIndex;
|
||||
selectionEndIndex = Math.Min(CaretIndex, textDrawn.Length);
|
||||
selectionEndPos = caretPos;
|
||||
selectedCharacters = Math.Abs(selectionStartIndex - selectionEndIndex);
|
||||
if (IsLeftToRight)
|
||||
{
|
||||
selectedText = Text.Substring(selectionStartIndex, selectedCharacters);
|
||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionStartIndex, selectedCharacters));
|
||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionStartIndex, selectedCharacters)) * TextBlock.TextScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedText = Text.Substring(selectionEndIndex, selectedCharacters);
|
||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionEndIndex, selectedCharacters));
|
||||
selectedText = Text.Substring(selectionEndIndex, Math.Min(selectedCharacters, textDrawn.Length - selectionEndIndex));
|
||||
selectionRectSize = Font.MeasureString(textDrawn.Substring(selectionEndIndex, selectedCharacters)) * TextBlock.TextScale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ namespace Barotrauma
|
||||
CreateUI();
|
||||
|
||||
campaignUI.Campaign.Map.OnLocationChanged += UpdateLocation;
|
||||
if (CurrentLocation?.Reputation != null)
|
||||
{
|
||||
CurrentLocation.Reputation.OnReputationValueChanged += Refresh;
|
||||
}
|
||||
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += RefreshBuying;
|
||||
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += RefreshBuying;
|
||||
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += RefreshSelling;
|
||||
@@ -378,9 +382,13 @@ namespace Barotrauma
|
||||
{
|
||||
Stretch = true
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), totalContainer.RectTransform), TextManager.Get("campaignstore.total"), font: GUI.Font);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), totalContainer.RectTransform), TextManager.Get("campaignstore.total"), font: GUI.Font)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
shoppingCrateTotal = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), totalContainer.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextScale = 1.1f
|
||||
};
|
||||
|
||||
@@ -412,11 +420,20 @@ namespace Barotrauma
|
||||
{
|
||||
if (prevLocation == newLocation) { return; }
|
||||
|
||||
if (prevLocation?.Reputation != null)
|
||||
{
|
||||
prevLocation.Reputation.OnReputationValueChanged -= Refresh;
|
||||
}
|
||||
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
{
|
||||
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _))
|
||||
{
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
newLocation.Reputation.OnReputationValueChanged += Refresh;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -717,9 +734,15 @@ namespace Barotrauma
|
||||
|
||||
private GUIComponent CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, bool forceDisable = false)
|
||||
{
|
||||
var tooltip = pi.ItemPrefab.Name;
|
||||
if (!string.IsNullOrWhiteSpace(pi.ItemPrefab.Description))
|
||||
{
|
||||
tooltip += "\n" + pi.ItemPrefab.Description;
|
||||
}
|
||||
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.yScale * 60)), parent: listBox.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = pi.ItemPrefab.Description,
|
||||
ToolTip = tooltip,
|
||||
UserData = pi
|
||||
};
|
||||
|
||||
@@ -740,6 +763,7 @@ namespace Barotrauma
|
||||
iconRelativeWidth = (0.9f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
GUIImage img = new GUIImage(new RectTransform(new Vector2(iconRelativeWidth, 0.9f), mainGroup.RectTransform), itemIcon, scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
Color = (itemIcon == pi.ItemPrefab.InventoryIcon ? pi.ItemPrefab.InventoryIconColor : pi.ItemPrefab.SpriteColor) * (forceDisable ? 0.5f : 1.0f),
|
||||
UserData = "icon"
|
||||
};
|
||||
@@ -748,8 +772,8 @@ namespace Barotrauma
|
||||
|
||||
GUILayoutGroup nameAndQuantityGroup = new GUILayoutGroup(new RectTransform(new Vector2(nameAndIconRelativeWidth - iconRelativeWidth, 1.0f), mainGroup.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
ToolTip = pi.ItemPrefab.Description
|
||||
CanBeFocused = false,
|
||||
Stretch = true
|
||||
};
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndQuantityGroup.RectTransform),
|
||||
pi.ItemPrefab.Name, font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
||||
@@ -801,8 +825,8 @@ namespace Barotrauma
|
||||
|
||||
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
ToolTip = pi.ItemPrefab.Description,
|
||||
UserData = "price"
|
||||
};
|
||||
if(listBox == storeSellList || listBox == shoppingCrateSellList)
|
||||
|
||||
@@ -788,17 +788,12 @@ namespace Barotrauma
|
||||
string msg = ChatMessage.GetTimeStamp() + message.TextWithSender;
|
||||
storedMessages.Add(new Pair<string, PlayerConnectionChangeType>(msg, message.ChangeType));
|
||||
|
||||
if (GameSession.IsTabMenuOpen)
|
||||
if (GameSession.IsTabMenuOpen && selectedTab == InfoFrameTab.Crew)
|
||||
{
|
||||
TabMenu instance = GameSession.TabMenuInstance;
|
||||
instance.AddLineToLog(msg, message.ChangeType);
|
||||
|
||||
// Update crew
|
||||
if (selectedTab == InfoFrameTab.Crew)
|
||||
{
|
||||
instance.RemoveCurrentElements();
|
||||
instance.CreateMultiPlayerList(true);
|
||||
}
|
||||
instance.RemoveCurrentElements();
|
||||
instance.CreateMultiPlayerList(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,14 +830,15 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), logList.Content.RectTransform), line, wrap: true, font: GUI.SmallFont)
|
||||
if (logList != null)
|
||||
{
|
||||
TextColor = textColor,
|
||||
CanBeFocused = false,
|
||||
UserData = line
|
||||
}.CalculateHeightFromText();
|
||||
|
||||
//if ((prevSize == 1.0f && listBox.BarScroll == 0.0f) || (prevSize < 1.0f && listBox.BarScroll == 1.0f)) listBox.BarScroll = 1.0f;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), logList.Content.RectTransform), line, wrap: true, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = textColor,
|
||||
CanBeFocused = false,
|
||||
UserData = line
|
||||
}.CalculateHeightFromText();
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateMissionInfo(GUIFrame infoFrame)
|
||||
|
||||
@@ -56,11 +56,6 @@ namespace Barotrauma
|
||||
|
||||
public static Thread MainThread { get; private set; }
|
||||
|
||||
public static IEnumerable<ContentPackage> SelectedPackages
|
||||
{
|
||||
get { return Config?.SelectedContentPackages; }
|
||||
}
|
||||
|
||||
private static ContentPackage vanillaContent;
|
||||
public static ContentPackage VanillaContent
|
||||
{
|
||||
@@ -69,7 +64,7 @@ namespace Barotrauma
|
||||
if (vanillaContent == null)
|
||||
{
|
||||
// TODO: Dynamic method for defining and finding the vanilla content package.
|
||||
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
|
||||
vanillaContent = ContentPackage.CorePackages.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
return vanillaContent;
|
||||
}
|
||||
@@ -454,40 +449,31 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
|
||||
GUI.Init(Window, Config.AllEnabledPackages, GraphicsDevice);
|
||||
DebugConsole.Init();
|
||||
|
||||
if (Config.AutoUpdateWorkshopItems)
|
||||
{
|
||||
bool waitingForWorkshopUpdates = true;
|
||||
bool result = false;
|
||||
Config.WaitingForAutoUpdate = true;
|
||||
TaskPool.Add("AutoUpdateWorkshopItemsAsync",
|
||||
SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
|
||||
{
|
||||
result = ((Task<bool>)task).Result;
|
||||
waitingForWorkshopUpdates = false;
|
||||
bool result = ((Task<bool>)task).Result;
|
||||
|
||||
Config.WaitingForAutoUpdate = false;
|
||||
});
|
||||
|
||||
while (waitingForWorkshopUpdates) { yield return CoroutineStatus.Running; }
|
||||
|
||||
if (result)
|
||||
{
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
ContentPackage.LoadAll();
|
||||
Config.ReloadContentPackages();
|
||||
});
|
||||
}
|
||||
while (Config.WaitingForAutoUpdate) { yield return CoroutineStatus.Running; }
|
||||
}
|
||||
|
||||
|
||||
if (SelectedPackages.None())
|
||||
if (Config.AllEnabledPackages.None())
|
||||
{
|
||||
DebugConsole.Log("No content packages selected");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Selected content packages: " + string.Join(", ", SelectedPackages.Select(cp => cp.Name)));
|
||||
DebugConsole.Log("Selected content packages: " + string.Join(", ", Config.AllEnabledPackages.Select(cp => cp.Name)));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -542,6 +528,7 @@ namespace Barotrauma
|
||||
OutpostGenerationParams.LoadPresets();
|
||||
WreckAIConfig.LoadAll();
|
||||
EventSet.LoadPrefabs();
|
||||
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
|
||||
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
|
||||
Order.Init();
|
||||
@@ -550,10 +537,6 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
|
||||
TitleScreen.LoadState = 53.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
|
||||
TitleScreen.LoadState = 55.0f;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -628,8 +611,6 @@ namespace Barotrauma
|
||||
LocationType.Init();
|
||||
MainMenuScreen.Select();
|
||||
|
||||
CheckContentPackage();
|
||||
|
||||
foreach (string steamError in SteamManager.InitializationErrors)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get(steamError));
|
||||
@@ -645,29 +626,6 @@ namespace Barotrauma
|
||||
|
||||
}
|
||||
|
||||
private void CheckContentPackage()
|
||||
{
|
||||
foreach (ContentPackage contentPackage in Config.SelectedContentPackages)
|
||||
{
|
||||
var exePaths = contentPackage.GetFilesOfType(ContentType.Executable);
|
||||
if (exePaths.Any() && AppDomain.CurrentDomain.FriendlyName != Path.GetFileNameWithoutExtension(exePaths.First()))
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("IncorrectExe",
|
||||
new string[2] { "[selectedpackage]", "[exename]" }, new string[2] { contentPackage.Name, exePaths.First() }),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
msgBox.Buttons[0].OnClicked += (_, userdata) =>
|
||||
{
|
||||
string fullPath = Path.GetFullPath(exePaths.First());
|
||||
ToolBox.OpenFileWithShell(fullPath);
|
||||
Exit();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnloadContent will be called once per game and is the place to unload
|
||||
/// all content.
|
||||
@@ -690,11 +648,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (searchAllContentPackages)
|
||||
{
|
||||
return ContentPackage.GetFilesOfType(ContentPackage.List, type);
|
||||
return ContentPackage.GetFilesOfType(ContentPackage.AllPackages, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ContentPackage.GetFilesOfType(SelectedPackages, type);
|
||||
return ContentPackage.GetFilesOfType(Config.AllEnabledPackages, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,6 +896,7 @@ namespace Barotrauma
|
||||
if (GameSession?.GameMode != null && GameSession.GameMode.Paused)
|
||||
{
|
||||
Paused = true;
|
||||
GameSession.GameMode.UpdateWhilePaused((float)Timing.Step);
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
@@ -960,7 +919,6 @@ namespace Barotrauma
|
||||
DebugConsole.AddToGUIUpdateList();
|
||||
|
||||
DebugConsole.Update((float)Timing.Step);
|
||||
Paused = Paused || (DebugConsole.IsOpen && (NetworkMember == null || !NetworkMember.GameStarted));
|
||||
|
||||
if (!Paused)
|
||||
{
|
||||
@@ -1088,11 +1046,11 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign campaign && Level.IsLoadedOutpost && campaign.Map?.CurrentLocation != null && campaign.CargoManager != null)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
||||
{
|
||||
campaign.Map.CurrentLocation.AddToStock(campaign.CargoManager.SoldItems);
|
||||
campaign.CargoManager.ClearSoldItemsProjSpecific();
|
||||
campaign.Map.CurrentLocation.RemoveFromStock(campaign.CargoManager.PurchasedItems);
|
||||
spCampaign.Map.CurrentLocation.AddToStock(spCampaign.CargoManager.SoldItems);
|
||||
spCampaign.CargoManager.ClearSoldItemsProjSpecific();
|
||||
spCampaign.Map.CurrentLocation.RemoveFromStock(spCampaign.CargoManager.PurchasedItems);
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameSession.SavePath);
|
||||
|
||||
@@ -10,8 +10,17 @@ namespace Barotrauma
|
||||
{
|
||||
public enum SellStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity sold in SP. Or, entity sold by client and confirmed by server in MP.
|
||||
/// </summary>
|
||||
Confirmed,
|
||||
/// <summary>
|
||||
/// Entity sold by client in MP. Client has received at least one update from server after selling, but this entity wasn't yet confirmed.
|
||||
/// </summary>
|
||||
Unconfirmed,
|
||||
/// <summary>
|
||||
/// Entity sold by client in MP. Client hasn't yet received an update from server after selling.
|
||||
/// </summary>
|
||||
Local
|
||||
}
|
||||
|
||||
@@ -36,28 +45,41 @@ namespace Barotrauma
|
||||
|
||||
// Only consider items which have been:
|
||||
// a) sold in singleplayer or confirmed by server (SellStatus.Confirmed); or
|
||||
// b) sold locally in multiplier (SellStatus.Local), but the client has not received a campaing state update yet after selling them
|
||||
// b) sold locally in multiplayer (SellStatus.Local), but the client has not received a campaing state update yet after selling them
|
||||
var soldEntities = SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||
|
||||
var sellables = Item.ItemList.FindAll(i => i?.Prefab != null && !i.Removed &&
|
||||
i.GetRootInventoryOwner() == character &&
|
||||
!i.SpawnedInOutpost &&
|
||||
(i.ContainedItems == null || i.ContainedItems.None() || i.ContainedItems.All(ci => soldEntities.Any(se => se.Item == ci))) &&
|
||||
i.IsFullCondition && soldEntities.None(se => se.Item == i));
|
||||
i.Condition >= 0.9f * i.MaxCondition && soldEntities.None(se => se.Item == i));
|
||||
|
||||
// Prevent selling things like battery cells from headsets and oxygen tanks from diving masks
|
||||
var slots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.OuterClothes, InvSlotType.Headset };
|
||||
// Prevent selling items in equipment slots
|
||||
var slots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
|
||||
foreach (InvSlotType slot in slots)
|
||||
{
|
||||
var index = character.Inventory.FindLimbSlot(slot);
|
||||
if (character.Inventory.Items[index] is Item item && item.ContainedItems != null)
|
||||
if (character.Inventory.Items[index] is Item item)
|
||||
{
|
||||
// Don't prevent selling of items which can only be put in equipment slots (like diving suits)
|
||||
if (item.AllowedSlots.Contains(InvSlotType.Any))
|
||||
{
|
||||
sellables.Remove(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent selling items contained in certain equipped items (like battery cell in equipped headset or oxygen tank in equipped diving mask)
|
||||
slots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.OuterClothes, InvSlotType.Headset };
|
||||
foreach (InvSlotType slot in slots)
|
||||
{
|
||||
var index = character.Inventory.FindLimbSlot(slot);
|
||||
if (character.Inventory.Items[index] is Item item &&
|
||||
item.ContainedItems != null && item.AllowedSlots.Contains(InvSlotType.Any))
|
||||
{
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
if (containedItem != null)
|
||||
{
|
||||
sellables.Remove(containedItem);
|
||||
}
|
||||
sellables.Remove(containedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +145,7 @@ namespace Barotrauma
|
||||
var itemValue = GetSellValueAtCurrentLocation(item.ItemPrefab, quantity: item.Quantity);
|
||||
|
||||
// check if the store can afford the item
|
||||
if (location.StoreCurrentBalance < itemValue) { continue; }
|
||||
if (Location.StoreCurrentBalance < itemValue) { continue; }
|
||||
|
||||
var matchingItems = itemsInInventory.FindAll(i => i.Prefab == item.ItemPrefab);
|
||||
if (matchingItems.Count <= item.Quantity)
|
||||
@@ -147,7 +169,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// Exchange money
|
||||
campaign.Map.CurrentLocation.StoreCurrentBalance -= itemValue;
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
|
||||
// Remove from the sell crate
|
||||
|
||||
@@ -15,11 +15,6 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CrewManager
|
||||
{
|
||||
/// <summary>
|
||||
/// How long the previously selected character waits doing nothing when switching to another character. Only affects idling.
|
||||
/// </summary>
|
||||
const float CharacterWaitOnSwitch = 10.0f;
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
#region UI
|
||||
@@ -63,6 +58,8 @@ namespace Barotrauma
|
||||
|
||||
private Sprite jobIndicatorBackground, previousOrderArrow, cancelIcon;
|
||||
|
||||
private const int MaxOrderIcons = 3;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@@ -363,9 +360,10 @@ namespace Barotrauma
|
||||
UserData = character
|
||||
};
|
||||
|
||||
// "Padding" to prevent member-specific command button from overlapping job indicator
|
||||
var commandButtonAbsoluteHeight = Math.Min(40.0f, 0.67f * background.Rect.Height);
|
||||
var paddingRelativeWidth = 0.35f * commandButtonAbsoluteHeight / background.Rect.Width;
|
||||
|
||||
// "Padding" to prevent member-specific command button from overlapping job indicator
|
||||
new GUIFrame(new RectTransform(new Vector2(paddingRelativeWidth, 1.0f), layoutGroup.RectTransform), style: null);
|
||||
|
||||
var jobIconBackground = new GUIImage(
|
||||
@@ -392,7 +390,16 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
var nameRelativeWidth = 1.0f - paddingRelativeWidth - 3.7f * iconRelativeWidth;
|
||||
var nameRelativeWidth = 1.0f
|
||||
// Start padding
|
||||
- paddingRelativeWidth
|
||||
// 5 icons (job, 3 orders, sound)
|
||||
- (5 * 0.8f * iconRelativeWidth)
|
||||
// Vertical line
|
||||
- (0.1f * iconRelativeWidth)
|
||||
// Spacing
|
||||
- (7 * layoutGroup.RelativeSpacing);
|
||||
|
||||
var font = layoutGroup.Rect.Width < 150 ? GUI.SmallFont : GUI.Font;
|
||||
var nameBlock = new GUITextBlock(
|
||||
new RectTransform(
|
||||
@@ -417,6 +424,7 @@ namespace Barotrauma
|
||||
{
|
||||
UserData = character
|
||||
};
|
||||
|
||||
// Only create a tooltip if the name doesn't fit the name block
|
||||
if (nameBlock.Text.EndsWith("..."))
|
||||
{
|
||||
@@ -432,6 +440,7 @@ namespace Barotrauma
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
characterButton.OnClicked = CharacterClicked;
|
||||
@@ -443,7 +452,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
new GUIImage(
|
||||
new RectTransform(new Vector2(0.5f * iconRelativeWidth, 0.5f), layoutGroup.RectTransform),
|
||||
new RectTransform(new Vector2(0.1f * iconRelativeWidth, 0.5f), layoutGroup.RectTransform),
|
||||
style: "VerticalLine")
|
||||
{
|
||||
CanBeFocused = false
|
||||
@@ -697,7 +706,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Displays the specified order in the crew UI next to the character.
|
||||
/// </summary>
|
||||
public void DisplayCharacterOrder(Character character, Order order, string option)
|
||||
public void AddCurrentOrderIcon(Character character, Order order, string option)
|
||||
{
|
||||
if (character == null) { return; }
|
||||
|
||||
@@ -706,34 +715,44 @@ namespace Barotrauma
|
||||
if (characterFrame == null) { return; }
|
||||
|
||||
GUILayoutGroup layoutGroup = (GUILayoutGroup)characterFrame.FindChild(c => c is GUILayoutGroup);
|
||||
var currentOrderComponent = GetCurrentOrderComponent(layoutGroup);
|
||||
|
||||
if (order != null)
|
||||
// Get the OrderInfo from the current order icon
|
||||
var currentOrderIcon = GetCurrentOrderIcon(layoutGroup);
|
||||
OrderInfo? currentOrderInfo = null;
|
||||
if (currentOrderIcon?.UserData is OrderInfo)
|
||||
{
|
||||
var prevOrderComponent = GetPreviousOrderComponent(layoutGroup);
|
||||
if (currentOrderComponent?.UserData is OrderInfo currentOrderInfo)
|
||||
{
|
||||
if (order.Identifier == currentOrderInfo.Order.Identifier &&
|
||||
option == currentOrderInfo.OrderOption &&
|
||||
order.TargetEntity == currentOrderInfo.Order.TargetEntity) { return; }
|
||||
currentOrderInfo = (OrderInfo)currentOrderIcon.UserData;
|
||||
// No need to recreate icons if the current order matches the new order
|
||||
if (currentOrderInfo.Value.MatchesOrder(order, option)) { return; }
|
||||
}
|
||||
|
||||
layoutGroup.RemoveChild(prevOrderComponent);
|
||||
DisplayPreviousCharacterOrder(character, layoutGroup, currentOrderInfo);
|
||||
}
|
||||
else if (order.Identifier != dismissedOrderPrefab.Identifier &&
|
||||
prevOrderComponent?.UserData is OrderInfo prevOrderInfo &&
|
||||
order.Identifier == prevOrderInfo.Order.Identifier &&
|
||||
option == prevOrderInfo.OrderOption &&
|
||||
order.TargetEntity == prevOrderInfo.Order.TargetEntity)
|
||||
// Remove the current order icon
|
||||
layoutGroup.RemoveChild(currentOrderIcon);
|
||||
|
||||
// Remove a previous order icon if it matches the new order
|
||||
// We don't want the same order as both a current order and a previous order
|
||||
foreach (GUIComponent icon in GetPreviousOrderIcons(layoutGroup))
|
||||
{
|
||||
if (icon?.UserData is OrderInfo info && info.MatchesOrder(order, option))
|
||||
{
|
||||
layoutGroup.RemoveChild(prevOrderComponent);
|
||||
layoutGroup.RemoveChild(icon);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
layoutGroup.RemoveChild(currentOrderComponent);
|
||||
// Create a new previous order icon from the current order icon's OrderInfo
|
||||
if (currentOrderInfo.HasValue)
|
||||
{
|
||||
AddPreviousOrderIcon(character, layoutGroup, currentOrderInfo.Value);
|
||||
}
|
||||
|
||||
if (order == null || order.Identifier == dismissedOrderPrefab.Identifier) { return; }
|
||||
|
||||
if (GetPreviousOrderIcons(layoutGroup).Count() >= MaxOrderIcons)
|
||||
{
|
||||
RemoveLastPreviousOrderIcon(layoutGroup);
|
||||
}
|
||||
|
||||
var orderFrame = new GUIButton(
|
||||
new RectTransform(
|
||||
layoutGroup.GetChildByUserData("job").RectTransform.RelativeSize,
|
||||
@@ -748,25 +767,31 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
CreateNodeIcon(orderFrame.RectTransform, order.SymbolSprite, order.Color, tooltip: order.Name);
|
||||
new GUIImage(
|
||||
new RectTransform(Vector2.One, orderFrame.RectTransform),
|
||||
cancelIcon,
|
||||
scaleToFit: true)
|
||||
|
||||
new GUIImage(new RectTransform(Vector2.One, orderFrame.RectTransform), cancelIcon, scaleToFit: true)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
UserData = "cancel",
|
||||
Visible = false
|
||||
};
|
||||
|
||||
orderFrame.RectTransform.RepositionChildInHierarchy(4);
|
||||
characterFrame.SetAsFirstChild();
|
||||
}
|
||||
|
||||
private void DisplayPreviousCharacterOrder(Character character, GUILayoutGroup characterComponent, OrderInfo orderInfo)
|
||||
private void AddPreviousOrderIcon(Character character, GUILayoutGroup characterComponent, OrderInfo orderInfo)
|
||||
{
|
||||
if (orderInfo.Order == null || orderInfo.Order.Identifier == dismissedOrderPrefab.Identifier) { return; }
|
||||
|
||||
var maxPreviousOrderIcons = GetCurrentOrderIcon(characterComponent) != null ? MaxOrderIcons - 1 : MaxOrderIcons;
|
||||
if (GetPreviousOrderIcons(characterComponent).Count() >= maxPreviousOrderIcons)
|
||||
{
|
||||
RemoveLastPreviousOrderIcon(characterComponent);
|
||||
}
|
||||
|
||||
var previousOrderInfo = new OrderInfo(orderInfo);
|
||||
|
||||
var prevOrderFrame = new GUIButton(
|
||||
new RectTransform(
|
||||
characterComponent.GetChildByUserData("job").RectTransform.RelativeSize,
|
||||
@@ -786,17 +811,20 @@ namespace Barotrauma
|
||||
var prevOrderIconFrame = new GUIFrame(
|
||||
new RectTransform(new Vector2(0.8f), prevOrderFrame.RectTransform, anchor: Anchor.BottomLeft),
|
||||
style: null);
|
||||
|
||||
CreateNodeIcon(
|
||||
prevOrderIconFrame.RectTransform,
|
||||
previousOrderInfo.Order.SymbolSprite,
|
||||
previousOrderInfo.Order.Color,
|
||||
tooltip: previousOrderInfo.Order.Name);
|
||||
|
||||
foreach (GUIComponent c in prevOrderIconFrame.Children)
|
||||
{
|
||||
c.HoverColor = c.Color;
|
||||
c.PressedColor = c.Color;
|
||||
c.SelectedColor = c.Color;
|
||||
}
|
||||
|
||||
new GUIImage(
|
||||
new RectTransform(new Vector2(0.8f), prevOrderFrame.RectTransform, anchor: Anchor.TopRight),
|
||||
previousOrderArrow,
|
||||
@@ -804,19 +832,63 @@ namespace Barotrauma
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
prevOrderFrame.RectTransform.RepositionChildInHierarchy(GetCurrentOrderComponent(characterComponent) != null ? 5 : 4);
|
||||
|
||||
var positionInHierarchy = GetCurrentOrderIcon(characterComponent) != null ? 5 : 4;
|
||||
prevOrderFrame.RectTransform.RepositionChildInHierarchy(positionInHierarchy);
|
||||
}
|
||||
|
||||
private GUIComponent GetCurrentOrderComponent(GUILayoutGroup characterComponent)
|
||||
private void AddOldPreviousOrderIcons(Character character, GUILayoutGroup oldCharacterComponent)
|
||||
{
|
||||
return characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "currentorder");
|
||||
var prevOrderIcons = GetPreviousOrderIcons(oldCharacterComponent).ToList();
|
||||
if (prevOrderIcons.None()) { return; }
|
||||
if (prevOrderIcons.Count() > 1)
|
||||
{
|
||||
prevOrderIcons.Sort((x, y) => oldCharacterComponent.GetChildIndex(x).CompareTo(oldCharacterComponent.GetChildIndex(y)));
|
||||
prevOrderIcons.Reverse();
|
||||
}
|
||||
if (crewList.Content.Children.FirstOrDefault(c => c?.UserData == character)?.GetChild<GUILayoutGroup>() is GUILayoutGroup newCharacterComponent)
|
||||
{
|
||||
foreach (GUIComponent icon in prevOrderIcons)
|
||||
{
|
||||
if (icon.UserData is OrderInfo orderInfo)
|
||||
{
|
||||
AddPreviousOrderIcon(character, newCharacterComponent, orderInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent GetPreviousOrderComponent(GUILayoutGroup characterComponent)
|
||||
private void RemoveLastPreviousOrderIcon(GUILayoutGroup characterComponent)
|
||||
{
|
||||
return characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
|
||||
var prevOrderIcons = GetPreviousOrderIcons(characterComponent);
|
||||
if (prevOrderIcons.None()) { return; }
|
||||
if (prevOrderIcons.Count() == 1)
|
||||
{
|
||||
characterComponent.RemoveChild(prevOrderIcons.First());
|
||||
}
|
||||
else
|
||||
{
|
||||
int highestIndex = 0;
|
||||
GUIComponent oldestPreviousOrderIcon = null;
|
||||
foreach (GUIComponent icon in prevOrderIcons)
|
||||
{
|
||||
int i = characterComponent.GetChildIndex(icon);
|
||||
if (i > highestIndex || oldestPreviousOrderIcon == null)
|
||||
{
|
||||
highestIndex = i;
|
||||
oldestPreviousOrderIcon = icon;
|
||||
}
|
||||
}
|
||||
characterComponent.RemoveChild(oldestPreviousOrderIcon);
|
||||
}
|
||||
}
|
||||
|
||||
private GUIComponent GetCurrentOrderIcon(GUILayoutGroup characterComponent) =>
|
||||
characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "currentorder");
|
||||
|
||||
private IEnumerable<GUIComponent> GetPreviousOrderIcons(GUILayoutGroup characterComponent) =>
|
||||
characterComponent?.FindChildren(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Updating and drawing the UI
|
||||
@@ -854,7 +926,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (IsSinglePlayer || client == null || (GameMain.NetworkMember?.ConnectedClients?.All(match => match != client) ?? true)) { return; }
|
||||
|
||||
contextMenu = new GUIFrame(new RectTransform(new Vector2(0.1f, 0.12f), GUI.Canvas) { ScreenSpaceOffset = mousePos }, style: "GUIToolTip") { UserData = client };
|
||||
contextMenu = new GUIFrame(new RectTransform(new Vector2(0.1f, 0.15f), GUI.Canvas) { ScreenSpaceOffset = mousePos }, style: "GUIToolTip") { UserData = client };
|
||||
|
||||
var nameLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.2f), contextMenu.RectTransform), client.Name, font: GUI.SubHeadingFont)
|
||||
{
|
||||
@@ -864,7 +936,9 @@ namespace Barotrauma
|
||||
|
||||
var optionsList = new GUIListBox(new RectTransform(new Vector2(1f, 0.8f), contextMenu.RectTransform, Anchor.BottomLeft), style: null)
|
||||
{
|
||||
Padding = new Vector4(4, 0, 4, 4)
|
||||
Padding = new Vector4(4, 0, 4, 4),
|
||||
AutoHideScrollBar = false,
|
||||
ScrollBarVisible = false
|
||||
};
|
||||
|
||||
bool hasSteam = client.SteamID > 0 && SteamManager.IsInitialized,
|
||||
@@ -886,6 +960,13 @@ namespace Barotrauma
|
||||
UserData = "steam"
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get("moderationmenu.userdetails"), font: GUI.SmallFont)
|
||||
{
|
||||
Padding = new Vector4(4),
|
||||
Enabled = true,
|
||||
UserData = "user"
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(Point.Zero, parent), TextManager.Get("permissions"), font: GUI.SmallFont)
|
||||
{
|
||||
Padding = new Vector4(4),
|
||||
@@ -971,6 +1052,9 @@ namespace Barotrauma
|
||||
case "ban":
|
||||
GameMain.Client?.CreateKickReasonPrompt(client.Name, true);
|
||||
break;
|
||||
case "user":
|
||||
GameMain.NetLobbyScreen?.SelectPlayer(client);
|
||||
break;
|
||||
}
|
||||
contextMenu = null;
|
||||
return true;
|
||||
@@ -983,7 +1067,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (client == null ) { return; }
|
||||
|
||||
subContextMenu = new GUIListBox(new RectTransform(new Vector2(0.1f, 0.1f), GUI.Canvas) { ScreenSpaceOffset = pos }, style: "GUIToolTip");
|
||||
subContextMenu = new GUIListBox(new RectTransform(new Vector2(0.1f, 0.1f), GUI.Canvas) { ScreenSpaceOffset = pos }, style: "GUIToolTip")
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
ScrollBarVisible = false
|
||||
};
|
||||
|
||||
foreach (var rank in PermissionPreset.List)
|
||||
{
|
||||
@@ -1073,11 +1161,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!(c.UserData is Character character) || character.IsDead || character.Removed) { continue; }
|
||||
AddCharacter(character);
|
||||
if (GetPreviousOrderComponent(c.GetChild<GUILayoutGroup>())?.UserData is OrderInfo prevInfo &&
|
||||
crewList.Content.Children.FirstOrDefault(c => c?.UserData == character)?.GetChild<GUILayoutGroup>() is GUILayoutGroup newLayoutGroup)
|
||||
{
|
||||
DisplayPreviousCharacterOrder(character, newLayoutGroup, prevInfo);
|
||||
}
|
||||
AddOldPreviousOrderIcons(character, c.GetChild<GUILayoutGroup>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1112,9 +1196,10 @@ namespace Barotrauma
|
||||
if (!AllowCharacterSwitch) { return; }
|
||||
//make the previously selected character wait in place for some time
|
||||
//(so they don't immediately start idling and walking away from their station)
|
||||
if (Character.Controlled?.AIController?.ObjectiveManager != null)
|
||||
var aiController = Character.Controlled?.AIController;
|
||||
if (aiController != null)
|
||||
{
|
||||
Character.Controlled.AIController.ObjectiveManager.WaitTimer = CharacterWaitOnSwitch;
|
||||
aiController.Reset();
|
||||
}
|
||||
DisableCommandUI();
|
||||
Character.Controlled = character;
|
||||
@@ -1419,7 +1504,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (child.FindChild(c => c is GUILayoutGroup) is GUILayoutGroup layoutGroup)
|
||||
{
|
||||
if (GetCurrentOrderComponent(layoutGroup) is GUIComponent orderButton &&
|
||||
if (GetCurrentOrderIcon(layoutGroup) is GUIComponent orderButton &&
|
||||
orderButton.GetChildByUserData("colorsource") is GUIComponent orderIcon &&
|
||||
orderButton.GetChildByUserData("cancel") is GUIComponent cancelIcon)
|
||||
{
|
||||
@@ -1504,8 +1589,8 @@ namespace Barotrauma
|
||||
private Hull hullContext;
|
||||
private bool isContextual;
|
||||
private readonly List<Order> contextualOrders = new List<Order>();
|
||||
private Point shorcutCenterNodeOffset;
|
||||
private const int maxShorcutNodeCount = 4;
|
||||
private Point shortcutCenterNodeOffset;
|
||||
private const int maxShortcutNodeCount = 4;
|
||||
|
||||
private bool WasCommandInterfaceDisabledThisUpdate { get; set; }
|
||||
private bool CanIssueOrders
|
||||
@@ -1688,7 +1773,7 @@ namespace Barotrauma
|
||||
returnNodeMargin = returnNodeSize.X * 0.5f;
|
||||
|
||||
nodeDistance = (int)(150 * GUI.Scale);
|
||||
shorcutCenterNodeOffset = new Point(0, (int)(1.25f * nodeDistance));
|
||||
shortcutCenterNodeOffset = new Point(0, (int)(1.25f * nodeDistance));
|
||||
}
|
||||
|
||||
private List<OrderCategory> GetAvailableCategories()
|
||||
@@ -1972,7 +2057,7 @@ namespace Barotrauma
|
||||
|
||||
shortcutNodes.Clear();
|
||||
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && sub.GetItems(false).Find(i => i.HasTag("reactor") && !i.NonInteractable)?.GetComponent<Reactor>() is Reactor reactor)
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && sub.GetItems(false).Find(i => i.HasTag("reactor") && !i.NonInteractable)?.GetComponent<Reactor>() is Reactor reactor)
|
||||
{
|
||||
var reactorOutput = -reactor.CurrPowerConsumption;
|
||||
// If player is not an engineer AND the reactor is not powered up AND nobody is using the reactor
|
||||
@@ -1990,7 +2075,7 @@ namespace Barotrauma
|
||||
// TODO: Reconsider the conditions as bot captain can have the nav term selected without operating it
|
||||
// If player is not a captain AND nobody is using the nav terminal AND the nav terminal is powered up
|
||||
// --> Create shortcut node for Steer order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("captain")) &&
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("captain")) &&
|
||||
sub.GetItems(false).Find(i => i.HasTag("navterminal") && !i.NonInteractable) is Item nav && characters.None(c => c.SelectedConstruction == nav) &&
|
||||
nav.GetComponent<Steering>() is Steering steering && steering.Voltage > steering.MinVoltage)
|
||||
{
|
||||
@@ -2000,7 +2085,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not a security officer AND invaders are reported
|
||||
// --> Create shorcut node for Fight Intruders order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("securityofficer")) &&
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("securityofficer")) &&
|
||||
(Order.GetPrefab("reportintruders") is Order reportIntruders && ActiveOrders.Any(o => o.First.Prefab == reportIntruders)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2009,7 +2094,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not a mechanic AND a breach has been reported
|
||||
// --> Create shorcut node for Fix Leaks order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("mechanic")) &&
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("mechanic")) &&
|
||||
(Order.GetPrefab("reportbreach") is Order reportBreach && ActiveOrders.Any(o => o.First.Prefab == reportBreach)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2018,7 +2103,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not an engineer AND broken devices have been reported
|
||||
// --> Create shortcut node for Repair Damaged Systems order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && (Character.Controlled == null || Character.Controlled.Info?.Job?.Prefab != JobPrefab.Get("engineer")) &&
|
||||
(Order.GetPrefab("reportbrokendevices") is Order reportBrokenDevices && ActiveOrders.Any(o => o.First.Prefab == reportBrokenDevices)))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
@@ -2027,13 +2112,13 @@ namespace Barotrauma
|
||||
|
||||
// If fire is reported
|
||||
// --> Create shortcut node for Extinguish Fires order
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && ActiveOrders.Any(o=> o.First.Prefab == Order.GetPrefab("reportfire")))
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && ActiveOrders.Any(o=> o.First.Prefab == Order.GetPrefab("reportfire")))
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, Order.GetPrefab("extinguishfires"), -1));
|
||||
}
|
||||
|
||||
if (shortcutNodes.Count < maxShorcutNodeCount && characterContext?.Info?.Job?.Prefab?.AppropriateOrders != null)
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && characterContext?.Info?.Job?.Prefab?.AppropriateOrders != null)
|
||||
{
|
||||
foreach (string orderIdentifier in characterContext.Info.Job.Prefab.AppropriateOrders)
|
||||
{
|
||||
@@ -2046,7 +2131,7 @@ namespace Barotrauma
|
||||
{
|
||||
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, orderPrefab, -1));
|
||||
}
|
||||
if (shortcutNodes.Count >= maxShorcutNodeCount) { break; }
|
||||
if (shortcutNodes.Count >= maxShortcutNodeCount) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2063,7 +2148,7 @@ namespace Barotrauma
|
||||
c.PressedColor = c.Color;
|
||||
c.SelectedColor = c.Color;
|
||||
}
|
||||
shortcutCenterNode.RectTransform.MoveOverTime(shorcutCenterNodeOffset, CommandNodeAnimDuration);
|
||||
shortcutCenterNode.RectTransform.MoveOverTime(shortcutCenterNodeOffset, CommandNodeAnimDuration);
|
||||
|
||||
var nodeCountForCalculations = shortcutNodes.Count * 2 + 2;
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, 0.75f * nodeDistance, nodeCountForCalculations);
|
||||
@@ -2071,7 +2156,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < shortcutNodes.Count; i++)
|
||||
{
|
||||
shortcutNodes[i].RectTransform.Parent = commandFrame.RectTransform;
|
||||
shortcutNodes[i].RectTransform.MoveOverTime(shorcutCenterNodeOffset + offsets[firstOffsetIndex - i].ToPoint(), CommandNodeAnimDuration);
|
||||
shortcutNodes[i].RectTransform.MoveOverTime(shortcutCenterNodeOffset + offsets[firstOffsetIndex - i].ToPoint(), CommandNodeAnimDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2100,6 +2185,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (contextualOrders.None())
|
||||
{
|
||||
string orderIdentifier;
|
||||
|
||||
// Check if targeting an item or a hull
|
||||
if (itemContext != null && !itemContext.NonInteractable)
|
||||
{
|
||||
@@ -2114,7 +2201,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// If targeting a periscope connected to a turret, show the 'operateweapons' order
|
||||
var orderIdentifier = "operateweapons";
|
||||
orderIdentifier = "operateweapons";
|
||||
var operateWeaponsPrefab = Order.GetPrefab(orderIdentifier);
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
|
||||
{
|
||||
@@ -2123,9 +2210,9 @@ namespace Barotrauma
|
||||
if (turret != null) { contextualOrders.Add(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled)); }
|
||||
}
|
||||
|
||||
// If targeting a repairable item, show the 'repairsystems' order
|
||||
// If targeting a repairable item with condition below the repair threshold, show the 'repairsystems' order
|
||||
orderIdentifier = "repairsystems";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any())
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any(r => itemContext.ConditionPercentage < r.RepairThreshold))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, null, Character.Controlled));
|
||||
if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical"))))
|
||||
@@ -2138,13 +2225,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// Always show the 'wait' order if there are other crew members alive
|
||||
orderIdentifier = "wait";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && characters.Any(c => c != Character.Controlled))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, null, Character.Controlled));
|
||||
}
|
||||
|
||||
// Remove the 'pumpwater' order if the target pump is auto-controlled (as it will immediately overwrite the work done by the bot)
|
||||
orderIdentifier = "pumpwater";
|
||||
if (contextualOrders.FirstOrDefault(o => o.Identifier.Equals(orderIdentifier)) is Order o &&
|
||||
@@ -2152,20 +2232,34 @@ namespace Barotrauma
|
||||
{
|
||||
if (pump.IsAutoControlled) { contextualOrders.Remove(o); }
|
||||
}
|
||||
|
||||
if (contextualOrders.None())
|
||||
{
|
||||
// If there are other crew members alive and there are no other contextual orders available, show the 'wait' order
|
||||
orderIdentifier = "wait";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && characters.Any(c => c != Character.Controlled))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, null, Character.Controlled));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(hullContext != null)
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("fixleaks"), hullContext, null, Character.Controlled));
|
||||
}
|
||||
|
||||
// Show the 'follow' and 'dismissed' orders if there are other crew members alive
|
||||
if (characters.Any(c => c != Character.Controlled))
|
||||
{
|
||||
var orderIdentifier = "follow";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
// Show 'follow' order only when there are no orders of other categories available
|
||||
if (contextualOrders.None(o => o.Category != OrderCategory.Movement))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
orderIdentifier = "follow";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
}
|
||||
}
|
||||
|
||||
// Show 'dismissed' order only when there are crew members with active orders
|
||||
orderIdentifier = "dismissed";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) &&
|
||||
@@ -2192,7 +2286,7 @@ namespace Barotrauma
|
||||
if (Order.PrefabList.Any(o => item.HasTag(o.ItemIdentifiers))) { return true; }
|
||||
if (Order.PrefabList.Any(o => o.ItemComponentType != null && item.Components.Any(c => c?.GetType() == o.ItemComponentType))) { return true; }
|
||||
|
||||
if (item.Repairables.Any()) { return true; }
|
||||
if (item.Repairables.Any(r => item.ConditionPercentage < r.RepairThreshold)) { return true; }
|
||||
var operateWeaponsPrefab = Order.GetPrefab("operateweapons");
|
||||
return item.Components.Any(c => c is Controller) &&
|
||||
(item.GetConnectedComponents<Turret>().Any(c => operateWeaponsPrefab.ItemIdentifiers.Contains(c.Item.Prefab.Identifier)) ||
|
||||
@@ -2209,8 +2303,30 @@ namespace Barotrauma
|
||||
|
||||
node.RectTransform.MoveOverTime(offset, CommandNodeAnimDuration);
|
||||
|
||||
if (checkIfOrderCanBeHeard && !disableNode) { disableNode = !CanSomeoneHearCharacter(); }
|
||||
var mustSetOptionOrTarget = order.HasOptions || (order.MustSetTarget && itemContext == null);
|
||||
if (checkIfOrderCanBeHeard && !disableNode)
|
||||
{
|
||||
disableNode = !CanSomeoneHearCharacter();
|
||||
}
|
||||
|
||||
var mustSetOptionOrTarget = order.HasOptions;
|
||||
Item orderTargetEntity = null;
|
||||
|
||||
// If the order doesn't have options, but must set a target,
|
||||
// we have to check if there's only one possible target available
|
||||
// so we know to directly target that with the order
|
||||
if (!mustSetOptionOrTarget && order.MustSetTarget && itemContext == null)
|
||||
{
|
||||
var matchingItems = order.GetMatchingItems(GetTargetSubmarine(), true);
|
||||
if (matchingItems.Count > 1)
|
||||
{
|
||||
mustSetOptionOrTarget = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
orderTargetEntity = matchingItems.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
node.OnClicked = (button, userData) =>
|
||||
{
|
||||
if (disableNode || !CanIssueOrders) { return false; }
|
||||
@@ -2224,7 +2340,11 @@ namespace Barotrauma
|
||||
NavigateForward(button, userData);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if (orderTargetEntity != null)
|
||||
{
|
||||
o = new Order(o.Prefab, orderTargetEntity, orderTargetEntity.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: order.OrderGiver);
|
||||
}
|
||||
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o), o, null, Character.Controlled);
|
||||
DisableCommandUI();
|
||||
}
|
||||
@@ -2382,6 +2502,10 @@ namespace Barotrauma
|
||||
|
||||
Sprite icon = null;
|
||||
order.MinimapIcons?.TryGetValue(item.Prefab.Identifier, out icon);
|
||||
if (item.Prefab.MinimapIcon != null)
|
||||
{
|
||||
icon = item.Prefab.MinimapIcon;
|
||||
}
|
||||
var colorMultiplier = characters.Any(c => c.CurrentOrder != null &&
|
||||
c.CurrentOrder.Identifier == userData.Item1.Identifier &&
|
||||
c.CurrentOrder.TargetEntity == userData.Item1.TargetEntity) ? 0.5f : 1f;
|
||||
@@ -2601,7 +2725,7 @@ namespace Barotrauma
|
||||
var availableNodePositions = 20;
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, 2.7f * this.nodeDistance, availableNodePositions,
|
||||
firstAngle: MathHelper.ToRadians(-90f - ((extraOptionCharacters.Count - 1) * 0.5f * (360f / availableNodePositions))));
|
||||
for (int i = 0; i < extraOptionCharacters.Count; i++)
|
||||
for (int i = 0; i < extraOptionCharacters.Count && i < availableNodePositions; i++)
|
||||
{
|
||||
CreateAssignmentNode(userData as Tuple<Order, string>, extraOptionCharacters[i], offsets[i].ToPoint(), -1, nameLabelScale: 1.15f);
|
||||
}
|
||||
@@ -2786,7 +2910,7 @@ namespace Barotrauma
|
||||
{
|
||||
bearing = GetBearing(
|
||||
centerNode.RectTransform.AnimTargetPos.ToVector2(),
|
||||
shorcutCenterNodeOffset.ToVector2());
|
||||
shortcutCenterNodeOffset.ToVector2());
|
||||
}
|
||||
return nodeCount % 2 > 0 ?
|
||||
MathHelper.ToRadians(bearing + 360.0f / nodeCount / 2) :
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
@@ -30,11 +31,6 @@ namespace Barotrauma
|
||||
protected set;
|
||||
}
|
||||
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
}
|
||||
|
||||
private bool showCampaignUI;
|
||||
private bool wasChatBoxOpen;
|
||||
public bool ShowCampaignUI
|
||||
@@ -165,7 +161,6 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case TransitionType.LeaveLocation:
|
||||
// not sure why this can happen at an outpost but it apparently can in multiplayer
|
||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
break;
|
||||
@@ -195,14 +190,26 @@ namespace Barotrauma
|
||||
|
||||
if (endRoundButton.Visible)
|
||||
{
|
||||
if (!AllowedToEndRound()) { buttonText = TextManager.Get("map"); }
|
||||
endRoundButton.Text = ToolBox.LimitString(buttonText, endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
||||
if (endRoundButton.Text != buttonText)
|
||||
{
|
||||
endRoundButton.ToolTip = buttonText;
|
||||
}
|
||||
endRoundButton.Enabled = AllowedToEndRound();
|
||||
if (Character.Controlled?.ViewTarget is Item item)
|
||||
{
|
||||
Turret turret = item.GetComponent<Turret>();
|
||||
endRoundButton.RectTransform.ScreenSpaceOffset = turret == null ? Point.Zero : new Point(0, (int)(turret.UIElementHeight * 1.25f));
|
||||
}
|
||||
else if (Character.Controlled?.CharacterHealth?.SuicideButton?.Visible ?? false)
|
||||
{
|
||||
endRoundButton.RectTransform.ScreenSpaceOffset = new Point(0, Character.Controlled.CharacterHealth.SuicideButton.Rect.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
endRoundButton.RectTransform.ScreenSpaceOffset = Point.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
endRoundButton.DrawManually(spriteBatch);
|
||||
}
|
||||
|
||||
@@ -216,7 +223,14 @@ namespace Barotrauma
|
||||
{
|
||||
await Task.Yield();
|
||||
Rand.ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
|
||||
GameMain.GameSession.StartRound(newLevel, mirrorLevel: mirror);
|
||||
try
|
||||
{
|
||||
GameMain.GameSession.StartRound(newLevel, mirrorLevel: mirror);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
roundSummaryScreen.LoadException = e;
|
||||
}
|
||||
Rand.ThreadId = 0;
|
||||
});
|
||||
TaskPool.Add("AsyncCampaignStartRound", loadTask, (t) =>
|
||||
|
||||
@@ -3,7 +3,7 @@ using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace Barotrauma
|
||||
{
|
||||
public bool SuppressStateSending = false;
|
||||
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition"); }
|
||||
}
|
||||
|
||||
private UInt16 pendingSaveID = 1;
|
||||
public UInt16 PendingSaveID
|
||||
{
|
||||
@@ -100,7 +105,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
int buttonHeight = (int)(GUI.Scale * 40);
|
||||
int buttonWidth = GUI.IntScale(200);
|
||||
int buttonWidth = GUI.IntScale(450);
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
@@ -209,6 +214,7 @@ namespace Barotrauma
|
||||
Character.Controlled = null;
|
||||
prevControlled.ClearInputs();
|
||||
}
|
||||
GameMain.GameScreen.Cam.Freeze = true;
|
||||
overlayTextColor = Color.Lerp(Color.Transparent, Color.White, (timer - 1.0f) / fadeInDuration);
|
||||
timer = Math.Min(timer + CoroutineManager.DeltaTime, textDuration);
|
||||
yield return CoroutineStatus.Running;
|
||||
@@ -357,7 +363,7 @@ namespace Barotrauma
|
||||
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (PlayerInput.RightButtonClicked() ||
|
||||
if (PlayerInput.SecondaryMouseButtonClicked() ||
|
||||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
ShowCampaignUI = false;
|
||||
@@ -403,6 +409,14 @@ namespace Barotrauma
|
||||
|
||||
if (CampaignUI == null) { InitCampaignUI(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
var transitionType = GetAvailableTransition(out _, out _);
|
||||
if (transitionType == TransitionType.None && CampaignUI?.SelectedTab == InteractionType.Map)
|
||||
{
|
||||
ShowCampaignUI = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void End(TransitionType transitionType = TransitionType.None)
|
||||
{
|
||||
@@ -528,6 +542,7 @@ namespace Barotrauma
|
||||
UInt16 currentLocIndex = msg.ReadUInt16();
|
||||
UInt16 selectedLocIndex = msg.ReadUInt16();
|
||||
byte selectedMissionIndex = msg.ReadByte();
|
||||
bool allowDebugTeleport = msg.ReadBoolean();
|
||||
float? reputation = null;
|
||||
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
|
||||
|
||||
@@ -640,6 +655,7 @@ namespace Barotrauma
|
||||
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
||||
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
campaign.Map.SelectMission(selectedMissionIndex);
|
||||
campaign.Map.AllowDebugTeleport = allowDebugTeleport;
|
||||
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
|
||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||
campaign.CargoManager.SetSoldItems(soldItems);
|
||||
|
||||
@@ -11,6 +11,35 @@ namespace Barotrauma
|
||||
{
|
||||
class SinglePlayerCampaign : CampaignMode
|
||||
{
|
||||
public override bool Paused
|
||||
{
|
||||
get { return ForceMapUI || CoroutineManager.IsCoroutineRunning("LevelTransition") || ShowCampaignUI && CampaignUI.SelectedTab == InteractionType.Map; }
|
||||
}
|
||||
|
||||
public override void UpdateWhilePaused(float deltaTime)
|
||||
{
|
||||
if (CoroutineManager.IsCoroutineRunning("LevelTransition") || CoroutineManager.IsCoroutineRunning("SubmarineTransition") || gameOver) { return; }
|
||||
|
||||
if (PlayerInput.RightButtonClicked() ||
|
||||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
ShowCampaignUI = false;
|
||||
if (GUIMessageBox.VisibleBox?.UserData is RoundSummary roundSummary &&
|
||||
roundSummary.ContinueButton != null &&
|
||||
roundSummary.ContinueButton.Visible)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(GUIMessageBox.VisibleBox);
|
||||
}
|
||||
}
|
||||
|
||||
if (CrewManager.ChatBox != null)
|
||||
{
|
||||
CrewManager.ChatBox.Update(deltaTime);
|
||||
}
|
||||
|
||||
CrewManager.UpdateReports();
|
||||
}
|
||||
|
||||
private float endTimer;
|
||||
|
||||
private bool savedOnStart;
|
||||
@@ -124,7 +153,7 @@ namespace Barotrauma
|
||||
private void InitUI()
|
||||
{
|
||||
int buttonHeight = (int)(GUI.Scale * 40);
|
||||
int buttonWidth = GUI.IntScale(200);
|
||||
int buttonWidth = GUI.IntScale(450);
|
||||
|
||||
endRoundButton = new GUIButton(HUDLayoutSettings.ToRectTransform(new Rectangle((GameMain.GraphicsWidth / 2) - (buttonWidth / 2), HUDLayoutSettings.ButtonAreaTop.Center.Y - (buttonHeight / 2), buttonWidth, buttonHeight), GUICanvas.Instance),
|
||||
TextManager.Get("EndRound"), textAlignment: Alignment.Center, style: "EndRoundButton")
|
||||
@@ -357,10 +386,11 @@ namespace Barotrauma
|
||||
break;
|
||||
case TransitionType.ProgressToNextLocation:
|
||||
Map.MoveToNextLocation();
|
||||
Map.ProgressWorld();
|
||||
break;
|
||||
}
|
||||
|
||||
Map.ProgressWorld(transitionType, (float)(Timing.TotalTime - GameMain.GameSession.RoundStartTime));
|
||||
|
||||
var endTransition = new CameraTransition(Submarine.MainSub, GameMain.GameScreen.Cam, null,
|
||||
transitionType == TransitionType.LeaveLocation ? Alignment.BottomCenter : Alignment.Center,
|
||||
fadeOut: false,
|
||||
@@ -383,6 +413,8 @@ namespace Barotrauma
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
bool save = false;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
||||
@@ -398,21 +430,33 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
|
||||
if (PendingSubmarineSwitch != null)
|
||||
{
|
||||
SubmarineInfo previousSub = GameMain.GameSession.SubmarineInfo;
|
||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
||||
PendingSubmarineSwitch = null;
|
||||
|
||||
for (int i = 0; i < GameMain.GameSession.OwnedSubmarines.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines[i].Name == previousSub.Name)
|
||||
{
|
||||
GameMain.GameSession.OwnedSubmarines[i] = previousSub;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingSubmarineSwitch = null;
|
||||
EnableRoundSummaryGameOverState();
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
if (PendingSubmarineSwitch != null)
|
||||
{
|
||||
GameMain.GameSession.SubmarineInfo = PendingSubmarineSwitch;
|
||||
PendingSubmarineSwitch = null;
|
||||
}
|
||||
|
||||
SelectSummaryScreen(roundSummary, newLevel, mirror, () =>
|
||||
{
|
||||
GameMain.GameScreen.Select();
|
||||
@@ -473,7 +517,7 @@ namespace Barotrauma
|
||||
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (PlayerInput.RightButtonClicked() ||
|
||||
if (PlayerInput.SecondaryMouseButtonClicked() ||
|
||||
PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Escape))
|
||||
{
|
||||
ShowCampaignUI = false;
|
||||
@@ -581,7 +625,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (transitionType == TransitionType.ProgressToNextEmptyLocation)
|
||||
{
|
||||
Map.SetLocation(Map.Locations.IndexOf(Level.Loaded.EndLocation));
|
||||
Map.SetLocation(Map.Locations.IndexOf(Level.Loaded.EndLocation ?? Map.CurrentLocation));
|
||||
}
|
||||
|
||||
var subsToLeaveBehind = GetSubsToLeaveBehind(leavingSub);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -7,6 +11,17 @@ namespace Barotrauma
|
||||
{
|
||||
public Action OnRoundEnd;
|
||||
|
||||
public bool SpawnOutpost;
|
||||
|
||||
public OutpostGenerationParams OutpostParams;
|
||||
public LocationType OutpostType;
|
||||
|
||||
public EventPrefab TriggeredEvent;
|
||||
|
||||
private List<Event> scriptedEvent;
|
||||
|
||||
private GUIButton createEventButton;
|
||||
|
||||
public TestGameMode(GameModePreset preset) : base(preset)
|
||||
{
|
||||
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
|
||||
@@ -24,11 +39,96 @@ namespace Barotrauma
|
||||
base.Start();
|
||||
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
|
||||
if (SpawnOutpost)
|
||||
{
|
||||
GenerateOutpost(Submarine.MainSub);
|
||||
}
|
||||
|
||||
if (TriggeredEvent != null)
|
||||
{
|
||||
scriptedEvent = new List<Event> { TriggeredEvent.CreateInstance() };
|
||||
GameMain.GameSession.EventManager.PinnedEvent = scriptedEvent.Last();
|
||||
|
||||
createEventButton = new GUIButton(new RectTransform(new Point(128, 64), GUI.Canvas, Anchor.TopCenter) { ScreenSpaceOffset = new Point(0, 32) }, TextManager.Get("create"))
|
||||
{
|
||||
OnClicked = delegate
|
||||
{
|
||||
scriptedEvent.Add(TriggeredEvent.CreateInstance());
|
||||
GameMain.GameSession.EventManager.PinnedEvent = scriptedEvent.Last();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
{
|
||||
base.AddToGUIUpdateList();
|
||||
createEventButton?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
public override void End(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
{
|
||||
GameMain.GameSession.EventManager.PinnedEvent = null;
|
||||
OnRoundEnd?.Invoke();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (scriptedEvent != null)
|
||||
{
|
||||
foreach (Event sEvent in scriptedEvent.Where(sEvent => !sEvent.IsFinished))
|
||||
{
|
||||
sEvent.Update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateOutpost(Submarine submarine)
|
||||
{
|
||||
Submarine outpost = OutpostGenerator.Generate(OutpostParams ?? OutpostGenerationParams.Params.GetRandom(), OutpostType ?? LocationType.List.GetRandom());
|
||||
outpost.SetPosition(Vector2.Zero);
|
||||
|
||||
float closestDistance = 0.0f;
|
||||
DockingPort myPort = null, outPostPort = null;
|
||||
foreach (DockingPort port in DockingPort.List)
|
||||
{
|
||||
if (port.IsHorizontal || port.Docked) { continue; }
|
||||
if (port.Item.Submarine == outpost)
|
||||
{
|
||||
outPostPort = port;
|
||||
continue;
|
||||
}
|
||||
if (port.Item.Submarine != submarine) { continue; }
|
||||
|
||||
//the submarine port has to be at the top of the sub
|
||||
if (port.Item.WorldPosition.Y < submarine.WorldPosition.Y) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(port.Item.WorldPosition, outpost.WorldPosition);
|
||||
if ((myPort == null || dist < closestDistance || port.MainDockingPort) && !(myPort?.MainDockingPort ?? false))
|
||||
{
|
||||
myPort = port;
|
||||
closestDistance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (myPort != null && outPostPort != null)
|
||||
{
|
||||
Vector2 portDiff = myPort.Item.WorldPosition - submarine.WorldPosition;
|
||||
Vector2 spawnPos = (outPostPort.Item.WorldPosition - portDiff) - Vector2.UnitY * outPostPort.DockedDistance;
|
||||
|
||||
submarine.SetPosition(spawnPos);
|
||||
myPort.Dock(outPostPort);
|
||||
myPort.Lock(true);
|
||||
}
|
||||
|
||||
if (Character.Controlled != null)
|
||||
{
|
||||
Character.Controlled.TeleportTo(outpost.GetWaypoints(false).GetRandom(point => point.SpawnType == SpawnType.Human).WorldPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,7 +293,9 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
// Room 4
|
||||
do { yield return null; } while (!officer_somethingBigSensor.MotionDetected);
|
||||
TriggerTutorialSegment(3); // Arm railgun
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Officer.Radio.SomethingBig"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(3); // Arm coilgun
|
||||
do
|
||||
{
|
||||
SetHighlight(officer_coilgunLoader.Item, officer_coilgunLoader.Inventory.Items[0] == null || officer_coilgunLoader.Inventory.Items[0].Condition == 0);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -373,15 +374,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gameSession.GameMode is CampaignMode))
|
||||
{
|
||||
var shadow = new GUIFrame(new RectTransform(new Point((int)(totalWidth * 1.2f), GameMain.GraphicsHeight * 2), background.RectTransform, Anchor.Center), style: "OuterGlow")
|
||||
{
|
||||
Color = Color.Black
|
||||
};
|
||||
shadow.RectTransform.SetAsFirstChild();
|
||||
}
|
||||
|
||||
Frame = background;
|
||||
return background;
|
||||
}
|
||||
@@ -511,7 +503,7 @@ namespace Barotrauma
|
||||
Character character = characterInfo.Character;
|
||||
if (character == null || character.IsDead)
|
||||
{
|
||||
if (characterInfo.IsNewHire)
|
||||
if (character == null && characterInfo.IsNewHire)
|
||||
{
|
||||
statusText = TextManager.Get("CampaignCrew.NewHire");
|
||||
statusColor = GUI.Style.Blue;
|
||||
@@ -616,21 +608,8 @@ namespace Barotrauma
|
||||
sliderHolder.RectTransform.MaxSize = new Point(int.MaxValue, GUI.IntScale(25.0f));
|
||||
factionTextContent.Recalculate();
|
||||
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.8f, 1.0f), sliderHolder.RectTransform), onDraw: (sb, customComponent) =>
|
||||
{
|
||||
GUI.DrawRectangle(sb, customComponent.Rect, GUI.Style.ColorInventoryBackground, isFilled: true);
|
||||
if (normalizedReputation < 0.5f)
|
||||
{
|
||||
int barWidth = (int)((0.5f - normalizedReputation) * customComponent.Rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(customComponent.Rect.Center.X - barWidth, customComponent.Rect.Y, barWidth, customComponent.Rect.Height), GUI.Style.Red, isFilled: true);
|
||||
}
|
||||
else if (normalizedReputation > 0.5f)
|
||||
{
|
||||
int barWidth = (int)((normalizedReputation - 0.5f) * customComponent.Rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(customComponent.Rect.Center.X, customComponent.Rect.Y, barWidth, customComponent.Rect.Height), GUI.Style.Green, isFilled: true);
|
||||
}
|
||||
GUI.DrawLine(sb, new Vector2(customComponent.Rect.Center.X, customComponent.Rect.Y - 2), new Vector2(customComponent.Rect.Center.X, customComponent.Rect.Bottom + 2), factionDescription.TextColor, width: 1);
|
||||
});
|
||||
new GUICustomComponent(new RectTransform(new Vector2(0.8f, 1.0f), sliderHolder.RectTransform),
|
||||
onDraw: (sb, customComponent) => DrawReputationBar(sb, customComponent.Rect, normalizedReputation));
|
||||
|
||||
string reputationText = ((int)Math.Round(reputation)).ToString();
|
||||
int reputationChange = (int)Math.Round( reputation - initialReputation);
|
||||
@@ -650,5 +629,21 @@ namespace Barotrauma
|
||||
textAlignment: Alignment.CenterLeft, font: GUI.SubHeadingFont);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawReputationBar(SpriteBatch sb, Rectangle rect, float normalizedReputation)
|
||||
{
|
||||
GUI.DrawRectangle(sb, rect, GUI.Style.ColorInventoryBackground, isFilled: true);
|
||||
if (normalizedReputation < 0.5f)
|
||||
{
|
||||
int barWidth = (int)((0.5f - normalizedReputation) * rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(rect.Center.X - barWidth, rect.Y, barWidth, rect.Height), GUI.Style.Red, isFilled: true);
|
||||
}
|
||||
else if (normalizedReputation > 0.5f)
|
||||
{
|
||||
int barWidth = (int)((normalizedReputation - 0.5f) * rect.Width);
|
||||
GUI.DrawRectangle(sb, new Rectangle(rect.Center.X, rect.Y, barWidth, rect.Height), GUI.Style.Green, isFilled: true);
|
||||
}
|
||||
GUI.DrawLine(sb, new Vector2(rect.Center.X, rect.Y - 2), new Vector2(rect.Center.X, rect.Bottom + 2), GUI.Style.TextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ namespace Barotrauma
|
||||
keyMapping[(int)InputType.Voice] = new KeyOrMouse(Keys.V);
|
||||
keyMapping[(int)InputType.LocalVoice] = new KeyOrMouse(Keys.B);
|
||||
keyMapping[(int)InputType.Command] = new KeyOrMouse(MouseButton.MiddleMouse);
|
||||
#if DEBUG
|
||||
keyMapping[(int)InputType.PreviousFireMode] = new KeyOrMouse(MouseButton.MouseWheelDown);
|
||||
keyMapping[(int)InputType.NextFireMode] = new KeyOrMouse(MouseButton.MouseWheelUp);
|
||||
#endif
|
||||
|
||||
if (Language == "French")
|
||||
{
|
||||
@@ -314,7 +318,7 @@ namespace Barotrauma
|
||||
|
||||
var corePackageDropdown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform))
|
||||
{
|
||||
ButtonEnabled = ContentPackage.List.Count(cp => cp.CorePackage) > 1
|
||||
ButtonEnabled = ContentPackage.CorePackages.Count > 1
|
||||
};
|
||||
|
||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform), isHorizontal: true)
|
||||
@@ -342,7 +346,7 @@ namespace Barotrauma
|
||||
ScrollBarVisible = true
|
||||
};
|
||||
|
||||
foreach (ContentPackage contentPackage in ContentPackage.List.Where(cp => cp.CorePackage))
|
||||
foreach (ContentPackage contentPackage in ContentPackage.CorePackages)
|
||||
{
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), corePackageDropdown.ListBox.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
@@ -358,7 +362,7 @@ namespace Barotrauma
|
||||
TextManager.GetWithVariables(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage",
|
||||
new string[3] { "[packagename]", "[packageversion]", "[gameversion]" }, new string[3] { contentPackage.Name, contentPackage.GameVersion.ToString(), GameMain.Version.ToString() });
|
||||
}
|
||||
else if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
|
||||
else if (!contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
|
||||
{
|
||||
frame.UserData = null;
|
||||
text.TextColor = GUI.Style.Red * 0.6f;
|
||||
@@ -374,7 +378,7 @@ namespace Barotrauma
|
||||
"\n" + string.Join("\n", contentPackage.ErrorMessages);
|
||||
}
|
||||
|
||||
if (SelectedContentPackages.Contains(contentPackage))
|
||||
if (contentPackage == CurrentCorePackage)
|
||||
{
|
||||
corePackageDropdown.Select(corePackageDropdown.ListBox.Content.GetChildIndex(frame));
|
||||
}
|
||||
@@ -382,10 +386,7 @@ namespace Barotrauma
|
||||
corePackageDropdown.OnSelected = SelectCorePackage;
|
||||
corePackageDropdown.ListBox.CanBeFocused = CanHotswapPackages(true);
|
||||
|
||||
foreach (ContentPackage contentPackage in ContentPackage.List
|
||||
.Where(cp => !cp.CorePackage)
|
||||
.OrderBy(cp => !SelectedContentPackages.Contains(cp))
|
||||
.ThenBy(cp => -SelectedContentPackages.IndexOf(cp)))
|
||||
foreach (ContentPackage contentPackage in ContentPackage.RegularPackages)
|
||||
{
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, tickBoxScale.Y), contentPackageList.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
@@ -407,7 +408,7 @@ namespace Barotrauma
|
||||
style: "GUITickBox")
|
||||
{
|
||||
UserData = contentPackage,
|
||||
Selected = SelectedContentPackages.Contains(contentPackage),
|
||||
Selected = EnabledRegularPackages.Contains(contentPackage),
|
||||
OnSelected = SelectContentPackage,
|
||||
Enabled = CanHotswapPackages(false)
|
||||
};
|
||||
@@ -1595,10 +1596,10 @@ namespace Barotrauma
|
||||
|
||||
if (userData is ContentPackage contentPackage)
|
||||
{
|
||||
if (!SelectedContentPackages.Contains(contentPackage)) { return; }
|
||||
if (!EnabledRegularPackages.Contains(contentPackage)) { return; }
|
||||
}
|
||||
|
||||
ReorderSelectedContentPackages(cp => -listBox.Content.GetChildIndex(listBox.Content.GetChildByUserData(cp)));
|
||||
ContentPackage.SortContentPackages(cp => listBox.Content.GetChildIndex(listBox.Content.GetChildByUserData(cp)), true);
|
||||
|
||||
UnsavedSettings = true;
|
||||
}
|
||||
@@ -1609,18 +1610,13 @@ namespace Barotrauma
|
||||
|
||||
var contentPackage = tickBox.UserData as ContentPackage;
|
||||
|
||||
ContentPackage.List = ContentPackage.List
|
||||
.OrderByDescending(p => p.CorePackage)
|
||||
.ThenBy(cp => -contentPackageList.Content.GetChildIndex(contentPackageList.Content.GetChildByUserData(cp)))
|
||||
.ToList();
|
||||
|
||||
if (tickBox.Selected)
|
||||
{
|
||||
SelectContentPackage(contentPackage);
|
||||
EnableRegularPackage(contentPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeselectContentPackage(contentPackage);
|
||||
DisableRegularPackage(contentPackage);
|
||||
}
|
||||
|
||||
UnsavedSettings = true;
|
||||
|
||||
@@ -717,7 +717,7 @@ namespace Barotrauma
|
||||
{
|
||||
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
|
||||
"" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.SelectedItems.FirstOrDefault(i => i != null)?.Name);
|
||||
if (PlayerInput.PrimaryMouseButtonDown()) slot.EquipButtonState = GUIComponent.ComponentState.Pressed;
|
||||
if (PlayerInput.PrimaryMouseButtonDown()) { slot.EquipButtonState = GUIComponent.ComponentState.Pressed; }
|
||||
if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
QuickUseItem(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||
@@ -937,28 +937,52 @@ namespace Barotrauma
|
||||
switch (quickUseAction)
|
||||
{
|
||||
case QuickUseAction.Equip:
|
||||
//attempt to put in a free slot first
|
||||
for (int i = capacity - 1; i >= 0; i--)
|
||||
if (string.IsNullOrEmpty(item.Prefab.EquipConfirmationText) || character != Character.Controlled)
|
||||
{
|
||||
if (Items[i] != null) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
|
||||
success = TryPutItem(item, i, true, false, Character.Controlled, true);
|
||||
if (success) { break; }
|
||||
Equip();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "equipconfirmation")) { return; }
|
||||
var equipConfirmation = new GUIMessageBox(string.Empty, TextManager.Get(item.Prefab.EquipConfirmationText),
|
||||
new string[] { TextManager.Get("yes"), TextManager.Get("no") })
|
||||
{
|
||||
UserData = "equipconfirmation"
|
||||
};
|
||||
equipConfirmation.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
Equip();
|
||||
equipConfirmation.Close();
|
||||
return true;
|
||||
};
|
||||
equipConfirmation.Buttons[1].OnClicked = equipConfirmation.Close;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
void Equip()
|
||||
{
|
||||
//attempt to put in a free slot first
|
||||
for (int i = capacity - 1; i >= 0; i--)
|
||||
{
|
||||
if (Items[i] != null) { continue; }
|
||||
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
|
||||
// something else already equipped in a hand slot, attempt to unequip it so items aren't unnecessarily swapped to it
|
||||
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any) && (SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand))
|
||||
{
|
||||
TryPutItem(Items[i], Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
|
||||
}
|
||||
success = TryPutItem(item, i, true, false, Character.Controlled, true);
|
||||
if (success) { break; }
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
for (int i = capacity - 1; i >= 0; i--)
|
||||
{
|
||||
if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
|
||||
// something else already equipped in a hand slot, attempt to unequip it so items aren't unnecessarily swapped to it
|
||||
if (Items[i] != null && Items[i].AllowedSlots.Contains(InvSlotType.Any) && (SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand))
|
||||
{
|
||||
TryPutItem(Items[i], Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
|
||||
}
|
||||
success = TryPutItem(item, i, true, false, Character.Controlled, true);
|
||||
if (success) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QuickUseAction.Unequip:
|
||||
@@ -1046,8 +1070,8 @@ namespace Barotrauma
|
||||
|
||||
public void DrawOwn(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!AccessibleWhenAlive && !character.IsDead) return;
|
||||
if (slots == null) CreateSlots();
|
||||
if (!AccessibleWhenAlive && !character.IsDead) { return; }
|
||||
if (slots == null) { CreateSlots(); }
|
||||
if (GameMain.GraphicsWidth != screenResolution.X ||
|
||||
GameMain.GraphicsHeight != screenResolution.Y ||
|
||||
prevUIScale != UIScale ||
|
||||
@@ -1070,7 +1094,7 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i)) { continue; }
|
||||
|
||||
Rectangle interactRect = slots[i].InteractRect;
|
||||
interactRect.Location += slots[i].DrawOffset.ToPoint();
|
||||
@@ -1086,9 +1110,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
InventorySlot highlightedQuickUseSlot = null;
|
||||
Rectangle inventoryArea = Rectangle.Empty;
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
if (HideSlot(i)) continue;
|
||||
if (HideSlot(i)) { continue; }
|
||||
|
||||
inventoryArea = inventoryArea == Rectangle.Empty ? slots[i].InteractRect : Rectangle.Union(inventoryArea, slots[i].InteractRect);
|
||||
|
||||
if (Items[i] == null ||
|
||||
(draggingItem == Items[i] && !slots[i].InteractRect.Contains(PlayerInput.MousePosition)) ||
|
||||
@@ -1102,7 +1130,7 @@ namespace Barotrauma
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (draggingItem == Items[i] && !slots[i].IsHighlighted) continue;
|
||||
if (draggingItem == Items[i] && !slots[i].IsHighlighted) { continue; }
|
||||
|
||||
//draw hand icons if the item is equipped in a hand slot
|
||||
if (IsInLimbSlot(Items[i], InvSlotType.LeftHand))
|
||||
@@ -1169,7 +1197,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (highlightedQuickUseSlot != null && !string.IsNullOrEmpty(highlightedQuickUseSlot.QuickUseButtonToolTip))
|
||||
if (Locked)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, inventoryArea, new Color(30,30,30,100), isFilled: true);
|
||||
var lockIcon = GUI.Style.GetComponentStyle("LockIcon")?.GetDefaultSprite();
|
||||
lockIcon?.Draw(spriteBatch, inventoryArea.Center.ToVector2(), scale: Math.Min(inventoryArea.Height / lockIcon.size.Y * 0.7f, 1.0f));
|
||||
if (inventoryArea.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, TextManager.Get("handcuffed"), new Rectangle(inventoryArea.Center - new Point(inventoryArea.Height / 2), new Point(inventoryArea.Height)));
|
||||
}
|
||||
}
|
||||
else if (highlightedQuickUseSlot != null && !string.IsNullOrEmpty(highlightedQuickUseSlot.QuickUseButtonToolTip))
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, highlightedQuickUseSlot.QuickUseButtonToolTip, highlightedQuickUseSlot.EquipButtonRect);
|
||||
}
|
||||
|
||||
@@ -68,29 +68,52 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (Window.Height > 0 && Window.Width > 0)
|
||||
{
|
||||
rect.Height = -(int)(Window.Y * item.Scale);
|
||||
|
||||
rect.Y += (int)(doorRect.Height * openState);
|
||||
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
|
||||
rect.Y = Math.Min(doorRect.Y, rect.Y);
|
||||
|
||||
if (convexHull2 != null)
|
||||
if (IsHorizontal)
|
||||
{
|
||||
Rectangle rect2 = doorRect;
|
||||
rect2.Y += (int)(Window.Y * item.Scale - Window.Height * item.Scale);
|
||||
|
||||
rect2.Y += (int)(doorRect.Height * openState);
|
||||
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
|
||||
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
|
||||
|
||||
if (rect2.Height == 0)
|
||||
rect.Width = (int)(Window.X * item.Scale);
|
||||
rect.X -= (int)(doorRect.Width * openState);
|
||||
rect.Width = Math.Max(rect.Width - (doorRect.X - rect.X), 0);
|
||||
rect.X = Math.Max(doorRect.X, rect.X);
|
||||
if (convexHull2 != null)
|
||||
{
|
||||
convexHull2.Enabled = false;
|
||||
Rectangle rect2 = doorRect;
|
||||
rect2.X += (int)(Window.Right * item.Scale);
|
||||
rect2.X -= (int)(doorRect.Width * openState);
|
||||
rect2.X = Math.Max(doorRect.X, rect2.X);
|
||||
rect2.Width = doorRect.Right - (int)(doorRect.Width * openState) - rect2.X;
|
||||
if (rect2.Width == 0)
|
||||
{
|
||||
convexHull2.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
convexHull2.Enabled = true;
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.Height = -(int)(Window.Y * item.Scale);
|
||||
rect.Y += (int)(doorRect.Height * openState);
|
||||
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
|
||||
rect.Y = Math.Min(doorRect.Y, rect.Y);
|
||||
if (convexHull2 != null)
|
||||
{
|
||||
convexHull2.Enabled = true;
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
Rectangle rect2 = doorRect;
|
||||
rect2.Y += (int)(Window.Y * item.Scale - Window.Height * item.Scale);
|
||||
rect2.Y += (int)(doorRect.Height * openState);
|
||||
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
|
||||
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
|
||||
if (rect2.Height == 0)
|
||||
{
|
||||
convexHull2.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
convexHull2.Enabled = true;
|
||||
convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,8 +274,9 @@ namespace Barotrauma.Items.Components
|
||||
bool open = msg.ReadBoolean();
|
||||
bool broken = msg.ReadBoolean();
|
||||
bool forcedOpen = msg.ReadBoolean();
|
||||
bool isStuck = msg.ReadBoolean();
|
||||
SetState(open, isNetworkMessage: true, sendNetworkMessage: false, forcedOpen: forcedOpen);
|
||||
Stuck = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
stuck = msg.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
UInt16 lastUserID = msg.ReadUInt16();
|
||||
Character user = lastUserID == 0 ? null : Entity.FindEntityByID(lastUserID) as Character;
|
||||
if (user != lastUser)
|
||||
@@ -260,7 +284,7 @@ namespace Barotrauma.Items.Components
|
||||
lastUser = user;
|
||||
toggleCooldownTimer = ToggleCoolDown;
|
||||
}
|
||||
|
||||
this.isStuck = isStuck;
|
||||
if (isStuck) { OpenState = 0.0f; }
|
||||
IsBroken = broken;
|
||||
PredictedState = null;
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class VineTile
|
||||
{
|
||||
public void Draw(SpriteBatch spriteBatch, Vector2 position, float depth, float leafDepth)
|
||||
{
|
||||
Vector2 pos = position + Position;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
VineSprite vineSprite = Parent.VineSprites[Type];
|
||||
Color color = Parent.Decayed ? Parent.DeadTint : Parent.VineTint;
|
||||
|
||||
float layer1 = depth + 0.01f, // flowers
|
||||
layer2 = depth + 0.02f, // decay atlas
|
||||
layer3 = depth + 0.03f; // branches and leaves
|
||||
|
||||
float scale = Parent.VineScale * VineStep;
|
||||
|
||||
if (Parent.VineAtlas != null)
|
||||
{
|
||||
spriteBatch.Draw(Parent.VineAtlas.Texture, pos + offset, vineSprite.SourceRect, color, 0f, vineSprite.AbsoluteOrigin, scale, SpriteEffects.None, layer3);
|
||||
}
|
||||
|
||||
if (Parent.DecayAtlas != null)
|
||||
{
|
||||
spriteBatch.Draw(Parent.DecayAtlas.Texture, pos, vineSprite.SourceRect, HealthColor, 0f, vineSprite.AbsoluteOrigin, scale, SpriteEffects.None, layer2);
|
||||
}
|
||||
|
||||
if (FlowerConfig.Variant >= 0 && !Parent.Decayed)
|
||||
{
|
||||
Sprite flowerSprite = Parent.FlowerSprites[FlowerConfig.Variant];
|
||||
flowerSprite.Draw(spriteBatch, pos, Parent.FlowerTint, flowerSprite.Origin, scale: Parent.BaseFlowerScale * FlowerConfig.Scale * FlowerStep, rotate: FlowerConfig.Rotation, depth: layer1);
|
||||
}
|
||||
|
||||
if (LeafConfig.Variant >= 0)
|
||||
{
|
||||
Sprite leafSprite = Parent.LeafSprites[LeafConfig.Variant];
|
||||
leafSprite.Draw(spriteBatch, pos, Parent.Decayed ? Parent.DeadTint : Parent.LeafTint, leafSprite.Origin, scale: Parent.BaseLeafScale * LeafConfig.Scale * FlowerStep, rotate: LeafConfig.Rotation, depth: layer3 + leafDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class VineSprite
|
||||
{
|
||||
[Serialize("0,0,0,0", false)]
|
||||
public Rectangle SourceRect { get; private set; }
|
||||
|
||||
[Serialize("0.5,0.5", false)]
|
||||
public Vector2 Origin { get; private set; }
|
||||
|
||||
public Vector2 AbsoluteOrigin;
|
||||
|
||||
public VineSprite(XElement element)
|
||||
{
|
||||
SerializableProperty.DeserializeProperties(this, element);
|
||||
AbsoluteOrigin = new Vector2(SourceRect.Width * Origin.X, SourceRect.Height * Origin.Y);
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class Growable
|
||||
{
|
||||
public readonly Dictionary<VineTileType, VineSprite> VineSprites = new Dictionary<VineTileType, VineSprite>();
|
||||
public readonly List<Sprite> FlowerSprites = new List<Sprite>();
|
||||
public readonly List<Sprite> LeafSprites = new List<Sprite>();
|
||||
|
||||
public Sprite? VineAtlas, DecayAtlas;
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
VineAtlas?.Remove();
|
||||
DecayAtlas?.Remove();
|
||||
|
||||
foreach (Sprite sprite in FlowerSprites)
|
||||
{
|
||||
sprite.Remove();
|
||||
}
|
||||
|
||||
foreach (Sprite sprite in LeafSprites)
|
||||
{
|
||||
sprite.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Planter planter, Vector2 offset, float depth)
|
||||
{
|
||||
const float zStep = 0.0001f;
|
||||
float leafDepth = 0f;
|
||||
|
||||
foreach (VineTile vine in Vines)
|
||||
{
|
||||
leafDepth += zStep;
|
||||
vine.Draw(spriteBatch, planter.Item.DrawPosition + offset, depth, leafDepth);
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
foreach (Rectangle rect in FailedRectangles)
|
||||
{
|
||||
Rectangle wRect = rect;
|
||||
wRect.Y = -wRect.Y;
|
||||
wRect.Y -= wRect.Height;
|
||||
GUI.DrawRectangle(spriteBatch, wRect, Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void LoadVines(XElement element)
|
||||
{
|
||||
string? vineAtlasPath = element.GetAttributeString("vineatlas", null);
|
||||
string? decayAtlasPath = element.GetAttributeString("decayatlas", null);
|
||||
|
||||
if (vineAtlasPath != null)
|
||||
{
|
||||
VineAtlas = new Sprite(vineAtlasPath, Rectangle.Empty);
|
||||
}
|
||||
|
||||
if (decayAtlasPath != null)
|
||||
{
|
||||
DecayAtlas = new Sprite(decayAtlasPath, Rectangle.Empty);
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "vinesprite":
|
||||
var tileType = subElement.GetAttributeString("type", null);
|
||||
VineTileType type = Enum.Parse<VineTileType>(tileType);
|
||||
VineSprites.Add(type, new VineSprite(subElement));
|
||||
break;
|
||||
case "flowersprite":
|
||||
FlowerSprites.Add(new Sprite(subElement));
|
||||
break;
|
||||
case "leafsprite":
|
||||
LeafSprites.Add(new Sprite(subElement));
|
||||
break;
|
||||
}
|
||||
|
||||
flowerVariants = FlowerSprites.Count;
|
||||
leafVariants = LeafSprites.Count;
|
||||
}
|
||||
|
||||
foreach (VineTileType type in Enum.GetValues(typeof(VineTileType)))
|
||||
{
|
||||
if (!VineSprites.ContainsKey(type))
|
||||
{
|
||||
DebugConsole.ThrowError($"Vine sprite missing from {item.prefab.Identifier}: {type}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly object mutex = new object();
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Health = msg.ReadRangedSingle(0, MaxHealth, 8);
|
||||
int startOffset = msg.ReadRangedInteger(-1, MaximumVines);
|
||||
if (startOffset > -1)
|
||||
{
|
||||
int vineCount = msg.ReadRangedInteger(0, VineChunkSize);
|
||||
List<VineTile> tiles = new List<VineTile>();
|
||||
for (int i = 0; i < vineCount; i++)
|
||||
{
|
||||
VineTileType vineType = (VineTileType) msg.ReadRangedInteger(0b0000, 0b1111);
|
||||
int flowerConfig = msg.ReadRangedInteger(0, 0xFFF);
|
||||
int leafConfig = msg.ReadRangedInteger(0, 0xFFF);
|
||||
sbyte posX = (sbyte) msg.ReadByte(), posY = (sbyte) msg.ReadByte();
|
||||
Vector2 pos = new Vector2(posX * VineTile.Size, posY * VineTile.Size);
|
||||
|
||||
tiles.Add(new VineTile(this, pos, vineType, FoliageConfig.Deserialize(flowerConfig), FoliageConfig.Deserialize(leafConfig)));
|
||||
}
|
||||
|
||||
// is this even needed??
|
||||
lock (mutex)
|
||||
{
|
||||
for (var i = 0; i < vineCount; i++)
|
||||
{
|
||||
int index = i + startOffset;
|
||||
if (index >= Vines.Count)
|
||||
{
|
||||
Vines.Add(tiles[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
VineTile oldVine = Vines[index];
|
||||
VineTile newVine = tiles[i];
|
||||
newVine.GrowthStep = oldVine.GrowthStep;
|
||||
Vines[index] = newVine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateBranchHealth();
|
||||
ResetPlanterSize();
|
||||
}
|
||||
|
||||
private void ResetPlanterSize()
|
||||
{
|
||||
if (item.ParentInventory is ItemInventory itemInventory && itemInventory.Owner is Item parentItem)
|
||||
{
|
||||
if (parentItem.GetComponent<Planter>() is { } planter)
|
||||
{
|
||||
planter.Item.ResetCachedVisibleSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private int seed;
|
||||
|
||||
// Huge bowl of spaghetti
|
||||
public void CreateDebugHUD(Planter planter, PlantSlot slot)
|
||||
{
|
||||
Vector2 relativeSize = new Vector2(0.3f, 0.6f);
|
||||
GUIMessageBox msgBox = new GUIMessageBox(item.Name, "", new[] { TextManager.Get("applysettingsbutton") }, relativeSize);
|
||||
|
||||
GUILayoutGroup content = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.85f), msgBox.Content.RectTransform)) { Stretch = true };
|
||||
GUINumberInput seedInput = CreateIntEntry("Random Seed", seed, content.RectTransform);
|
||||
GUINumberInput vineTileSizeInput = CreateIntEntry("Vine Tile Size (Global)", VineTile.Size, content.RectTransform);
|
||||
GUINumberInput[] leafScaleRangeInput = CreateMinMaxEntry("Leaf Scale Range (Global)", new []{ MinLeafScale, MaxLeafScale }, 1.5f, content.RectTransform);
|
||||
GUINumberInput[] flowerScaleRangeInput = CreateMinMaxEntry("Flower Scale Range (Global)", new []{ MinFlowerScale, MaxFlowerScale }, 1.5f, content.RectTransform);
|
||||
GUINumberInput vineCountInput = CreateIntEntry("Vine Count", MaximumVines, content.RectTransform);
|
||||
GUINumberInput vineScaleInput = CreateFloatEntry("Vine Scale", VineScale, content.RectTransform);
|
||||
GUINumberInput flowerInput = CreateIntEntry("Flower Quantity", FlowerQuantity, content.RectTransform);
|
||||
GUINumberInput flowerScaleInput = CreateFloatEntry("Flower Scale", BaseFlowerScale, content.RectTransform);
|
||||
GUINumberInput leafScaleInput = CreateFloatEntry("Leaf Scale", BaseLeafScale, content.RectTransform);
|
||||
GUINumberInput leafProbabilityInput = CreateFloatEntry("Leaf Probability", LeafProbability, content.RectTransform);
|
||||
GUINumberInput[] leafTintInputs = CreateMinMaxEntry("Leaf Tint", new []{ LeafTint.R / 255f, LeafTint.G / 255f, LeafTint.B / 255f }, 1.0f, content.RectTransform);
|
||||
GUINumberInput[] flowerTintInputs = CreateMinMaxEntry("Flower Tint", new []{ FlowerTint.R / 255f, FlowerTint.G / 255f, FlowerTint.B / 255f }, 1.0f, content.RectTransform);
|
||||
GUINumberInput[] vineTintInputs = CreateMinMaxEntry("Branch Tint", new []{ VineTint.R / 255f, VineTint.G / 255f, VineTint.B / 255f }, 1.0f, content.RectTransform);
|
||||
|
||||
// Apply
|
||||
msgBox.Buttons[0].OnClicked = (button, o) =>
|
||||
{
|
||||
seed = seedInput.IntValue;
|
||||
MaximumVines = vineCountInput.IntValue;
|
||||
FlowerQuantity = flowerInput.IntValue;
|
||||
BaseFlowerScale = flowerScaleInput.FloatValue;
|
||||
VineScale = vineScaleInput.FloatValue;
|
||||
BaseLeafScale = leafScaleInput.FloatValue;
|
||||
LeafProbability = leafProbabilityInput.FloatValue;
|
||||
VineTile.Size = vineTileSizeInput.IntValue;
|
||||
|
||||
MinFlowerScale = flowerScaleRangeInput[0].FloatValue;
|
||||
MaxFlowerScale = flowerScaleRangeInput[1].FloatValue;
|
||||
MinLeafScale = leafScaleRangeInput[0].FloatValue;
|
||||
MaxLeafScale = leafScaleRangeInput[1].FloatValue;
|
||||
|
||||
LeafTint = new Color(leafTintInputs[0].FloatValue, leafTintInputs[1].FloatValue, leafTintInputs[2].FloatValue);
|
||||
FlowerTint = new Color(flowerTintInputs[0].FloatValue, flowerTintInputs[1].FloatValue, flowerTintInputs[2].FloatValue);
|
||||
VineTint = new Color(vineTintInputs[0].FloatValue, vineTintInputs[1].FloatValue, vineTintInputs[2].FloatValue);
|
||||
|
||||
if (FlowerQuantity >= MaximumVines - 1)
|
||||
{
|
||||
vineCountInput.Flash(Color.Red);
|
||||
flowerInput.Flash(Color.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MinFlowerScale > MaxFlowerScale)
|
||||
{
|
||||
foreach (GUINumberInput input in flowerScaleRangeInput)
|
||||
{
|
||||
input.Flash(Color.Red);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MinLeafScale > MaxLeafScale)
|
||||
{
|
||||
foreach (GUINumberInput input in leafScaleRangeInput)
|
||||
{
|
||||
input.Flash(Color.Red);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
msgBox.Close();
|
||||
|
||||
Random random = new Random(seed);
|
||||
Random flowerRandom = new Random(seed);
|
||||
Vines.Clear();
|
||||
GenerateFlowerTiles(flowerRandom);
|
||||
GenerateStem();
|
||||
|
||||
Decayed = false;
|
||||
FullyGrown = false;
|
||||
while (MaximumVines > Vines.Count)
|
||||
{
|
||||
if (!CanGrowMore())
|
||||
{
|
||||
Decayed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
TryGenerateBranches(planter, slot, random, flowerRandom);
|
||||
}
|
||||
|
||||
if (!Decayed)
|
||||
{
|
||||
FullyGrown = true;
|
||||
}
|
||||
|
||||
foreach (VineTile vineTile in Vines)
|
||||
{
|
||||
vineTile.GrowthStep = 2.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private static GUINumberInput CreateIntEntry(string label, int defaultValue, RectTransform parent)
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f), parent), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), label);
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), GUINumberInput.NumberType.Int) { IntValue = defaultValue };
|
||||
return input;
|
||||
}
|
||||
|
||||
private static GUINumberInput CreateFloatEntry(string label, float defaultValue, RectTransform parent)
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f), parent), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), label);
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), GUINumberInput.NumberType.Float) { FloatValue = defaultValue, DecimalsToDisplay = 2 };
|
||||
return input;
|
||||
}
|
||||
|
||||
private static GUINumberInput[] CreateMinMaxEntry(string label, float[] values, float max, RectTransform parent, float min = 0f)
|
||||
{
|
||||
GUILayoutGroup layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f), parent), isHorizontal: true);
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), layout.RectTransform), label);
|
||||
GUINumberInput[] inputs = new GUINumberInput[values.Length];
|
||||
for (var i = 0; i < values.Length; i++)
|
||||
{
|
||||
float value = values[i];
|
||||
GUINumberInput input = new GUINumberInput(new RectTransform(new Vector2(0.5f / values.Length, 1f), layout.RectTransform), GUINumberInput.NumberType.Float)
|
||||
{
|
||||
FloatValue = value, DecimalsToDisplay = 2,
|
||||
MinValueFloat = min,
|
||||
MaxValueFloat = max
|
||||
};
|
||||
inputs[i] = input;
|
||||
}
|
||||
|
||||
return inputs;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,11 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class RangedWeapon : ItemComponent
|
||||
{
|
||||
private Sprite crosshairSprite, crosshairPointerSprite;
|
||||
protected Sprite crosshairSprite, crosshairPointerSprite;
|
||||
|
||||
private Vector2 crosshairPos, crosshairPointerPos;
|
||||
protected Vector2 crosshairPos, crosshairPointerPos;
|
||||
|
||||
private float currentCrossHairScale, currentCrossHairPointerScale;
|
||||
protected float currentCrossHairScale, currentCrossHairPointerScale;
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
|
||||
@@ -86,7 +86,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (crosshairSprite == null) { return; }
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
|
||||
|
||||
//camera focused on some other item/device, don't draw the crosshair
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
|
||||
partial class Sprayer : RangedWeapon, IDrawableComponent
|
||||
{
|
||||
#if DEBUG
|
||||
private Vector2 debugRayStartPos, debugRayEndPos;
|
||||
#endif
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get { return Vector2.Zero; }
|
||||
}
|
||||
|
||||
private readonly List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
private Hull targetHull;
|
||||
|
||||
private Vector2 rayStartWorldPosition;
|
||||
|
||||
private Color color;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
currentCrossHairPointerScale = element.GetAttributeFloat("crosshairscale", 0.1f);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "particleemitter":
|
||||
particleEmitters.Add(new ParticleEmitter(subElement));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<BackgroundSection> targetSections = new List<BackgroundSection>();
|
||||
|
||||
// 0 = 1x1, 1 = 2x2, 2 = 3x3
|
||||
private int spraySetting = 0;
|
||||
private readonly Point[] sprayArray = new Point[8];
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) return;
|
||||
|
||||
#if DEBUG
|
||||
if (PlayerInput.KeyHit(InputType.PreviousFireMode))
|
||||
#else
|
||||
if (PlayerInput.MouseWheelDownClicked())
|
||||
#endif
|
||||
{
|
||||
|
||||
if (spraySetting > 0)
|
||||
{
|
||||
spraySetting--;
|
||||
}
|
||||
else
|
||||
{
|
||||
spraySetting = 2;
|
||||
}
|
||||
|
||||
targetSections.Clear();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (PlayerInput.KeyHit(InputType.NextFireMode))
|
||||
#else
|
||||
if (PlayerInput.MouseWheelUpClicked())
|
||||
#endif
|
||||
{
|
||||
if (spraySetting < 2)
|
||||
{
|
||||
spraySetting++;
|
||||
}
|
||||
else
|
||||
{
|
||||
spraySetting = 0;
|
||||
}
|
||||
|
||||
targetSections.Clear();
|
||||
}
|
||||
|
||||
crosshairPointerPos = PlayerInput.MousePosition;
|
||||
|
||||
Vector2 rayStart;
|
||||
Vector2 sourcePos = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
|
||||
Vector2 barrelPos = item.SimPosition + TransformedBarrelPos;
|
||||
//make sure there's no obstacles between the base of the item (or the shoulder of the character) and the end of the barrel
|
||||
if (Submarine.PickBody(sourcePos, barrelPos, collisionCategory: Physics.CollisionItem | Physics.CollisionItemBlocking | Physics.CollisionWall) == null)
|
||||
{
|
||||
//no obstacles -> we start the raycast at the end of the barrel
|
||||
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition) + TransformedBarrelPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetHull = null;
|
||||
targetSections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 pos = character.CursorWorldPosition;
|
||||
Vector2 rayEnd = ConvertUnits.ToSimUnits(pos);
|
||||
rayStartWorldPosition = ConvertUnits.ToDisplayUnits(rayStart);
|
||||
|
||||
if (Vector2.Distance(rayStartWorldPosition, pos) > Range)
|
||||
{
|
||||
targetHull = null;
|
||||
targetSections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
debugRayStartPos = ConvertUnits.ToDisplayUnits(rayStart);
|
||||
debugRayEndPos = ConvertUnits.ToDisplayUnits(rayEnd);
|
||||
#endif
|
||||
|
||||
Submarine parentSub = character.Submarine ?? item.Submarine;
|
||||
if (parentSub != null)
|
||||
{
|
||||
rayStart -= parentSub.SimPosition;
|
||||
rayEnd -= parentSub.SimPosition;
|
||||
}
|
||||
|
||||
var obstacles = Submarine.PickBodies(rayStart, rayEnd, collisionCategory: Physics.CollisionItem | Physics.CollisionItemBlocking | Physics.CollisionWall);
|
||||
foreach (var body in obstacles)
|
||||
{
|
||||
if (body.UserData is Item item)
|
||||
{
|
||||
var door = item.GetComponent<Door>();
|
||||
if (door != null && door.IsOpen || door.IsBroken) continue;
|
||||
}
|
||||
|
||||
targetHull = null;
|
||||
targetSections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
targetHull = Hull.GetCleanTarget(pos);
|
||||
if (targetHull == null)
|
||||
{
|
||||
targetSections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
BackgroundSection mousedOverSection = targetHull.GetBackgroundSection(pos);
|
||||
|
||||
if (mousedOverSection == null)
|
||||
{
|
||||
targetSections.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to refresh
|
||||
if (targetSections.Count > 0 && mousedOverSection == targetSections[0])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
targetSections.Clear();
|
||||
|
||||
targetSections.Add(mousedOverSection);
|
||||
int mousedOverIndex = mousedOverSection.Index;
|
||||
|
||||
// Start with 2x2
|
||||
if (spraySetting > 0)
|
||||
{
|
||||
sprayArray[0].X = mousedOverIndex + 1;
|
||||
sprayArray[0].Y = mousedOverSection.RowIndex;
|
||||
|
||||
sprayArray[1].X = mousedOverIndex + targetHull.xBackgroundMax;
|
||||
sprayArray[1].Y = mousedOverSection.RowIndex + 1;
|
||||
|
||||
sprayArray[2].X = sprayArray[1].X + 1;
|
||||
sprayArray[2].Y = sprayArray[1].Y;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (targetHull.DoesSectionMatch(sprayArray[i].X, sprayArray[i].Y))
|
||||
{
|
||||
targetSections.Add(targetHull.BackgroundSections[sprayArray[i].X]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add more if it's 3x3
|
||||
if (spraySetting == 2)
|
||||
{
|
||||
sprayArray[3].X = mousedOverIndex - 1;
|
||||
sprayArray[3].Y = mousedOverSection.RowIndex;
|
||||
|
||||
sprayArray[4].X = sprayArray[1].X - 1;
|
||||
sprayArray[4].Y = sprayArray[1].Y;
|
||||
|
||||
sprayArray[5].X = sprayArray[3].X - targetHull.xBackgroundMax;
|
||||
sprayArray[5].Y = sprayArray[3].Y - 1;
|
||||
|
||||
sprayArray[6].X = sprayArray[5].X + 1;
|
||||
sprayArray[6].Y = sprayArray[5].Y;
|
||||
|
||||
sprayArray[7].X = sprayArray[6].X + 1;
|
||||
sprayArray[7].Y = sprayArray[6].Y;
|
||||
|
||||
for (int i = 3; i < sprayArray.Length; i++)
|
||||
{
|
||||
if (targetHull.DoesSectionMatch(sprayArray[i].X, sprayArray[i].Y))
|
||||
{
|
||||
targetSections.Add(targetHull.BackgroundSections[sprayArray[i].X]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (character == null || !character.IsKeyDown(InputType.Aim)) { return; }
|
||||
GUI.HideCursor = targetSections.Count > 0;
|
||||
}
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character == null) { return false; }
|
||||
if (character == Character.Controlled)
|
||||
{
|
||||
if (targetSections.Count == 0) { return false; }
|
||||
Spray(deltaTime);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//allow remote players to use the sprayer, but don't actually color the walls (we'll receive the data from the server)
|
||||
return character.IsRemotePlayer;
|
||||
}
|
||||
}
|
||||
|
||||
public void Spray(float deltaTime)
|
||||
{
|
||||
if (targetSections.Count == 0) { return; }
|
||||
|
||||
Item liquidItem = liquidContainer?.Inventory.Items[0];
|
||||
if (liquidItem == null) { return; }
|
||||
|
||||
bool isCleaning = false;
|
||||
liquidColors.TryGetValue(liquidItem.prefab.Identifier, out color);
|
||||
|
||||
// Ethanol or other cleaning solvent
|
||||
if (color.A == 0) { isCleaning = true; }
|
||||
|
||||
float sizeAdjustedSprayStrength = SprayStrength / targetSections.Count;
|
||||
|
||||
if (!isCleaning)
|
||||
{
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
targetHull.SetSectionColorOrStrength(targetSections[i], color, sizeAdjustedSprayStrength * deltaTime, true, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
targetHull.CleanSection(targetSections[i], -sizeAdjustedSprayStrength * deltaTime, true);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 particleStartPos = item.WorldPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
|
||||
Vector2 particleEndPos = Vector2.Zero;
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
particleEndPos += new Vector2(targetSections[i].Rect.Center.X, targetSections[i].Rect.Y - targetSections[i].Rect.Height / 2) + targetHull.Rect.Location.ToVector2();
|
||||
}
|
||||
particleEndPos /= targetSections.Count;
|
||||
if (targetHull?.Submarine != null)
|
||||
{
|
||||
particleEndPos += targetHull.Submarine.Position;
|
||||
}
|
||||
float dist = Vector2.Distance(particleStartPos, particleEndPos);
|
||||
|
||||
foreach (ParticleEmitter particleEmitter in particleEmitters)
|
||||
{
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
float particleRange = particleEmitter.Prefab.VelocityMax * particleEmitter.Prefab.ParticlePrefab.LifeTime;
|
||||
particleEmitter.Emit(
|
||||
deltaTime, particleStartPos,
|
||||
item.CurrentHull, particleAngle, particleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0, velocityMultiplier: dist / particleRange * 1.5f,
|
||||
colorMultiplier: new Color(color.R, color.G, color.B, (byte)255));
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
#if DEBUG
|
||||
if (GameMain.DebugDraw && Character.Controlled != null && Character.Controlled.IsKeyDown(InputType.Aim))
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(debugRayStartPos.X, -debugRayStartPos.Y),
|
||||
new Vector2(debugRayEndPos.X, -debugRayEndPos.Y),
|
||||
Color.Yellow);
|
||||
}
|
||||
#endif
|
||||
if (Character.Controlled == null || !Character.Controlled.HasEquippedItem(item) || !Character.Controlled.IsKeyDown(InputType.Aim) || targetHull == null || targetSections.Count == 0) return;
|
||||
|
||||
Vector2 drawOffset = targetHull.Submarine == null ? Vector2.Zero : targetHull.Submarine.DrawPosition;
|
||||
Point sectionSize = targetSections[0].Rect.Size;
|
||||
Rectangle drawPositionRect = new Rectangle((int)(drawOffset.X + targetHull.Rect.X), (int)(drawOffset.Y + targetHull.Rect.Y), sectionSize.X, sectionSize.Y);
|
||||
|
||||
if (crosshairSprite == null && crosshairPointerSprite == null)
|
||||
{
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(drawPositionRect.X + targetSections[i].Rect.X, -(drawPositionRect.Y + targetSections[i].Rect.Y)), new Vector2(sectionSize.X, sectionSize.Y), Color.White, false, 0.0f, 1);
|
||||
}
|
||||
}
|
||||
else if (targetSections.Count > 0)
|
||||
{
|
||||
Vector2 drawPos = Vector2.Zero;
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
drawPos += new Vector2(drawPositionRect.X + targetSections[i].Rect.X + sectionSize.X / 2, -(drawPositionRect.Y + targetSections[i].Rect.Y - sectionSize.Y / 2));
|
||||
}
|
||||
drawPos /= targetSections.Count;
|
||||
crosshairSprite?.Draw(spriteBatch, drawPos, scale: sectionSize.X * 3 / crosshairSprite.size.X);
|
||||
crosshairPointerSprite?.Draw(spriteBatch, drawPos, scale: sectionSize.X * (spraySetting + 1) / crosshairPointerSprite.size.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,6 +256,7 @@ namespace Barotrauma.Items.Components
|
||||
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
|
||||
new Vector3(item.WorldPosition, 0.0f),
|
||||
0.01f,
|
||||
loopingSound.RoundSound.GetRandomFrequencyMultiplier(),
|
||||
SoundPlayer.ShouldMuffleSound(Character.Controlled, item.WorldPosition, loopingSound.Range, Character.Controlled?.CurrentHull));
|
||||
loopingSoundChannel.Looping = true;
|
||||
//TODO: tweak
|
||||
@@ -326,7 +327,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
float volume = GetSoundVolume(itemSound);
|
||||
if (volume <= 0.0001f) { return; }
|
||||
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
|
||||
var channel = SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, itemSound.RoundSound.GetRandomFrequencyMultiplier(), item.CurrentHull);
|
||||
if (channel != null) { playingOneshotSoundChannels.Add(channel); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Vector2 transformedItemPos = ItemPos * item.Scale;
|
||||
Vector2 transformedItemInterval = ItemInterval * item.Scale;
|
||||
Vector2 transformedItemIntervalHorizontal = new Vector2(transformedItemInterval.X, 0.0f);
|
||||
Vector2 transformedItemIntervalVertical = new Vector2(0.0f, transformedItemInterval.Y);
|
||||
|
||||
if (item.body == null)
|
||||
{
|
||||
@@ -180,15 +182,26 @@ namespace Barotrauma.Items.Components
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
transformedItemPos.X += item.Rect.Width;
|
||||
transformedItemInterval.X = -transformedItemInterval.X;
|
||||
transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
transformedItemPos.Y = -transformedItemPos.Y;
|
||||
transformedItemPos.Y -= item.Rect.Height;
|
||||
transformedItemInterval.Y = -transformedItemInterval.Y;
|
||||
transformedItemIntervalVertical.Y = -transformedItemIntervalVertical.Y;
|
||||
}
|
||||
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
|
||||
if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
|
||||
|
||||
if (Math.Abs(item.Rotation) > 0.01f)
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(MathHelper.ToRadians(-item.Rotation));
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos - item.DrawPosition, transform) + item.DrawPosition;
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
transformedItemIntervalVertical = Vector2.Transform(transformedItemIntervalVertical, transform);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -197,9 +210,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
transformedItemPos.X = -transformedItemPos.X;
|
||||
transformedItemInterval.X = -transformedItemInterval.X;
|
||||
transformedItemIntervalHorizontal.X = -transformedItemIntervalHorizontal.X;
|
||||
}
|
||||
|
||||
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
transformedItemIntervalHorizontal = Vector2.Transform(transformedItemIntervalHorizontal, transform);
|
||||
|
||||
transformedItemPos += item.DrawPosition;
|
||||
}
|
||||
@@ -207,8 +223,14 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 currentItemPos = transformedItemPos;
|
||||
|
||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||
if ((item.body != null && item.body.Dir == -1) || item.FlippedX) { spriteEffects |= SpriteEffects.FlipHorizontally; }
|
||||
if (item.FlippedY) { spriteEffects |= SpriteEffects.FlipVertically; }
|
||||
if ((item.body != null && item.body.Dir == -1) || item.FlippedX)
|
||||
{
|
||||
spriteEffects |= MathUtils.NearlyEqual(ItemRotation % 180, 90.0f) ? SpriteEffects.FlipVertically : SpriteEffects.FlipHorizontally;
|
||||
}
|
||||
if (item.FlippedY)
|
||||
{
|
||||
spriteEffects |= MathUtils.NearlyEqual(ItemRotation % 180, 90.0f) ? SpriteEffects.FlipHorizontally : SpriteEffects.FlipVertically;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
foreach (Item containedItem in Inventory.Items)
|
||||
@@ -233,7 +255,7 @@ namespace Barotrauma.Items.Components
|
||||
new Vector2(currentItemPos.X, -currentItemPos.Y),
|
||||
containedItem.GetSpriteColor(),
|
||||
origin,
|
||||
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation),
|
||||
-(containedItem.body == null ? 0.0f : containedItem.body.DrawRotation + MathHelper.ToRadians(-item.Rotation)),
|
||||
containedItem.Scale,
|
||||
spriteEffects,
|
||||
depth: containedSpriteDepth);
|
||||
@@ -248,11 +270,11 @@ namespace Barotrauma.Items.Components
|
||||
if (Math.Abs(ItemInterval.X) > 0.001f && Math.Abs(ItemInterval.Y) > 0.001f)
|
||||
{
|
||||
//interval set on both axes -> use a grid layout
|
||||
currentItemPos.X += transformedItemInterval.X;
|
||||
currentItemPos += transformedItemIntervalHorizontal;
|
||||
if (i % ItemsPerRow == 0)
|
||||
{
|
||||
currentItemPos.X = transformedItemPos.X;
|
||||
currentItemPos.Y += transformedItemInterval.Y;
|
||||
currentItemPos = transformedItemPos;
|
||||
currentItemPos += transformedItemIntervalVertical * (i / ItemsPerRow);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -264,6 +286,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
if (item.NonInteractable) { return; }
|
||||
if (Inventory.RectTransform != null)
|
||||
{
|
||||
guiCustomComponent.RectTransform.Parent = Inventory.RectTransform;
|
||||
@@ -272,7 +295,7 @@ namespace Barotrauma.Items.Components
|
||||
//if the item is in the character's inventory, no need to update the item's inventory
|
||||
//because the player can see it by hovering the cursor over the item
|
||||
guiCustomComponent.Visible = item.ParentInventory?.Owner != character && DrawInventory;
|
||||
if (!guiCustomComponent.Visible) return;
|
||||
if (!guiCustomComponent.Visible) { return; }
|
||||
|
||||
Inventory.Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Text;
|
||||
@@ -225,5 +226,10 @@ namespace Barotrauma.Items.Components
|
||||
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + new Vector2(scrollAmount + scrollPadding, 0.0f);
|
||||
textBlock.DrawManually(spriteBatch);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Text = msg.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace Barotrauma.Items.Components
|
||||
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
|
||||
{
|
||||
Vector2 origin = light.LightSprite.Origin;
|
||||
if (light.LightSpriteEffect == SpriteEffects.FlipHorizontally) { origin.X = light.LightSprite.SourceRect.Width - origin.X; }
|
||||
if (light.LightSpriteEffect == SpriteEffects.FlipVertically) { origin.Y = light.LightSprite.SourceRect.Height - origin.Y; }
|
||||
if ((light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = light.LightSprite.SourceRect.Width - origin.X; }
|
||||
if ((light.LightSpriteEffect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically) { origin.Y = light.LightSprite.SourceRect.Height - origin.Y; }
|
||||
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, origin, -light.Rotation, item.Scale, light.LightSpriteEffect, item.SpriteDepth - 0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,9 @@ namespace Barotrauma.Items.Components
|
||||
RelativeOffset = new Vector2(0.05f, 0)
|
||||
}, TextManager.Get("PumpAutoControl", fallBackTag: "ReactorAutoControl"), font: GUI.SubHeadingFont, style: "IndicatorLightYellow")
|
||||
{
|
||||
CanBeFocused = false
|
||||
Selected = false,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get("AutoControlTip")
|
||||
};
|
||||
powerIndicator.TextBlock.Wrap = autoControlIndicator.TextBlock.Wrap = true;
|
||||
powerIndicator.TextBlock.OverrideTextColor(GUI.Style.TextColor);
|
||||
@@ -75,6 +77,7 @@ namespace Barotrauma.Items.Components
|
||||
if (Math.Abs(newTargetForce - targetForce) < 0.01) { return false; }
|
||||
|
||||
targetForce = newTargetForce;
|
||||
User = Character.Controlled;
|
||||
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
@@ -145,7 +148,7 @@ namespace Barotrauma.Items.Components
|
||||
propellerSprite.Draw(spriteBatch, (int)Math.Floor(spriteIndex), drawPos, Color.White, propellerSprite.Origin, 0.0f, Vector2.One);
|
||||
}
|
||||
|
||||
if (editing)
|
||||
if (editing && !GUI.DisableHUD)
|
||||
{
|
||||
Vector2 drawPos = item.DrawPosition;
|
||||
drawPos += PropellerPos;
|
||||
@@ -164,11 +167,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
StartDelayedCorrection(type, msg.ExtractBits(5), sendingTime);
|
||||
StartDelayedCorrection(type, msg.ExtractBits(5 + 16), sendingTime);
|
||||
return;
|
||||
}
|
||||
|
||||
targetForce = msg.ReadRangedInteger(-10, 10) * 10.0f;
|
||||
UInt16 userID = msg.ReadUInt16();
|
||||
if (userID != Entity.NullEntityID)
|
||||
{
|
||||
User = Entity.FindEntityByID(userID) as Character;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Barotrauma.Items.Components
|
||||
OnSelected = (component, userdata) =>
|
||||
{
|
||||
selectedItem = userdata as FabricationRecipe;
|
||||
if (selectedItem != null) SelectItem(Character.Controlled, selectedItem);
|
||||
if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); }
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -292,7 +292,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Item item in inputContainer.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefab == item.prefab));
|
||||
missingItems.Remove(missingItems.FirstOrDefault(mi => mi.ItemPrefabs.Contains(item.prefab)));
|
||||
}
|
||||
|
||||
var availableIngredients = GetAvailableIngredients();
|
||||
@@ -328,12 +328,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (slotIndex >= inputContainer.Capacity) { break; }
|
||||
|
||||
var itemIcon = requiredItem.ItemPrefab.InventoryIcon ?? requiredItem.ItemPrefab.sprite;
|
||||
var itemIcon = requiredItem.ItemPrefabs.First().InventoryIcon ?? requiredItem.ItemPrefabs.First().sprite;
|
||||
Rectangle slotRect = inputContainer.Inventory.slots[slotIndex].Rect;
|
||||
itemIcon.Draw(
|
||||
spriteBatch,
|
||||
slotRect.Center.ToVector2(),
|
||||
color: requiredItem.ItemPrefab.InventoryIconColor * 0.3f,
|
||||
color: requiredItem.ItemPrefabs.First().InventoryIconColor * 0.3f,
|
||||
scale: Math.Min(slotRect.Width / itemIcon.size.X, slotRect.Height / itemIcon.size.Y));
|
||||
|
||||
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
|
||||
@@ -346,14 +346,16 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (slotRect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
string toolTipText = requiredItem.ItemPrefab.Name;
|
||||
var suitableIngredients = requiredItem.ItemPrefabs.Select(ip => ip.Name);
|
||||
string toolTipText = string.Join(", ", suitableIngredients.Count() > 3 ? suitableIngredients.SkipLast(suitableIngredients.Count() - 3) : suitableIngredients);
|
||||
if (suitableIngredients.Count() > 3) { toolTipText += "..."; }
|
||||
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
|
||||
{
|
||||
toolTipText += " " + (int)Math.Round(requiredItem.MinCondition * 100) + "%";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(requiredItem.ItemPrefab.Description))
|
||||
if (!string.IsNullOrEmpty(requiredItem.ItemPrefabs.First().Description))
|
||||
{
|
||||
toolTipText += '\n' + requiredItem.ItemPrefab.Description;
|
||||
toolTipText += '\n' + requiredItem.ItemPrefabs.First().Description;
|
||||
}
|
||||
tooltip = new Pair<Rectangle, string>(slotRect, toolTipText);
|
||||
}
|
||||
@@ -378,10 +380,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (fabricatedItem != null)
|
||||
{
|
||||
float clampedProgressState = Math.Clamp(progressState, 0f, 1f);
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(
|
||||
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - progressState)),
|
||||
slotRect.Width, (int)(slotRect.Height * progressState)),
|
||||
slotRect.X, slotRect.Y + (int)(slotRect.Height * (1.0f - clampedProgressState)),
|
||||
slotRect.Width, (int)(slotRect.Height * clampedProgressState)),
|
||||
GUI.Style.Green * 0.5f, isFilled: true);
|
||||
}
|
||||
|
||||
@@ -429,8 +432,10 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SelectItem(Character user, FabricationRecipe selectedItem)
|
||||
private bool SelectItem(Character user, FabricationRecipe selectedItem, float? overrideRequiredTime = null)
|
||||
{
|
||||
this.selectedItem = selectedItem;
|
||||
|
||||
selectedItemFrame.ClearChildren();
|
||||
selectedItemReqsFrame.ClearChildren();
|
||||
|
||||
@@ -496,7 +501,8 @@ namespace Barotrauma.Items.Components
|
||||
float degreeOfSuccess = user == null ? 0.0f : FabricationDegreeOfSuccess(user, selectedItem.RequiredSkills);
|
||||
if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; }
|
||||
|
||||
float requiredTime = user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user);
|
||||
float requiredTime = overrideRequiredTime ??
|
||||
(user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user));
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform),
|
||||
TextManager.Get("FabricatorRequiredTime") , textColor: ToolBox.GradientLerp(degreeOfSuccess, GUI.Style.Red, Color.Yellow, GUI.Style.Green), font: GUI.SubHeadingFont)
|
||||
@@ -605,7 +611,7 @@ namespace Barotrauma.Items.Components
|
||||
State = newState;
|
||||
timeUntilReady = newTimeUntilReady;
|
||||
|
||||
if (newState == FabricatorState.Stopped || itemIndex == -1 || user == null)
|
||||
if (newState == FabricatorState.Stopped || itemIndex == -1)
|
||||
{
|
||||
CancelFabricating();
|
||||
}
|
||||
|
||||
@@ -81,7 +81,9 @@ namespace Barotrauma.Items.Components
|
||||
autoControlIndicator = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.25f), rightArea.RectTransform, Anchor.TopLeft),
|
||||
TextManager.Get("PumpAutoControl", fallBackTag: "ReactorAutoControl"), font: GUI.SubHeadingFont, style: "IndicatorLightYellow")
|
||||
{
|
||||
CanBeFocused = false
|
||||
Selected = false,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get("AutoControlTip")
|
||||
};
|
||||
autoControlIndicator.TextBlock.AutoScaleHorizontal = true;
|
||||
autoControlIndicator.TextBlock.OverrideTextColor(GUI.Style.TextColor);
|
||||
|
||||
@@ -131,17 +131,23 @@ namespace Barotrauma.Items.Components
|
||||
criticalHeatWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||
TextManager.Get("ReactorWarningCriticalTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||
{
|
||||
CanBeFocused = false
|
||||
Selected = false,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get("ReactorHeatTip")
|
||||
};
|
||||
lowTemperatureWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||
TextManager.Get("ReactorWarningCriticalLowTemp"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||
{
|
||||
CanBeFocused = false
|
||||
Selected = false,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get("ReactorTempTip")
|
||||
};
|
||||
criticalOutputWarning = new GUITickBox(new RectTransform(new Vector2(0.33f, 1.0f), topLeftArea.RectTransform) { MaxSize = maxIndicatorSize },
|
||||
TextManager.Get("ReactorWarningCriticalOutput"), font: GUI.SubHeadingFont, style: "IndicatorLightRed")
|
||||
{
|
||||
CanBeFocused = false
|
||||
Selected = false,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get("ReactorOutputTip")
|
||||
};
|
||||
List<GUITickBox> indicatorLights = new List<GUITickBox>() { criticalHeatWarning, lowTemperatureWarning, criticalOutputWarning };
|
||||
indicatorLights.ForEach(l => l.TextBlock.OverrideTextColor(GUI.Style.TextColor));
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -20,7 +19,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private PathFinder pathFinder;
|
||||
|
||||
private bool dynamicDockingIndicator = true;
|
||||
private readonly bool dynamicDockingIndicator = true;
|
||||
|
||||
private bool unsentChanges;
|
||||
private float networkUpdateTimer;
|
||||
@@ -378,7 +377,6 @@ namespace Barotrauma.Items.Components
|
||||
float edgeDist = Rand.Range(0.0f, 1.0f);
|
||||
Vector2 blipPos = trigger.WorldPosition + Rand.Vector(trigger.ColliderRadius * edgeDist);
|
||||
Vector2 blipVel = flow;
|
||||
if (trigger.ForceFalloff) flow *= (1.0f - edgeDist);
|
||||
|
||||
//go through other triggers in range and add the flows of the ones that the blip is inside
|
||||
foreach (KeyValuePair<LevelTrigger, Vector2> triggerFlow2 in levelTriggerFlows)
|
||||
@@ -387,7 +385,7 @@ namespace Barotrauma.Items.Components
|
||||
if (trigger2 != trigger && Vector2.DistanceSquared(blipPos, trigger2.WorldPosition) < trigger2.ColliderRadius * trigger2.ColliderRadius)
|
||||
{
|
||||
Vector2 trigger2flow = triggerFlow2.Value;
|
||||
if (trigger2.ForceFalloff) trigger2flow *= (1.0f - Vector2.Distance(blipPos, trigger2.WorldPosition) / trigger2.ColliderRadius);
|
||||
if (trigger2.ForceFalloff) trigger2flow *= 1.0f - Vector2.Distance(blipPos, trigger2.WorldPosition) / trigger2.ColliderRadius;
|
||||
blipVel += trigger2flow;
|
||||
}
|
||||
}
|
||||
@@ -507,7 +505,7 @@ namespace Barotrauma.Items.Components
|
||||
float passivePingRadius = (float)(Timing.TotalTime % 1.0f);
|
||||
if (passivePingRadius > 0.0f)
|
||||
{
|
||||
disruptedDirections.Clear();
|
||||
if (activePingsCount == 0) { disruptedDirections.Clear(); }
|
||||
foreach (AITarget t in AITarget.List)
|
||||
{
|
||||
if (t.Entity is Character c && c.Params.HideInSonar) { continue; }
|
||||
@@ -581,14 +579,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMode == Mode.Active && currentPingIndex != -1)
|
||||
if (currentPingIndex != -1)
|
||||
{
|
||||
var activePing = activePings[currentPingIndex];
|
||||
if (activePing.IsDirectional && directionalPingCircle != null)
|
||||
{
|
||||
directionalPingCircle.Draw(spriteBatch, center, Color.White * (1.0f - activePing.State),
|
||||
rotate: MathUtils.VectorToAngle(activePing.Direction),
|
||||
scale: (DisplayRadius / directionalPingCircle.size.X) * activePing.State);
|
||||
rotate: MathUtils.VectorToAngle(activePing.Direction),
|
||||
scale: DisplayRadius / directionalPingCircle.size.X * activePing.State);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -611,13 +609,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (sonarBlips.Count > 0)
|
||||
{
|
||||
zoomSqrt = (float)Math.Sqrt(zoom);
|
||||
float blipScale = 0.08f * (float)Math.Sqrt(zoom) * (rect.Width / 700.0f);
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Additive);
|
||||
|
||||
foreach (SonarBlip sonarBlip in sonarBlips)
|
||||
{
|
||||
DrawBlip(spriteBatch, sonarBlip, transducerCenter, center, sonarBlip.FadeTimer / 2.0f * signalStrength);
|
||||
DrawBlip(spriteBatch, sonarBlip, transducerCenter, center, sonarBlip.FadeTimer / 2.0f * signalStrength, blipScale);
|
||||
}
|
||||
|
||||
spriteBatch.End();
|
||||
@@ -1297,7 +1295,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DrawBlip(SpriteBatch spriteBatch, SonarBlip blip, Vector2 transducerPos, Vector2 center, float strength)
|
||||
private void DrawBlip(SpriteBatch spriteBatch, SonarBlip blip, Vector2 transducerPos, Vector2 center, float strength, float blipScale)
|
||||
{
|
||||
strength = MathHelper.Clamp(strength, 0.0f, 1.0f);
|
||||
|
||||
@@ -1306,8 +1304,8 @@ namespace Barotrauma.Items.Components
|
||||
Vector2 pos = (blip.Position - transducerPos) * displayScale * zoom;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (Rand.Range(0.5f, 2.0f) < distort) pos.X = -pos.X;
|
||||
if (Rand.Range(0.5f, 2.0f) < distort) pos.Y = -pos.Y;
|
||||
if (Rand.Range(0.5f, 2.0f) < distort) { pos.X = -pos.X; }
|
||||
if (Rand.Range(0.5f, 2.0f) < distort) { pos.Y = -pos.Y; }
|
||||
|
||||
float posDistSqr = pos.LengthSquared();
|
||||
if (posDistSqr > DisplayRadius * DisplayRadius)
|
||||
@@ -1324,15 +1322,15 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
Vector2 dir = pos / (float)Math.Sqrt(posDistSqr);
|
||||
Vector2 normal = new Vector2(dir.Y, -dir.X);
|
||||
float scale = (strength + 3.0f) * blip.Scale * zoomSqrt;
|
||||
float scale = (strength + 3.0f) * blip.Scale * blipScale;
|
||||
Color color = ToolBox.GradientLerp(strength, blipColorGradient[blip.BlipType]);
|
||||
|
||||
sonarBlip.Draw(spriteBatch, center + pos, color, sonarBlip.Origin, blip.Rotation ?? MathUtils.VectorToAngle(pos),
|
||||
blip.Size * scale * 0.04f, SpriteEffects.None, 0);
|
||||
blip.Size * scale * 0.5f, SpriteEffects.None, 0);
|
||||
|
||||
pos += Rand.Range(0.0f, 1.0f) * dir + Rand.Range(-scale, scale) * normal;
|
||||
|
||||
sonarBlip.Draw(spriteBatch, center + pos, color * 0.5f, sonarBlip.Origin, 0, scale * 0.08f, SpriteEffects.None, 0);
|
||||
sonarBlip.Draw(spriteBatch, center + pos, color * 0.5f, sonarBlip.Origin, 0, scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
private void DrawMarker(SpriteBatch spriteBatch, string label, string iconIdentifier, object targetIdentifier, Vector2 worldPosition, Vector2 transducerPosition, float scale, Vector2 center, float radius)
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Barotrauma.Items.Components
|
||||
LevelEnd,
|
||||
LevelStart
|
||||
};
|
||||
|
||||
private GUITickBox maintainPosTickBox, levelEndTickBox, levelStartTickBox;
|
||||
|
||||
private GUIComponent statusContainer, dockingContainer, controlContainer;
|
||||
@@ -349,20 +350,34 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
|
||||
if (GameMain.GameSession?.Campaign != null)
|
||||
if (GameMain.GameSession?.Campaign is CampaignMode campaign)
|
||||
{
|
||||
if (Level.IsLoadedOutpost &&
|
||||
DockingSources.Any(d => d.Docked && (d.DockingTarget?.Item.Submarine?.Info?.IsOutpost ?? false)))
|
||||
{
|
||||
GameMain.GameSession.Campaign.CampaignUI.SelectTab(CampaignMode.InteractionType.Map);
|
||||
GameMain.GameSession.Campaign.ShowCampaignUI = true;
|
||||
// Undocking from an outpost
|
||||
campaign.CampaignUI.SelectTab(CampaignMode.InteractionType.Map);
|
||||
campaign.ShowCampaignUI = true;
|
||||
return false;
|
||||
}
|
||||
else if (!Level.IsLoadedOutpost && DockingModeEnabled && ActiveDockingSource != null &&
|
||||
!ActiveDockingSource.Docked && (DockingTarget?.Item?.Submarine?.Info.IsOutpost ?? false))
|
||||
!ActiveDockingSource.Docked && DockingTarget?.Item?.Submarine == Level.Loaded.StartOutpost && (DockingTarget?.Item?.Submarine?.Info.IsOutpost ?? false))
|
||||
{
|
||||
enterOutpostPrompt = new GUIMessageBox("", TextManager.GetWithVariable("campaignenteroutpostprompt", "[locationname]", DockingTarget.Item.Submarine.Info.Name), new string[] { TextManager.Get("yes"), TextManager.Get("no") });
|
||||
// Docking to an outpost
|
||||
var subsToLeaveBehind = campaign.GetSubsToLeaveBehind(Item.Submarine);
|
||||
if (subsToLeaveBehind.Any())
|
||||
{
|
||||
enterOutpostPrompt = new GUIMessageBox(
|
||||
TextManager.GetWithVariable("enterlocation", "[locationname]", DockingTarget.Item.Submarine.Info.Name),
|
||||
TextManager.Get(subsToLeaveBehind.Count == 1 ? "LeaveSubBehind" : "LeaveSubsBehind"),
|
||||
new string[] { TextManager.Get("yes"), TextManager.Get("no") });
|
||||
}
|
||||
else
|
||||
{
|
||||
enterOutpostPrompt = new GUIMessageBox("",
|
||||
TextManager.GetWithVariable("campaignenteroutpostprompt", "[locationname]", DockingTarget.Item.Submarine.Info.Name),
|
||||
new string[] { TextManager.Get("yes"), TextManager.Get("no") });
|
||||
}
|
||||
enterOutpostPrompt.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
SendDockingSignal();
|
||||
@@ -780,10 +795,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
checkConnectedPortsTimer = CheckConnectedPortsInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
checkConnectedPortsTimer -= deltaTime;
|
||||
}
|
||||
|
||||
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
|
||||
DockingModeEnabled = false;
|
||||
|
||||
|
||||
if (connectedPorts.None()) { return; }
|
||||
|
||||
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
|
||||
foreach (DockingPort sourcePort in connectedPorts)
|
||||
{
|
||||
if (sourcePort.Docked || sourcePort.Item.Submarine == null) { continue; }
|
||||
@@ -795,15 +816,14 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (targetPort.Docked || targetPort.Item.Submarine == null) { continue; }
|
||||
if (targetPort.Item.Submarine == controlledSub || targetPort.IsHorizontal != sourcePort.IsHorizontal) { continue; }
|
||||
if (targetPort.Item.Submarine.DockedTo?.Contains(sourcePort.Item.Submarine) ?? false) { continue; }
|
||||
if (Level.Loaded != null && targetPort.Item.Submarine.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
|
||||
|
||||
int targetDir = targetPort.GetDir();
|
||||
|
||||
if (sourceDir == targetDir) { continue; }
|
||||
if (sourceDir == targetPort.GetDir()) { continue; }
|
||||
|
||||
float dist = Vector2.DistanceSquared(sourcePort.Item.WorldPosition, targetPort.Item.WorldPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
DockingModeEnabled = true;
|
||||
ActiveDockingSource = sourcePort;
|
||||
DockingTarget = targetPort;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class Planter
|
||||
{
|
||||
public Vector2 DrawSize => CalculateSize();
|
||||
|
||||
private Vector2 CalculateSize()
|
||||
{
|
||||
if (GrowableSeeds.All(s => s == null)) { return Vector2.Zero; }
|
||||
|
||||
Point pos = item.DrawPosition.ToPoint();
|
||||
Rectangle rect = new Rectangle(pos, Point.Zero);
|
||||
|
||||
for (int i = 0; i < GrowableSeeds.Length; i++)
|
||||
{
|
||||
Growable seed = GrowableSeeds[i];
|
||||
PlantSlot slot = PlantSlots.ContainsKey(i) ? PlantSlots[i] : NullSlot;
|
||||
if (seed == null) { continue; }
|
||||
|
||||
foreach (VineTile vine in seed.Vines)
|
||||
{
|
||||
Rectangle worldRect = vine.Rect;
|
||||
worldRect.Location += slot.Offset.ToPoint();
|
||||
worldRect.Location += pos;
|
||||
rect = Rectangle.Union(rect, worldRect);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 result = new Vector2(MaxDistance(pos.X, rect.Left, rect.Right) * 2, MaxDistance(pos.Y, rect.Top, rect.Bottom) * 2);
|
||||
return result;
|
||||
|
||||
static float MaxDistance(float origin, float x, float y)
|
||||
{
|
||||
return Math.Max(Math.Abs(origin - x), Math.Abs(origin - y));
|
||||
}
|
||||
}
|
||||
|
||||
private LightComponent lightComponent;
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||
{
|
||||
for (var i = 0; i < GrowableSeeds.Length; i++)
|
||||
{
|
||||
Growable growable = GrowableSeeds[i];
|
||||
PlantSlot slot = PlantSlots.ContainsKey(i) ? PlantSlots[i] : NullSlot;
|
||||
growable?.Draw(spriteBatch, this, slot.Offset, itemDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ namespace Barotrauma.Items.Components
|
||||
private List<Pair<RelatedItem, ParticleEmitter>> particleEmitterHitItem = new List<Pair<RelatedItem, ParticleEmitter>>();
|
||||
|
||||
private float prevProgressBarState;
|
||||
private Item prevProgressBarTarget = null;
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
@@ -65,7 +66,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (ParticleEmitter particleEmitter in particleEmitters)
|
||||
{
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
particleEmitter.Emit(
|
||||
deltaTime, ConvertUnits.ToDisplayUnits(raystart),
|
||||
item.CurrentHull, particleAngle, particleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
|
||||
@@ -92,7 +93,7 @@ namespace Barotrauma.Items.Components
|
||||
if (targetStructure.Submarine != null) particlePos += targetStructure.Submarine.DrawPosition;
|
||||
foreach (var emitter in particleEmitterHitStructure)
|
||||
{
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||
}
|
||||
}
|
||||
@@ -103,7 +104,7 @@ namespace Barotrauma.Items.Components
|
||||
if (targetCharacter.Submarine != null) particlePos += targetCharacter.Submarine.DrawPosition;
|
||||
foreach (var emitter in particleEmitterHitCharacter)
|
||||
{
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||
}
|
||||
}
|
||||
@@ -111,7 +112,7 @@ namespace Barotrauma.Items.Components
|
||||
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem)
|
||||
{
|
||||
float progressBarState = targetItem.ConditionPercentage / 100.0f;
|
||||
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState))
|
||||
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState) || prevProgressBarTarget != targetItem)
|
||||
{
|
||||
var door = targetItem.GetComponent<Door>();
|
||||
if (door == null || door.Stuck <= 0)
|
||||
@@ -121,18 +122,20 @@ namespace Barotrauma.Items.Components
|
||||
targetItem,
|
||||
progressBarPos,
|
||||
progressBarState,
|
||||
GUI.Style.Red, GUI.Style.Green);
|
||||
GUI.Style.Red, GUI.Style.Green,
|
||||
progressBarState < prevProgressBarState ? "progressbar.cutting" : "");
|
||||
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||
}
|
||||
prevProgressBarState = progressBarState;
|
||||
prevProgressBarTarget = targetItem;
|
||||
}
|
||||
|
||||
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
||||
foreach (var emitter in particleEmitterHitItem)
|
||||
{
|
||||
if (!emitter.First.MatchesItem(targetItem)) continue;
|
||||
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
if (!emitter.First.MatchesItem(targetItem)) { continue; }
|
||||
float particleAngle = item.body.Rotation + MathHelper.ToRadians(BarrelRotation) + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
emitter.Second.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Wire wire in panel.DisconnectedWires)
|
||||
{
|
||||
if (wire == DraggingConnected && mouseInRect) { continue; }
|
||||
if (wire.HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
||||
|
||||
Connection recipient = wire.OtherConnection(null);
|
||||
string label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
|
||||
@@ -238,6 +239,7 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < MaxLinked; i++)
|
||||
{
|
||||
if (wires[i] == null || wires[i].Hidden || (DraggingConnected == wires[i] && (mouseIn || Screen.Selected == GameMain.SubEditorScreen))) { continue; }
|
||||
if (wires[i].HiddenInGame && Screen.Selected == GameMain.GameScreen) { continue; }
|
||||
|
||||
Connection recipient = wires[i].OtherConnection(this);
|
||||
string label = recipient == null ? "" : recipient.item.Name + $" ({recipient.DisplayName})";
|
||||
@@ -289,7 +291,7 @@ namespace Barotrauma.Items.Components
|
||||
flashColor * (float)Math.Sin(FlashTimer % flashCycleDuration / flashCycleDuration * MathHelper.Pi * 0.8f), scale: connectorSpriteScale);
|
||||
}
|
||||
|
||||
if (Wires.Any(w => w != null && w != DraggingConnected && !w.Hidden))
|
||||
if (Wires.Any(w => w != null && w != DraggingConnected && !w.Hidden && (!w.HiddenInGame || Screen.Selected != GameMain.GameScreen)))
|
||||
{
|
||||
int screwIndex = (int)Math.Floor(position.Y / 30.0f) % screwSprites.Count;
|
||||
screwSprites[screwIndex].Draw(spriteBatch, position, scale: connectorSpriteScale);
|
||||
@@ -325,7 +327,7 @@ namespace Barotrauma.Items.Components
|
||||
canDrag &&
|
||||
((PlayerInput.MousePosition.X > Math.Min(start.X, end.X) &&
|
||||
PlayerInput.MousePosition.X < Math.Max(start.X, end.X) &&
|
||||
MathUtils.LineToPointDistance(start, end, PlayerInput.MousePosition) < 6) ||
|
||||
MathUtils.LineToPointDistanceSquared(start, end, PlayerInput.MousePosition) < 36) ||
|
||||
Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f ||
|
||||
new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition));
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class MemoryComponent : ItemComponent
|
||||
{
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
Value = msg.ReadString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -165,6 +165,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(target.customInteractHUDText) && target.AllowCustomInteract)
|
||||
{
|
||||
texts.Add(target.customInteractHUDText);
|
||||
textColors.Add(GUI.Style.Green);
|
||||
}
|
||||
|
||||
if (target.IsUnconscious)
|
||||
{
|
||||
texts.Add(TextManager.Get("Unconscious"));
|
||||
|
||||
@@ -17,6 +17,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private GUIProgressBar powerIndicator;
|
||||
|
||||
public int UIElementHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
int height = 0;
|
||||
if (ShowChargeIndicator) { height += powerIndicator.Rect.Height; }
|
||||
if (ShowProjectileIndicator) { height += (int)(Inventory.SlotSpriteSmall.size.Y * Inventory.UIScale) + 5; }
|
||||
return height;
|
||||
}
|
||||
}
|
||||
|
||||
private float recoilTimer;
|
||||
|
||||
private float RetractionTime => Math.Max(Reload * RetractionDurationMultiplier, RecoilTime);
|
||||
@@ -235,12 +246,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null)
|
||||
if (!MathUtils.NearlyEqual(item.Rotation, prevBaseRotation))
|
||||
{
|
||||
drawPos += item.Submarine.DrawPosition;
|
||||
UpdateTransformedBarrelPos();
|
||||
}
|
||||
drawPos.Y = -drawPos.Y;
|
||||
Vector2 drawPos = GetDrawPos();
|
||||
|
||||
float recoilOffset = 0.0f;
|
||||
if (Math.Abs(RecoilDistance) > 0.0f && recoilTimer > 0.0f)
|
||||
@@ -275,7 +285,7 @@ namespace Barotrauma.Items.Components
|
||||
rotation + MathHelper.PiOver2, item.Scale,
|
||||
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
||||
|
||||
if (!editing) { return; }
|
||||
if (!editing || GUI.DisableHUD) { return; }
|
||||
|
||||
float widgetRadius = 60.0f;
|
||||
|
||||
@@ -310,7 +320,7 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
widget.MouseHeld += (deltaTime) =>
|
||||
{
|
||||
minRotation = GetRotationAngle(drawPos);
|
||||
minRotation = GetRotationAngle(GetDrawPos());
|
||||
if (minRotation > maxRotation)
|
||||
{
|
||||
float temp = minRotation;
|
||||
@@ -332,7 +342,7 @@ namespace Barotrauma.Items.Components
|
||||
widget.PreDraw += (sprtBtch, deltaTime) =>
|
||||
{
|
||||
widget.tooltip = "Min: " + (int)MathHelper.ToDegrees(minRotation);
|
||||
widget.DrawPos = drawPos + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * widgetRadius;
|
||||
widget.DrawPos = GetDrawPos() + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * widgetRadius;
|
||||
widget.Update(deltaTime);
|
||||
};
|
||||
});
|
||||
@@ -351,7 +361,7 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
widget.MouseHeld += (deltaTime) =>
|
||||
{
|
||||
maxRotation = GetRotationAngle(drawPos);
|
||||
maxRotation = GetRotationAngle(GetDrawPos());
|
||||
if (minRotation > maxRotation)
|
||||
{
|
||||
float temp = minRotation;
|
||||
@@ -373,12 +383,20 @@ namespace Barotrauma.Items.Components
|
||||
widget.PreDraw += (sprtBtch, deltaTime) =>
|
||||
{
|
||||
widget.tooltip = "Max: " + (int)MathHelper.ToDegrees(maxRotation);
|
||||
widget.DrawPos = drawPos + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * widgetRadius;
|
||||
widget.DrawPos = GetDrawPos() + new Vector2((float)Math.Cos(maxRotation), (float)Math.Sin(maxRotation)) * widgetRadius;
|
||||
widget.Update(deltaTime);
|
||||
};
|
||||
});
|
||||
minRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
maxRotationWidget.Draw(spriteBatch, (float)Timing.Step);
|
||||
|
||||
Vector2 GetDrawPos()
|
||||
{
|
||||
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
|
||||
if (item.Submarine != null) { drawPos += item.Submarine.DrawPosition; }
|
||||
drawPos.Y = -drawPos.Y;
|
||||
return drawPos;
|
||||
}
|
||||
}
|
||||
|
||||
private Widget GetWidget(string id, SpriteBatch spriteBatch, int size = 5, Action<Widget> initMethod = null)
|
||||
|
||||
@@ -715,7 +715,12 @@ namespace Barotrauma
|
||||
/// <returns></returns>
|
||||
public static bool IsMouseOnInventory(bool ignoreDraggedItem = false)
|
||||
{
|
||||
var isSubEditor = Screen.Selected is SubEditorScreen editor && !editor.WiringMode;
|
||||
if (GameMain.GameSession?.Campaign != null &&
|
||||
(GameMain.GameSession.Campaign.ShowCampaignUI || GameMain.GameSession.Campaign.ForceMapUI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Character.Controlled == null) { return false; }
|
||||
|
||||
if (!ignoreDraggedItem)
|
||||
@@ -723,6 +728,8 @@ namespace Barotrauma
|
||||
if (draggingItem != null || DraggingInventory != null) { return true; }
|
||||
}
|
||||
|
||||
var isSubEditor = Screen.Selected is SubEditorScreen editor && !editor.WiringMode;
|
||||
|
||||
if (Character.Controlled.Inventory != null && !isSubEditor)
|
||||
{
|
||||
var inv = Character.Controlled.Inventory;
|
||||
@@ -840,7 +847,8 @@ namespace Barotrauma
|
||||
foreach (var ic in character.SelectedConstruction.ActiveHUDs)
|
||||
{
|
||||
var itemContainer = ic as ItemContainer;
|
||||
if (itemContainer?.Inventory?.slots == null) continue;
|
||||
if (itemContainer?.Inventory?.slots == null) { continue; }
|
||||
if (ic.Item.NonInteractable) { continue; }
|
||||
|
||||
foreach (var slot in itemContainer.Inventory.slots)
|
||||
{
|
||||
@@ -1127,7 +1135,6 @@ namespace Barotrauma
|
||||
return hoverArea;
|
||||
}
|
||||
|
||||
|
||||
public static void DrawFront(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) { return; }
|
||||
@@ -1202,6 +1209,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Color slotColor = Color.White;
|
||||
if ((inventory?.Owner as Item)?.NonInteractable ?? false) { slotColor = Color.Gray; }
|
||||
var itemContainer = item?.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null && (itemContainer.InventoryTopSprite != null || itemContainer.InventoryBottomSprite != null))
|
||||
{
|
||||
@@ -1470,18 +1478,19 @@ namespace Barotrauma
|
||||
{
|
||||
if (receivedItemIDs[i] == 0 || (Entity.FindEntityByID(receivedItemIDs[i]) as Item != Items[i]))
|
||||
{
|
||||
if (Items[i] != null) Items[i].Drop(null);
|
||||
Items[i]?.Drop(null);
|
||||
System.Diagnostics.Debug.Assert(Items[i] == null);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
//iterate backwards to get the item to the Any slots first
|
||||
for (int i = capacity - 1; i >= 0; i--)
|
||||
{
|
||||
if (receivedItemIDs[i] > 0)
|
||||
{
|
||||
if (!(Entity.FindEntityByID(receivedItemIDs[i]) is Item item) || Items[i] == item) { continue; }
|
||||
|
||||
TryPutItem(item, i, true, true, null, false);
|
||||
TryPutItem(item, i, false, false, null, false);
|
||||
for (int j = 0; j < capacity; j++)
|
||||
{
|
||||
if (Items[j] == item && receivedItemIDs[j] != item.ID)
|
||||
|
||||
@@ -92,8 +92,6 @@ namespace Barotrauma
|
||||
return parentInventory == null && (body == null || body.Enabled) && ShowItems;
|
||||
}
|
||||
}
|
||||
|
||||
public float SpriteRotation;
|
||||
|
||||
public Color GetSpriteColor()
|
||||
{
|
||||
@@ -297,7 +295,7 @@ namespace Barotrauma
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
|
||||
decorativeSprite.Sprite.DrawTiled(spriteBatch,
|
||||
new Vector2(DrawPosition.X + offset.X - rect.Width / 2, -(DrawPosition.Y + offset.Y + rect.Height / 2)),
|
||||
size, color: color,
|
||||
@@ -307,15 +305,24 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, SpriteRotation + rotation, Scale, activeSprite.effects, depth);
|
||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, SpriteRotation + rotation, Scale, activeSprite.effects, depth - 0.000001f);
|
||||
Vector2 origin = activeSprite.Origin;
|
||||
if ((activeSprite.effects & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
origin.X = activeSprite.SourceRect.Width - origin.X;
|
||||
}
|
||||
if ((activeSprite.effects & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
|
||||
{
|
||||
origin.Y = activeSprite.SourceRect.Height - origin.Y;
|
||||
}
|
||||
activeSprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + drawOffset, color, origin, rotationRad, Scale, activeSprite.effects, depth);
|
||||
fadeInBrokenSprite?.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X, -DrawPosition.Y) + fadeInBrokenSprite.Offset.ToVector2() * Scale, color * fadeInBrokenSpriteAlpha, origin, rotationRad, Scale, activeSprite.effects, depth - 0.000001f);
|
||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rot = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
|
||||
SpriteRotation + rotation + rot, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
rotationRad + rot, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth), 0.999f));
|
||||
}
|
||||
}
|
||||
@@ -358,7 +365,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
|
||||
|
||||
var ca = (float)Math.Cos(-body.Rotation);
|
||||
var sa = (float)Math.Sin(-body.Rotation);
|
||||
@@ -378,7 +385,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
var (xOff, yOff) = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
var (xOff, yOff) = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, -rotationRad) * Scale;
|
||||
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + xOff, -(DrawPosition.Y + yOff)), color,
|
||||
rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
@@ -437,7 +444,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!ShowLinks) return;
|
||||
if (!ShowLinks || GUI.DisableHUD) { return; }
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
@@ -455,21 +462,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDecorativeSprite(SpriteBatch spriteBatch, DecorativeSprite decorativeSprite, Color color, float depth)
|
||||
{
|
||||
if (!spriteAnimState[decorativeSprite].IsActive) { return; }
|
||||
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
|
||||
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
|
||||
|
||||
var ca = (float)Math.Cos(-body.Rotation);
|
||||
var sa = (float)Math.Sin(-body.Rotation);
|
||||
Vector2 transformedOffset = new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
|
||||
|
||||
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + transformedOffset.X, -(DrawPosition.Y + transformedOffset.Y)), color,
|
||||
-body.Rotation + rotation, decorativeSprite.Scale * Scale, activeSprite.effects,
|
||||
depth: depth + (decorativeSprite.Sprite.Depth - activeSprite.Depth));
|
||||
}
|
||||
|
||||
partial void OnCollisionProjSpecific(float impact)
|
||||
{
|
||||
if (impact > 1.0f &&
|
||||
@@ -512,7 +504,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
|
||||
|
||||
if (Character.Controlled == null) { activeHUDs.Clear(); }
|
||||
|
||||
if (!Linkable) { return; }
|
||||
@@ -1154,7 +1146,6 @@ namespace Barotrauma
|
||||
editingHUDRefreshPending = true;
|
||||
break;
|
||||
case NetEntityEvent.Type.Upgrade:
|
||||
{
|
||||
string identifier = msg.ReadString();
|
||||
byte level = msg.ReadByte();
|
||||
if (UpgradePrefab.Find(identifier) is { } upgradePrefab)
|
||||
@@ -1174,8 +1165,7 @@ namespace Barotrauma
|
||||
|
||||
AddUpgrade(upgrade, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.Invalid:
|
||||
break;
|
||||
}
|
||||
@@ -1391,7 +1381,7 @@ namespace Barotrauma
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
string errorMsg = "Failed to spawn item, prefab not found (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null") + ")";
|
||||
errorMsg += "\n" + string.Join(", ", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name));
|
||||
errorMsg += "\n" + string.Join(", ", GameMain.Config.AllEnabledPackages.Select(cp => cp.Name));
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:PrefabNotFound" + (itemName ?? "null") + (itemIdentifier ?? "null"),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Critical,
|
||||
errorMsg);
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Barotrauma
|
||||
public List<ContainedItemSprite> ContainedSprites = new List<ContainedItemSprite>();
|
||||
public Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
|
||||
public Sprite InventoryIcon;
|
||||
public Sprite MinimapIcon;
|
||||
|
||||
//only used to display correct color in the sub editor, item instances have their own property that can be edited on a per-item basis
|
||||
[Serialize("1.0,1.0,1.0,1.0", false)]
|
||||
@@ -90,6 +91,7 @@ namespace Barotrauma
|
||||
};
|
||||
item.SetTransform(ConvertUnits.ToSimUnits(Submarine.MainSub == null ? item.Position : item.Position - Submarine.MainSub.Position), 0.0f);
|
||||
item.FindHull();
|
||||
item.Submarine = Submarine.MainSub;
|
||||
|
||||
if (PlayerInput.IsShiftDown())
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Barotrauma
|
||||
Vector2.Zero, 0.0f, hull);
|
||||
}
|
||||
|
||||
hull = hull ?? Hull.FindHull(worldPosition, useWorldCoordinates: true);
|
||||
hull ??= Hull.FindHull(worldPosition, useWorldCoordinates: true);
|
||||
bool underwater = hull == null || worldPosition.Y < hull.WorldSurface;
|
||||
|
||||
if (underwater && underwaterBubble)
|
||||
@@ -44,7 +44,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (smoke)
|
||||
{
|
||||
var smokeParticle = GameMain.ParticleManager.CreateParticle(Rand.Range(0.0f, 1.0f) < 0.5f ? "explosionsmoke" : "smoke",
|
||||
GameMain.ParticleManager.CreateParticle(Rand.Range(0.0f, 1.0f) < 0.5f ? "explosionsmoke" : "smoke",
|
||||
ClampParticlePos(worldPosition + Rand.Vector((float)System.Math.Sqrt(Rand.Range(0.0f, attack.Range))), hull),
|
||||
Rand.Vector(Rand.Range(0.0f, particleSpeed)), 0.0f, hull);
|
||||
}
|
||||
@@ -75,11 +75,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (hull != null && !string.IsNullOrWhiteSpace(decal) && decalSize > 0.0f)
|
||||
{
|
||||
hull.AddDecal(decal, worldPosition, decalSize);
|
||||
}
|
||||
|
||||
if (flash)
|
||||
{
|
||||
float displayRange = flashRange.HasValue ? flashRange.Value : attack.Range;
|
||||
|
||||
@@ -12,35 +12,10 @@ namespace Barotrauma
|
||||
partial void UpdateProjSpecific(float growModifier)
|
||||
{
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, OnChangeHull);
|
||||
|
||||
|
||||
lightSource.Color = new Color(1.0f, 0.45f, 0.3f) * Rand.Range(0.8f, 1.0f);
|
||||
if (Math.Abs((lightSource.Range * 0.2f) - Math.Max(size.X, size.Y)) > 1.0f) lightSource.Range = Math.Max(size.X, size.Y) * 5.0f;
|
||||
if (Vector2.DistanceSquared(lightSource.Position,position) > 5.0f) lightSource.Position = position + Vector2.UnitY * 30.0f;
|
||||
|
||||
if (size.X > 256.0f)
|
||||
{
|
||||
if (burnDecals.Count == 0)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition + size/2);
|
||||
if (newDecal != null) burnDecals.Add(newDecal);
|
||||
}
|
||||
else if (WorldPosition.X < burnDecals[0].WorldPosition.X - 256.0f)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition);
|
||||
if (newDecal != null) burnDecals.Insert(0, newDecal);
|
||||
}
|
||||
else if (WorldPosition.X + size.X > burnDecals[burnDecals.Count-1].WorldPosition.X + 256.0f)
|
||||
{
|
||||
var newDecal = hull.AddDecal("burnt", WorldPosition + Vector2.UnitX * size.X);
|
||||
if (newDecal != null) burnDecals.Add(newDecal);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Decal d in burnDecals)
|
||||
{
|
||||
//prevent the decals from fading out as long as the firesource is alive
|
||||
d.FadeTimer = Math.Min(d.FadeTimer, d.FadeInTime);
|
||||
}
|
||||
if (Vector2.DistanceSquared(lightSource.Position, position) > 5.0f) lightSource.Position = position + Vector2.UnitY * 30.0f;
|
||||
}
|
||||
|
||||
public static void EmitParticles(Vector2 size, Vector2 worldPosition, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -12,16 +10,10 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Hull : MapEntity, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public const int MaxDecalsPerHull = 10;
|
||||
|
||||
private readonly List<Decal> decals = new List<Decal>();
|
||||
|
||||
private float serverUpdateDelay;
|
||||
private float remoteWaterVolume, remoteOxygenPercentage;
|
||||
private List<Vector3> remoteFireSources;
|
||||
|
||||
private bool networkUpdatePending;
|
||||
private float networkUpdateTimer;
|
||||
private readonly List<BackgroundSection> remoteBackgroundSections = new List<BackgroundSection>();
|
||||
|
||||
private double lastAmbientLightEditTime;
|
||||
|
||||
@@ -49,11 +41,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private float paintAmount = 0.0f;
|
||||
private float minimumPaintAmountToDraw;
|
||||
|
||||
public override bool IsVisible(Rectangle worldView)
|
||||
{
|
||||
if (Screen.Selected != GameMain.SubEditorScreen && !GameMain.DebugDraw)
|
||||
{
|
||||
if (decals.Count == 0) { return false; }
|
||||
if (decals.Count == 0 && paintAmount < minimumPaintAmountToDraw) { return false; }
|
||||
|
||||
Rectangle worldRect = WorldRect;
|
||||
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) { return false; }
|
||||
@@ -70,20 +65,6 @@ namespace Barotrauma
|
||||
!Submarine.RectContains(MathUtils.ExpandRect(WorldRect, -8), position));
|
||||
}
|
||||
|
||||
public Decal AddDecal(string decalName, Vector2 worldPosition, float scale = 1.0f)
|
||||
{
|
||||
if (decals.Count >= MaxDecalsPerHull) return null;
|
||||
|
||||
var decal = GameMain.DecalManager.CreateDecal(decalName, scale, worldPosition, this);
|
||||
|
||||
if (decal != null)
|
||||
{
|
||||
decals.Add(decal);
|
||||
}
|
||||
|
||||
return decal;
|
||||
}
|
||||
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
@@ -101,39 +82,32 @@ namespace Barotrauma
|
||||
{
|
||||
editingHUD = CreateEditingHUD(Screen.Selected != GameMain.SubEditorScreen);
|
||||
}
|
||||
|
||||
if (!PlayerInput.KeyDown(Keys.Space)) return;
|
||||
|
||||
if (!PlayerInput.KeyDown(Keys.Space)) { return; }
|
||||
bool lClick = PlayerInput.PrimaryMouseButtonClicked();
|
||||
bool rClick = PlayerInput.SecondaryMouseButtonClicked();
|
||||
if (!lClick && !rClick) return;
|
||||
if (!lClick && !rClick) { return; }
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
|
||||
if (lClick)
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
{
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
if (entity == this || !entity.IsHighlighted) { continue; }
|
||||
if (!entity.IsMouseOn(position)) { continue; }
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this))
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
if (entity.Linkable && entity.linkedTo != null)
|
||||
if (entity.Linkable && entity.linkedTo != null && !entity.linkedTo.Contains(this))
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
else if (entity.Linkable && entity.linkedTo != null)
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this))
|
||||
{
|
||||
entity.linkedTo.Remove(this);
|
||||
linkedTo.Remove(entity);
|
||||
|
||||
}
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,7 +125,15 @@ namespace Barotrauma
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
if (!pendingSectionUpdates.Any())
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
}
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { pendingSectionUpdate });
|
||||
}
|
||||
pendingSectionUpdates.Clear();
|
||||
networkUpdatePending = false;
|
||||
networkUpdateTimer = 0.0f;
|
||||
}
|
||||
@@ -189,14 +171,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Decal decal in decals)
|
||||
{
|
||||
decal.Update(deltaTime);
|
||||
}
|
||||
|
||||
decals.RemoveAll(d => d.FadeTimer >= d.LifeTime);
|
||||
|
||||
|
||||
if (waterVolume < 1.0f) return;
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
@@ -324,6 +299,35 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawSectionColors(SpriteBatch spriteBatch)
|
||||
{
|
||||
Vector2 drawOffset = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
|
||||
Point sectionSize = BackgroundSections[0].Rect.Size;
|
||||
Vector2 drawPos = drawOffset + new Vector2(rect.Location.X + sectionSize.X / 2, rect.Location.Y - sectionSize.Y / 2);
|
||||
|
||||
for (int i = 0; i < BackgroundSections.Count; i++)
|
||||
{
|
||||
BackgroundSection section = BackgroundSections[i];
|
||||
|
||||
if (section.ColorStrength < 0.01f || section.Color.A < 1) { continue; }
|
||||
|
||||
if (GameMain.DecalManager.GrimeSprites.Count == 0)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(drawOffset.X + rect.X + section.Rect.X, -(drawOffset.Y + rect.Y + section.Rect.Y)),
|
||||
new Vector2(sectionSize.X, sectionSize.Y),
|
||||
section.GetStrengthAdjustedColor(), true, 0.0f, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 sectionPos = new Vector2(drawPos.X + section.Rect.Location.X, -(drawPos.Y + section.Rect.Location.Y));
|
||||
Vector2 randomOffset = new Vector2(section.Noise.X - 0.5f, section.Noise.Y - 0.5f) * 15.0f;
|
||||
var sprite = GameMain.DecalManager.GrimeSprites[i % GameMain.DecalManager.GrimeSprites.Count];
|
||||
sprite.Draw(spriteBatch, sectionPos + randomOffset, section.GetStrengthAdjustedColor(), scale: 1.25f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateVertices(Camera cam, WaterRenderer renderer)
|
||||
{
|
||||
foreach (EntityGrid entityGrid in EntityGrids)
|
||||
@@ -526,22 +530,38 @@ namespace Barotrauma
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
|
||||
|
||||
msg.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
msg.Write(extraData != null);
|
||||
if (extraData == null)
|
||||
{
|
||||
msg.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
Vector2 normalizedPos = new Vector2(
|
||||
(fireSource.Position.X - rect.X) / rect.Width,
|
||||
(fireSource.Position.Y - (rect.Y - rect.Height)) / rect.Height);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
|
||||
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(normalizedPos.X, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(normalizedPos.Y, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(fireSource.Size.X / rect.Width, 0.0f, 1.0f), 0, 1.0f, 8);
|
||||
msg.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
{
|
||||
msg.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
Vector2 normalizedPos = new Vector2(
|
||||
(fireSource.Position.X - rect.X) / rect.Width,
|
||||
(fireSource.Position.Y - (rect.Y - rect.Height)) / rect.Height);
|
||||
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(normalizedPos.X, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(normalizedPos.Y, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(fireSource.Size.X / rect.Width, 0.0f, 1.0f), 0, 1.0f, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sectorToUpdate = (int)extraData[0];
|
||||
int start = sectorToUpdate * BackgroundSectionsPerNetworkEvent;
|
||||
int end = Math.Min((sectorToUpdate + 1) * BackgroundSectionsPerNetworkEvent, BackgroundSections.Count - 1);
|
||||
msg.WriteRangedInteger(sectorToUpdate, 0, BackgroundSections.Count - 1);
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
msg.WriteRangedSingle(BackgroundSections[i].ColorStrength, 0.0f, 1.0f, 8);
|
||||
msg.Write(BackgroundSections[i].Color.PackedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,6 +585,54 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
bool hasExtraData = message.ReadBoolean();
|
||||
if (hasExtraData)
|
||||
{
|
||||
bool hasSectionUpdate = message.ReadBoolean();
|
||||
if (hasSectionUpdate)
|
||||
{
|
||||
int sectorToUpdate = message.ReadRangedInteger(0, BackgroundSections.Count - 1);
|
||||
int start = sectorToUpdate * BackgroundSectionsPerNetworkEvent;
|
||||
int end = Math.Min((sectorToUpdate + 1) * BackgroundSectionsPerNetworkEvent, BackgroundSections.Count - 1);
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
float colorStrength = message.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
Color color = new Color(message.ReadUInt32());
|
||||
float prevColorStrength = BackgroundSections[i].ColorStrength;
|
||||
BackgroundSections[i].SetColorStrength(colorStrength);
|
||||
BackgroundSections[i].SetColor(color);
|
||||
paintAmount = Math.Max(0, paintAmount + (BackgroundSections[i].ColorStrength - prevColorStrength) / BackgroundSections.Count);
|
||||
|
||||
var remoteBackgroundSection = remoteBackgroundSections.Find(s => s.Index == i);
|
||||
if (remoteBackgroundSection != null)
|
||||
{
|
||||
remoteBackgroundSection.SetColorStrength(colorStrength);
|
||||
remoteBackgroundSection.SetColor(color);
|
||||
}
|
||||
else
|
||||
{
|
||||
remoteBackgroundSections.Add(new BackgroundSection(new Rectangle(0, 0, 1, 1), i, colorStrength, color, 0));
|
||||
}
|
||||
}
|
||||
paintAmount = BackgroundSections.Sum(s => s.ColorStrength);
|
||||
}
|
||||
else
|
||||
{
|
||||
int decalCount = message.ReadRangedInteger(0, MaxDecalsPerHull);
|
||||
decals.Clear();
|
||||
for (int i = 0; i < decalCount; i++)
|
||||
{
|
||||
UInt32 decalId = message.ReadUInt32();
|
||||
float normalizedXPos = message.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
float normalizedYPos = message.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
float decalPosX = MathHelper.Lerp(rect.X, rect.Right, normalizedXPos);
|
||||
float decalPosY = MathHelper.Lerp(rect.Y - rect.Height, rect.Y, normalizedYPos);
|
||||
float decalScale = message.ReadRangedSingle(0.0f, 2.0f, 12);
|
||||
AddDecal(decalId, new Vector2(decalPosX, decalPosY), decalScale, isNetworkEvent: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serverUpdateDelay > 0.0f) { return; }
|
||||
|
||||
ApplyRemoteState();
|
||||
@@ -572,10 +640,14 @@ namespace Barotrauma
|
||||
|
||||
private void ApplyRemoteState()
|
||||
{
|
||||
if (remoteFireSources == null)
|
||||
foreach (BackgroundSection remoteBackgroundSection in remoteBackgroundSections)
|
||||
{
|
||||
return;
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColor(remoteBackgroundSection.Color);
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColorStrength(remoteBackgroundSection.ColorStrength);
|
||||
}
|
||||
remoteBackgroundSections.Clear();
|
||||
|
||||
if (remoteFireSources == null) { return; }
|
||||
|
||||
WaterVolume = remoteWaterVolume;
|
||||
OxygenPercentage = remoteOxygenPercentage;
|
||||
@@ -609,7 +681,6 @@ namespace Barotrauma
|
||||
FireSources.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
remoteFireSources = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace Barotrauma
|
||||
public const int DefaultBufferSize = 2000;
|
||||
public const int DefaultIndoorsBufferSize = 3000;
|
||||
|
||||
public static Vector2 DistortionScale = new Vector2(2f, 2f);
|
||||
public static Vector2 DistortionStrength = new Vector2(0.25f, 0.25f);
|
||||
public static Vector2 DistortionScale = new Vector2(2f, 1.5f);
|
||||
public static Vector2 DistortionStrength = new Vector2(0.01f, 0.33f);
|
||||
public static float BlurAmount = 0.0f;
|
||||
|
||||
public Vector2 WavePos
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using SharpFont;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -87,6 +88,12 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
class VectorPair
|
||||
{
|
||||
public Vector2? A = null;
|
||||
public Vector2? B = null;
|
||||
}
|
||||
|
||||
class ConvexHull
|
||||
{
|
||||
public static List<ConvexHullList> HullLists = new List<ConvexHullList>();
|
||||
@@ -96,6 +103,7 @@ namespace Barotrauma.Lights
|
||||
private readonly Segment[] segments = new Segment[4];
|
||||
private readonly SegmentPoint[] vertices = new SegmentPoint[4];
|
||||
private readonly SegmentPoint[] losVertices = new SegmentPoint[4];
|
||||
private readonly VectorPair[] losOffsets = new VectorPair[4];
|
||||
|
||||
private readonly bool[] backFacing;
|
||||
private readonly bool[] ignoreEdge;
|
||||
@@ -105,6 +113,7 @@ namespace Barotrauma.Lights
|
||||
public VertexPositionColor[] ShadowVertices { get; private set; }
|
||||
public VertexPositionTexture[] PenumbraVertices { get; private set; }
|
||||
public int ShadowVertexCount { get; private set; }
|
||||
public int PenumbraVertexCount { get; private set; }
|
||||
|
||||
private readonly HashSet<ConvexHull> overlappingHulls = new HashSet<ConvexHull>();
|
||||
|
||||
@@ -157,15 +166,24 @@ namespace Barotrauma.Lights
|
||||
|
||||
ParentEntity = parent;
|
||||
|
||||
ShadowVertices = new VertexPositionColor[6 * 2];
|
||||
PenumbraVertices = new VertexPositionTexture[6];
|
||||
ShadowVertices = new VertexPositionColor[6 * 4];
|
||||
PenumbraVertices = new VertexPositionTexture[6 * 4];
|
||||
|
||||
backFacing = new bool[4];
|
||||
ignoreEdge = new bool[4];
|
||||
|
||||
SetVertices(points);
|
||||
|
||||
Enabled = true;
|
||||
float minX = points[0].X, minY = points[0].Y, maxX = points[0].X, maxY = points[0].Y;
|
||||
|
||||
for (int i = 1; i < vertices.Length; i++)
|
||||
{
|
||||
if (points[i].X < minX) minX = points[i].X;
|
||||
if (points[i].Y < minY) minY = points[i].Y;
|
||||
|
||||
if (points[i].X > maxX) maxX = points[i].X;
|
||||
if (points[i].Y > minY) maxY = points[i].Y;
|
||||
}
|
||||
|
||||
BoundingBox = new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
|
||||
|
||||
isHorizontal = BoundingBox.Width > BoundingBox.Height;
|
||||
if (ParentEntity is Structure structure)
|
||||
@@ -180,6 +198,10 @@ namespace Barotrauma.Lights
|
||||
if (door != null) { isHorizontal = door.IsHorizontal; }
|
||||
}
|
||||
|
||||
SetVertices(points);
|
||||
|
||||
Enabled = true;
|
||||
|
||||
var chList = HullLists.Find(h => h.Submarine == parent.Submarine);
|
||||
if (chList == null)
|
||||
{
|
||||
@@ -202,11 +224,17 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (isHorizontal == ch.isHorizontal)
|
||||
{
|
||||
if (BoundingBox == ch.BoundingBox) { return; }
|
||||
|
||||
//hide segments that are roughly at the some position as some other segment (e.g. the ends of two adjacent wall pieces)
|
||||
float mergeDist = 32;
|
||||
float mergeDist = 16;
|
||||
float mergeDistSqr = mergeDist * mergeDist;
|
||||
|
||||
Rectangle intersection = Rectangle.Intersect(BoundingBox, ch.BoundingBox);
|
||||
int intersectionArea = intersection.Width * intersection.Height;
|
||||
int bboxArea = BoundingBox.Width * BoundingBox.Height;
|
||||
int otherBboxArea = ch.BoundingBox.Width * ch.BoundingBox.Height;
|
||||
if (Math.Abs(intersectionArea - bboxArea) < mergeDistSqr) { return; }
|
||||
if (Math.Abs(intersectionArea - otherBboxArea) < mergeDistSqr) { return; }
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < ch.segments.Length; j++)
|
||||
@@ -237,21 +265,67 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
for (int i = 0; i < segments.Length; i++)
|
||||
{
|
||||
//TODO: do something to corner areas where a vertical wall meets a horizontal one
|
||||
if (ignoreEdge[i]) { continue; }
|
||||
if (Vector2.DistanceSquared(segments[i].Start.Pos, segments[i].End.Pos) < 1.0f) { continue; }
|
||||
for (int j = 0; j < ch.segments.Length; j++)
|
||||
{
|
||||
if (ch.ignoreEdge[j]) { continue; }
|
||||
if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, ch.segments[j].End.Pos) < 1.0f) { continue; }
|
||||
if (IsSegmentAInB(segments[i], ch.segments[j]))
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, segments[i].Start.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, false, segments[i].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(ch.segments[j].Start.Pos, segments[i].End.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, false, segments[i].Start.Pos);
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(ch.segments[j].End.Pos, segments[i].Start.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, true, segments[i].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(ch.segments[j].End.Pos, segments[i].End.Pos) < 4.0f)
|
||||
{
|
||||
ch.ShiftSegmentPoint(j, true, segments[i].Start.Pos);
|
||||
}
|
||||
}
|
||||
else if (IsSegmentAInB(ch.segments[j], segments[i]))
|
||||
{
|
||||
ch.ignoreEdge[j] = true;
|
||||
|
||||
if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].Start.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, false, ch.segments[j].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(segments[i].Start.Pos, ch.segments[j].End.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, false, ch.segments[j].Start.Pos);
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].Start.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, true, ch.segments[j].End.Pos);
|
||||
}
|
||||
else if (Vector2.DistanceSquared(segments[i].End.Pos, ch.segments[j].End.Pos) < 4.0f)
|
||||
{
|
||||
ShiftSegmentPoint(i, true, ch.segments[j].Start.Pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ignore edges that are inside some other convex hull
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
if (vertices[i].Pos.X >= ch.BoundingBox.X && vertices[i].Pos.X <= ch.BoundingBox.Right &&
|
||||
vertices[i].Pos.Y >= ch.BoundingBox.Y && vertices[i].Pos.Y <= ch.BoundingBox.Bottom)
|
||||
if (ch.IsPointInside(vertices[i].Pos))
|
||||
{
|
||||
Vector2 p = vertices[(i + 1) % vertices.Length].Pos;
|
||||
|
||||
if (p.X >= ch.BoundingBox.X && p.X <= ch.BoundingBox.Right &&
|
||||
p.Y >= ch.BoundingBox.Y && p.Y <= ch.BoundingBox.Bottom)
|
||||
if (ch.IsPointInside(vertices[(i + 1) % vertices.Length].Pos))
|
||||
{
|
||||
ignoreEdge[i] = true;
|
||||
overlappingHulls.Add(ch);
|
||||
@@ -260,6 +334,75 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
private void ShiftSegmentPoint(int segmentIndex, bool end, Vector2 newPos)
|
||||
{
|
||||
var segment = segments[segmentIndex];
|
||||
|
||||
losOffsets[segmentIndex] ??= new VectorPair();
|
||||
bool flipped = false;
|
||||
if (Vector2.DistanceSquared(vertices[segmentIndex].Pos, segment.Start.Pos) > Vector2.DistanceSquared(vertices[segmentIndex].Pos, segment.End.Pos))
|
||||
{
|
||||
flipped = true;
|
||||
}
|
||||
if (end == !flipped)
|
||||
{
|
||||
losOffsets[segmentIndex].B = newPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
losOffsets[segmentIndex].A = newPos;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSegmentAInB(Segment a, Segment b)
|
||||
{
|
||||
if (Vector2.DistanceSquared(a.Start.Pos, a.End.Pos) > Vector2.DistanceSquared(b.Start.Pos, b.End.Pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector2 min = new Vector2(Math.Min(b.Start.Pos.X, b.End.Pos.X), Math.Min(b.Start.Pos.Y, b.End.Pos.Y));
|
||||
Vector2 max = new Vector2(Math.Max(b.Start.Pos.X, b.End.Pos.X), Math.Max(b.Start.Pos.Y, b.End.Pos.Y));
|
||||
min.X -= 1.0f; min.Y -= 1.0f;
|
||||
max.X += 1.0f; max.Y += 1.0f;
|
||||
|
||||
if (a.Start.Pos.X < min.X) { return false; }
|
||||
if (a.Start.Pos.Y < min.Y) { return false; }
|
||||
if (a.End.Pos.X < min.X) { return false; }
|
||||
if (a.End.Pos.Y < min.Y) { return false; }
|
||||
|
||||
if (a.Start.Pos.X > max.X) { return false; }
|
||||
if (a.Start.Pos.Y > max.Y) { return false; }
|
||||
if (a.End.Pos.X > max.X) { return false; }
|
||||
if (a.End.Pos.Y > max.Y) { return false; }
|
||||
|
||||
float startDist = MathUtils.LineToPointDistanceSquared(b.Start.Pos, b.End.Pos, a.Start.Pos);
|
||||
if (startDist > 1.0f) { return false; }
|
||||
float endDist = MathUtils.LineToPointDistanceSquared(b.Start.Pos, b.End.Pos, a.End.Pos);
|
||||
if (endDist > 1.0f) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsPointInside(Vector2 point)
|
||||
{
|
||||
if (!BoundingBox.Contains(point)) { return false; }
|
||||
|
||||
Vector2 center = (vertices[0].Pos + vertices[1].Pos + vertices[2].Pos + vertices[3].Pos) * 0.25f;
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
Vector2 segmentVector = vertices[(i + 1) % 4].Pos - vertices[i].Pos;
|
||||
Vector2 centerToVertex = center - vertices[i].Pos;
|
||||
Vector2 pointToVertex = point - vertices[i].Pos;
|
||||
|
||||
float dotCenter = Vector2.Dot(centerToVertex, segmentVector);
|
||||
float dotPoint = Vector2.Dot(pointToVertex, segmentVector);
|
||||
|
||||
if ((dotCenter > 0f && dotPoint < 0f) || (dotCenter < 0f && dotPoint > 0f)) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void MergeSegments(Segment segment1, Segment segment2, bool startPointsMatch)
|
||||
{
|
||||
int startPointIndex = -1, endPointIndex = -1;
|
||||
@@ -344,6 +487,8 @@ namespace Barotrauma.Lights
|
||||
vertices[i].Pos += amount;
|
||||
losVertices[i].Pos += amount;
|
||||
|
||||
losOffsets[i] = null;
|
||||
|
||||
segments[i].Start.Pos += amount;
|
||||
segments[i].End.Pos += amount;
|
||||
}
|
||||
@@ -406,6 +551,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
vertices[i] = new SegmentPoint(points[i], this);
|
||||
losVertices[i] = new SegmentPoint(points[i], this);
|
||||
losOffsets[i] = null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -517,7 +663,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public void CalculateShadowVertices(Vector2 lightSourcePos, bool los = true)
|
||||
public void CalculateLosVertices(Vector2 lightSourcePos)
|
||||
{
|
||||
Vector3 offset = Vector3.Zero;
|
||||
if (ParentEntity != null && ParentEntity.Submarine != null)
|
||||
@@ -527,8 +673,6 @@ namespace Barotrauma.Lights
|
||||
|
||||
ShadowVertexCount = 0;
|
||||
|
||||
var vertices = los ? losVertices : this.vertices;
|
||||
|
||||
//compute facing of each edge, using N*L
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
@@ -538,8 +682,8 @@ namespace Barotrauma.Lights
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2 firstVertex = vertices[i].Pos;
|
||||
Vector2 secondVertex = vertices[(i+1) % 4].Pos;
|
||||
Vector2 firstVertex = losVertices[i].Pos;
|
||||
Vector2 secondVertex = losVertices[(i+1) % 4].Pos;
|
||||
|
||||
Vector2 L = lightSourcePos - ((firstVertex + secondVertex) / 2.0f);
|
||||
|
||||
@@ -547,121 +691,144 @@ namespace Barotrauma.Lights
|
||||
-(secondVertex.Y - firstVertex.Y),
|
||||
secondVertex.X - firstVertex.X);
|
||||
|
||||
backFacing[i] = (Vector2.Dot(N, L) < 0) == los;
|
||||
backFacing[i] = (Vector2.Dot(N, L) < 0);
|
||||
}
|
||||
|
||||
//find beginning and ending vertices which
|
||||
//belong to the shadow
|
||||
int startingIndex = -1;
|
||||
int endingIndex = -1;
|
||||
for (int i = 0; i < 4; i++)
|
||||
ShadowVertexCount = 0;
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
int currentEdge = i;
|
||||
int nextEdge = (i + 1) % 4;
|
||||
if (!backFacing[i]) { continue; }
|
||||
int currentIndex = i;
|
||||
Vector3 vertexPos0 = new Vector3(losOffsets[currentIndex]?.A ?? losVertices[currentIndex].Pos, 0.0f);
|
||||
Vector3 vertexPos1 = new Vector3(losOffsets[currentIndex]?.B ?? losVertices[(currentIndex + 1) % 4].Pos, 0.0f);
|
||||
|
||||
if (backFacing[currentEdge] && !backFacing[nextEdge])
|
||||
endingIndex = nextEdge;
|
||||
if (Vector3.DistanceSquared(vertexPos0, vertexPos1) < 1.0f) { continue; }
|
||||
|
||||
if (!backFacing[currentEdge] && backFacing[nextEdge])
|
||||
startingIndex = nextEdge;
|
||||
}
|
||||
Vector3 L2P0 = vertexPos0 - new Vector3(lightSourcePos, 0);
|
||||
L2P0.Normalize();
|
||||
Vector3 extruded0 = new Vector3(lightSourcePos, 0) + L2P0 * 9000;
|
||||
|
||||
if (startingIndex == -1 || endingIndex == -1) { return; }
|
||||
Vector3 L2P1 = vertexPos1 - new Vector3(lightSourcePos, 0);
|
||||
L2P1.Normalize();
|
||||
Vector3 extruded1 = new Vector3(lightSourcePos, 0) + L2P1 * 9000;
|
||||
|
||||
//nr of vertices that are in the shadow
|
||||
if (endingIndex > startingIndex)
|
||||
ShadowVertexCount = endingIndex - startingIndex + 1;
|
||||
else
|
||||
ShadowVertexCount = 4 + 1 - startingIndex + endingIndex;
|
||||
|
||||
//shadowVertices = new VertexPositionColor[shadowVertexCount * 2];
|
||||
|
||||
//create a triangle strip that has the shape of the shadow
|
||||
int currentIndex = startingIndex;
|
||||
int svCount = 0;
|
||||
while (svCount != ShadowVertexCount * 2)
|
||||
{
|
||||
Vector3 vertexPos = new Vector3(vertices[currentIndex].Pos, 0.0f);
|
||||
|
||||
int i = los ? svCount : svCount + 1;
|
||||
int j = los ? svCount + 1 : svCount;
|
||||
|
||||
//one vertex on the hull
|
||||
ShadowVertices[i] = new VertexPositionColor
|
||||
ShadowVertices[ShadowVertexCount + 0] = new VertexPositionColor
|
||||
{
|
||||
Color = los ? Color.Black : Color.Transparent,
|
||||
Position = vertexPos + offset
|
||||
Color = Color.Black,
|
||||
Position = vertexPos1 + offset
|
||||
};
|
||||
|
||||
//one extruded by the light direction
|
||||
ShadowVertices[j] = new VertexPositionColor
|
||||
ShadowVertices[ShadowVertexCount + 1] = new VertexPositionColor
|
||||
{
|
||||
Color = ShadowVertices[i].Color
|
||||
Color = Color.Black,
|
||||
Position = vertexPos0 + offset
|
||||
};
|
||||
|
||||
Vector3 L2P = vertexPos - new Vector3(lightSourcePos, 0);
|
||||
L2P.Normalize();
|
||||
|
||||
ShadowVertices[j].Position = new Vector3(lightSourcePos, 0) + L2P * 9000 + offset;
|
||||
ShadowVertices[ShadowVertexCount + 2] = new VertexPositionColor
|
||||
{
|
||||
Color = Color.Black,
|
||||
Position = extruded0 + offset
|
||||
};
|
||||
|
||||
svCount += 2;
|
||||
currentIndex = (currentIndex + 1) % 4;
|
||||
ShadowVertices[ShadowVertexCount + 3] = new VertexPositionColor
|
||||
{
|
||||
Color = Color.Black,
|
||||
Position = vertexPos1 + offset
|
||||
};
|
||||
|
||||
ShadowVertices[ShadowVertexCount + 4] = new VertexPositionColor
|
||||
{
|
||||
Color = Color.Black,
|
||||
Position = extruded0 + offset
|
||||
};
|
||||
|
||||
ShadowVertices[ShadowVertexCount + 5] = new VertexPositionColor
|
||||
{
|
||||
Color = Color.Black,
|
||||
Position = extruded1 + offset
|
||||
};
|
||||
|
||||
ShadowVertexCount += 6;
|
||||
}
|
||||
|
||||
if (los)
|
||||
{
|
||||
CalculatePenumbraVertices(startingIndex, endingIndex, lightSourcePos, los);
|
||||
}
|
||||
CalculateLosPenumbraVertices(lightSourcePos);
|
||||
}
|
||||
|
||||
private void CalculatePenumbraVertices(int startingIndex, int endingIndex, Vector2 lightSourcePos, bool los)
|
||||
private void CalculateLosPenumbraVertices(Vector2 lightSourcePos)
|
||||
{
|
||||
var vertices = los ? losVertices : this.vertices;
|
||||
|
||||
Vector3 offset = Vector3.Zero;
|
||||
if (ParentEntity != null && ParentEntity.Submarine != null)
|
||||
{
|
||||
offset = new Vector3(ParentEntity.Submarine.DrawPosition.X, ParentEntity.Submarine.DrawPosition.Y, 0.0f);
|
||||
}
|
||||
|
||||
for (int n = 0; n < 4; n += 3)
|
||||
PenumbraVertexCount = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vector3 penumbraStart = new Vector3((n == 0) ? vertices[startingIndex].Pos : vertices[endingIndex].Pos, 0.0f);
|
||||
int currentIndex = i;
|
||||
int prevIndex = (i + 3) % 4;
|
||||
int nextIndex = (i + 1) % 4;
|
||||
bool disjointed = losOffsets[i]?.A != null;
|
||||
Vector2 vertexPos0 = losOffsets[currentIndex]?.A ?? losVertices[currentIndex].Pos;
|
||||
Vector2 vertexPos1 = losOffsets[currentIndex]?.B ?? losVertices[nextIndex].Pos;
|
||||
|
||||
PenumbraVertices[n] = new VertexPositionTexture
|
||||
if (Vector2.DistanceSquared(vertexPos0, vertexPos1) < 1.0f) { continue; }
|
||||
|
||||
if (backFacing[currentIndex] && (disjointed || (!backFacing[prevIndex])))
|
||||
{
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
Vector3 penumbraStart = new Vector3(vertexPos0, 0.0f);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
PenumbraVertices[n + i + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
|
||||
Vector3 normal = (i == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
if (n > 0) normal = -normal;
|
||||
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) - normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[n + i + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
if (los)
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
PenumbraVertices[n + i + 1].TextureCoordinate = (i == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
else
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[n + i + 1].TextureCoordinate = (i == 0) ? new Vector2(1.0f, 0.0f) : Vector2.Zero;
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) - normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount + j + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
PenumbraVertexCount += 3;
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
disjointed = losOffsets[i]?.B != null;
|
||||
if (backFacing[currentIndex] && (disjointed || (!backFacing[nextIndex])))
|
||||
{
|
||||
var temp = PenumbraVertices[4];
|
||||
PenumbraVertices[4] = PenumbraVertices[5];
|
||||
PenumbraVertices[5] = temp;
|
||||
Vector3 penumbraStart = new Vector3(vertexPos1, 0.0f);
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount] = new VertexPositionTexture
|
||||
{
|
||||
Position = penumbraStart + offset,
|
||||
TextureCoordinate = new Vector2(0.0f, 1.0f)
|
||||
};
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1] = new VertexPositionTexture();
|
||||
Vector3 vertexDir = penumbraStart - new Vector3(lightSourcePos, 0);
|
||||
vertexDir.Normalize();
|
||||
|
||||
Vector3 normal = (j == 0) ? new Vector3(-vertexDir.Y, vertexDir.X, 0.0f) : new Vector3(vertexDir.Y, -vertexDir.X, 0.0f) * 0.05f;
|
||||
|
||||
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) + normal * 20.0f);
|
||||
vertexDir.Normalize();
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
|
||||
|
||||
PenumbraVertices[PenumbraVertexCount + (1 - j) + 1].TextureCoordinate = (j == 0) ? new Vector2(0.05f, 0.0f) : new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
|
||||
PenumbraVertexCount += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ namespace Barotrauma.Lights
|
||||
if (GUI.DisableItemHighlights) { return false; }
|
||||
|
||||
highlightedEntities.Clear();
|
||||
if (Character.Controlled != null)
|
||||
if (Character.Controlled != null && (!Character.Controlled.IsKeyDown(InputType.Aim) || Character.Controlled.SelectedItems.Any(it => it?.GetComponent<Sprayer>() == null)))
|
||||
{
|
||||
if (Character.Controlled.FocusedItem != null)
|
||||
{
|
||||
@@ -532,28 +532,16 @@ namespace Barotrauma.Lights
|
||||
Vector2 relativeLightPos = pos;
|
||||
if (convexHull.ParentEntity?.Submarine != null) relativeLightPos -= convexHull.ParentEntity.Submarine.Position;
|
||||
|
||||
convexHull.CalculateShadowVertices(relativeLightPos, true);
|
||||
convexHull.CalculateLosVertices(relativeLightPos);
|
||||
|
||||
//convert triangle strips to a triangle list
|
||||
for (int i = 0; i < convexHull.ShadowVertexCount * 2 - 2; i++)
|
||||
for (int i = 0; i < convexHull.ShadowVertexCount; i++)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i]);
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i + 1]);
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i + 2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i]);
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i + 2]);
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i + 1]);
|
||||
}
|
||||
shadowVerts.Add(convexHull.ShadowVertices[i]);
|
||||
}
|
||||
|
||||
if (convexHull.ShadowVertexCount > 0)
|
||||
for (int i = 0; i < convexHull.PenumbraVertexCount; i++)
|
||||
{
|
||||
penumbraVerts.AddRange(convexHull.PenumbraVertices);
|
||||
penumbraVerts.Add(convexHull.PenumbraVertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace Barotrauma.Lights
|
||||
private short[] indices;
|
||||
|
||||
private List<ConvexHullList> hullsInRange;
|
||||
|
||||
|
||||
public Texture2D texture;
|
||||
|
||||
public SpriteEffects LightSpriteEffect;
|
||||
@@ -300,6 +300,14 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
public float TextureRange
|
||||
{
|
||||
get
|
||||
{
|
||||
return lightSourceParams.TextureRange;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Background lights are drawn behind submarines and they don't cast shadows.
|
||||
/// </summary>
|
||||
@@ -366,7 +374,7 @@ namespace Barotrauma.Lights
|
||||
var fullChList = ConvexHull.HullLists.Find(x => x.Submarine == sub);
|
||||
if (fullChList == null) return;
|
||||
|
||||
chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, Range, ch.BoundingBox));
|
||||
chList.List = fullChList.List.FindAll(ch => ch.Enabled && MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, ch.BoundingBox));
|
||||
|
||||
NeedsHullCheck = true;
|
||||
}
|
||||
@@ -418,7 +426,7 @@ namespace Barotrauma.Lights
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//only draw if the light overlaps with the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, Range, subBorders))
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
@@ -452,7 +460,7 @@ namespace Barotrauma.Lights
|
||||
subBorders.Location += sub.HiddenSubPosition.ToPoint() - new Point(0, sub.Borders.Height);
|
||||
|
||||
//don't draw any shadows if the light doesn't overlap with the borders of the sub
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, Range, subBorders))
|
||||
if (!MathUtils.CircleIntersectsRectangle(lightPos, TextureRange, subBorders))
|
||||
{
|
||||
if (chList.List.Count > 0) NeedsRecalculation = true;
|
||||
chList.List.Clear();
|
||||
@@ -495,7 +503,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
{
|
||||
if (!chList.IsHidden.Contains(hull)) hulls.Add(hull);
|
||||
if (!chList.IsHidden.Contains(hull)) { hulls.Add(hull); }
|
||||
}
|
||||
foreach (ConvexHull hull in chList.List)
|
||||
{
|
||||
@@ -503,7 +511,7 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
float bounds = Range * 2;
|
||||
float bounds = TextureRange;
|
||||
//find convexhull segments that are close enough and facing towards the light source
|
||||
List<Segment> visibleSegments = new List<Segment>();
|
||||
List<SegmentPoint> points = new List<SegmentPoint>();
|
||||
@@ -513,6 +521,49 @@ namespace Barotrauma.Lights
|
||||
hull.GetVisibleSegments(drawPos, visibleSegments, ignoreEdges: false);
|
||||
}
|
||||
|
||||
//add a square-shaped boundary to make sure we've got something to construct the triangles from
|
||||
//even if there aren't enough hull segments around the light source
|
||||
|
||||
//(might be more effective to calculate if we actually need these extra points)
|
||||
|
||||
Vector2 drawOffset = Vector2.Zero;
|
||||
float boundsExtended = bounds;
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
float cosAngle = (float)Math.Cos(Rotation);
|
||||
float sinAngle = -(float)Math.Sin(Rotation);
|
||||
|
||||
var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTexture.Origin;
|
||||
|
||||
origin /= Math.Max(overrideTextureDims.X, overrideTextureDims.Y);
|
||||
origin -= Vector2.One * 0.5f;
|
||||
|
||||
if (Math.Abs(origin.X) >= 0.45f || Math.Abs(origin.Y) >= 0.45f)
|
||||
{
|
||||
boundsExtended += 5.0f;
|
||||
}
|
||||
|
||||
origin *= TextureRange;
|
||||
|
||||
drawOffset.X = -origin.X * cosAngle - origin.Y * sinAngle;
|
||||
drawOffset.Y = origin.X * sinAngle + origin.Y * cosAngle;
|
||||
}
|
||||
|
||||
var boundaryCorners = new SegmentPoint[] {
|
||||
new SegmentPoint(new Vector2(drawPos.X + drawOffset.X + boundsExtended, drawPos.Y + drawOffset.Y + boundsExtended), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X + drawOffset.X + boundsExtended, drawPos.Y + drawOffset.Y - boundsExtended), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X + drawOffset.X - boundsExtended, drawPos.Y + drawOffset.Y - boundsExtended), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X + drawOffset.X - boundsExtended, drawPos.Y + drawOffset.Y + boundsExtended), null)
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
var s = new Segment(boundaryCorners[i], boundaryCorners[(i + 1) % 4], null);
|
||||
visibleSegments.Add(s);
|
||||
}
|
||||
|
||||
//Generate new points at the intersections between segments
|
||||
//This is necessary for the light volume to generate properly on some subs
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
@@ -532,10 +583,10 @@ namespace Barotrauma.Lights
|
||||
Vector2 p2a = visibleSegments[j].Start.WorldPos;
|
||||
Vector2 p2b = visibleSegments[j].End.WorldPos;
|
||||
|
||||
if (Vector2.DistanceSquared(p1a, p2a) < 25.0f ||
|
||||
Vector2.DistanceSquared(p1a, p2b) < 25.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2a) < 25.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2b) < 25.0f)
|
||||
if (Vector2.DistanceSquared(p1a, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1a, p2b) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2a) < 5.0f ||
|
||||
Vector2.DistanceSquared(p1b, p2b) < 5.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -565,8 +616,8 @@ namespace Barotrauma.Lights
|
||||
mid.Pos -= visibleSegments[i].ConvexHull.ParentEntity.Submarine.DrawPosition;
|
||||
}
|
||||
|
||||
if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 25.0f ||
|
||||
Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 25.0f)
|
||||
if (Vector2.DistanceSquared(start.WorldPos, mid.WorldPos) < 5.0f ||
|
||||
Vector2.DistanceSquared(end.WorldPos, mid.WorldPos) < 5.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -580,6 +631,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
IsHorizontal = visibleSegments[i].IsHorizontal
|
||||
};
|
||||
|
||||
visibleSegments[i] = seg1;
|
||||
visibleSegments.Insert(i + 1, seg2);
|
||||
i--;
|
||||
@@ -588,34 +640,27 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Segment s in visibleSegments)
|
||||
//remove segments that fall out of bounds
|
||||
for (int i = 0; i < visibleSegments.Count; i++)
|
||||
{
|
||||
points.Add(s.Start);
|
||||
points.Add(s.End);
|
||||
if (Math.Abs(s.Start.WorldPos.X - drawPos.X) > bounds) bounds = Math.Abs(s.Start.WorldPos.X - drawPos.X);
|
||||
if (Math.Abs(s.Start.WorldPos.Y - drawPos.Y) > bounds) bounds = Math.Abs(s.Start.WorldPos.Y - drawPos.Y);
|
||||
if (Math.Abs(s.End.WorldPos.X - drawPos.X) > bounds) bounds = Math.Abs(s.End.WorldPos.X - drawPos.X);
|
||||
if (Math.Abs(s.End.WorldPos.Y - drawPos.Y) > bounds) bounds = Math.Abs(s.End.WorldPos.Y - drawPos.Y);
|
||||
Segment s = visibleSegments[i];
|
||||
if (Math.Abs(s.Start.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.Start.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.X - drawPos.X - drawOffset.X) > boundsExtended + 1.0f ||
|
||||
Math.Abs(s.End.WorldPos.Y - drawPos.Y - drawOffset.Y) > boundsExtended + 1.0f)
|
||||
{
|
||||
visibleSegments.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
else
|
||||
{
|
||||
points.Add(s.Start);
|
||||
points.Add(s.End);
|
||||
}
|
||||
}
|
||||
|
||||
//add a square-shaped boundary to make sure we've got something to construct the triangles from
|
||||
//even if there aren't enough hull segments around the light source
|
||||
visibleSegments = visibleSegments.OrderBy(s => MathUtils.LineToPointDistanceSquared(s.Start.WorldPos, s.End.WorldPos, drawPos)).ToList();
|
||||
|
||||
//(might be more effective to calculate if we actually need these extra points)
|
||||
var boundaryCorners = new List<SegmentPoint> {
|
||||
new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y + bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y - bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y - bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y + bounds), null)
|
||||
};
|
||||
|
||||
points.AddRange(boundaryCorners);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
visibleSegments.Add(new Segment(boundaryCorners[i], boundaryCorners[(i + 1) % 4], null));
|
||||
}
|
||||
|
||||
var compareCCW = new CompareSegmentPointCW(drawPos);
|
||||
try
|
||||
{
|
||||
@@ -635,13 +680,15 @@ namespace Barotrauma.Lights
|
||||
//List<Pair<int, Vector2>> preOutput = new List<Pair<int, Vector2>>();
|
||||
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
if (Math.Abs(points[i].WorldPos.X - points[i + 1].WorldPos.X) < 6 &&
|
||||
Math.Abs(points[i].WorldPos.Y - points[i + 1].WorldPos.Y) < 6)
|
||||
for (int j = Math.Min(i + 4, points.Count-1); j > i; j--)
|
||||
{
|
||||
points.RemoveAt(i + 1);
|
||||
i--;
|
||||
if (Math.Abs(points[i].WorldPos.X - points[j].WorldPos.X) < 6 &&
|
||||
Math.Abs(points[i].WorldPos.Y - points[j].WorldPos.Y) < 6)
|
||||
{
|
||||
points.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,16 +698,16 @@ namespace Barotrauma.Lights
|
||||
Vector2 dirNormal = new Vector2(-dir.Y, dir.X) * 3;
|
||||
|
||||
//do two slightly offset raycasts to hit the segment itself and whatever's behind it
|
||||
Pair<int,Vector2> intersection1 = RayCast(drawPos, drawPos + dir * bounds * 2 - dirNormal, visibleSegments);
|
||||
Pair<int,Vector2> intersection2 = RayCast(drawPos, drawPos + dir * bounds * 2 + dirNormal, visibleSegments);
|
||||
Pair<int,Vector2> intersection1 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 - dirNormal, visibleSegments);
|
||||
Pair<int,Vector2> intersection2 = RayCast(drawPos, drawPos + dir * boundsExtended * 2 + dirNormal, visibleSegments);
|
||||
|
||||
if (intersection1.First < 0) return new List<Vector2>();
|
||||
if (intersection2.First < 0) return new List<Vector2>();
|
||||
if (intersection1.First < 0) return null;
|
||||
if (intersection2.First < 0) return null;
|
||||
Segment seg1 = visibleSegments[intersection1.First];
|
||||
Segment seg2 = visibleSegments[intersection2.First];
|
||||
|
||||
bool isPoint1 = MathUtils.LineToPointDistance(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 5.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistance(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 5.0f;
|
||||
bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f;
|
||||
|
||||
if (isPoint1 && isPoint2)
|
||||
{
|
||||
@@ -696,11 +743,13 @@ namespace Barotrauma.Lights
|
||||
//remove points that are very close to each other
|
||||
for (int i = 0; i < output.Count - 1; i++)
|
||||
{
|
||||
if (Math.Abs(output[i].X - output[i + 1].X) < 6 &&
|
||||
Math.Abs(output[i].Y - output[i + 1].Y) < 6)
|
||||
for (int j = Math.Min(i + 4, output.Count - 1); j > i; j--)
|
||||
{
|
||||
output.RemoveAt(i + 1);
|
||||
i--;
|
||||
if (Math.Abs(output[i].X - output[j].X) < 6 &&
|
||||
Math.Abs(output[i].Y - output[j].Y) < 6)
|
||||
{
|
||||
output.RemoveAt(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,7 +758,6 @@ namespace Barotrauma.Lights
|
||||
|
||||
private Pair<int, Vector2> RayCast(Vector2 rayStart, Vector2 rayEnd, List<Segment> segments)
|
||||
{
|
||||
float closestDist = float.PositiveInfinity;
|
||||
Vector2? closestIntersection = null;
|
||||
int segment = -1;
|
||||
|
||||
@@ -724,11 +772,11 @@ namespace Barotrauma.Lights
|
||||
|
||||
//segment's end position always has a higher or equal y coordinate than the start position
|
||||
//so we can do this comparison and skip segments that are at the wrong side of the ray
|
||||
if (s.End.WorldPos.Y < s.Start.WorldPos.Y)
|
||||
/*if (s.End.WorldPos.Y < s.Start.WorldPos.Y)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(s.End.WorldPos.Y >= s.Start.WorldPos.Y,
|
||||
"LightSource raycast failed. Segment's end positions should never be below the start position. Parent entity: " + (s.ConvexHull?.ParentEntity == null ? "null" : s.ConvexHull.ParentEntity.ToString()));
|
||||
}
|
||||
}*/
|
||||
if (s.Start.WorldPos.Y > maxY || s.End.WorldPos.Y < minY) { continue; }
|
||||
//same for the x-axis
|
||||
if (s.Start.WorldPos.X > s.End.WorldPos.X)
|
||||
@@ -741,18 +789,29 @@ namespace Barotrauma.Lights
|
||||
if (s.End.WorldPos.X < minX) continue;
|
||||
if (s.Start.WorldPos.X > maxX) continue;
|
||||
}
|
||||
|
||||
if (s.IsAxisAligned ?
|
||||
MathUtils.GetAxisAlignedLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, s.IsHorizontal, out Vector2 intersection) :
|
||||
MathUtils.GetLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, out intersection))
|
||||
|
||||
bool intersects;
|
||||
Vector2 intersection;
|
||||
if (s.IsAxisAligned)
|
||||
{
|
||||
float dist = Vector2.DistanceSquared(intersection, rayStart);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
closestIntersection = intersection;
|
||||
segment = i;
|
||||
}
|
||||
intersects = MathUtils.GetAxisAlignedLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, s.IsHorizontal, out intersection);
|
||||
}
|
||||
else
|
||||
{
|
||||
intersects = MathUtils.GetLineIntersection(rayStart, rayEnd, s.Start.WorldPos, s.End.WorldPos, out intersection);
|
||||
}
|
||||
|
||||
if (intersects)
|
||||
{
|
||||
closestIntersection = intersection;
|
||||
|
||||
rayEnd = intersection;
|
||||
minX = Math.Min(rayStart.X, rayEnd.X);
|
||||
maxX = Math.Max(rayStart.X, rayEnd.X);
|
||||
minY = Math.Min(rayStart.Y, rayEnd.Y);
|
||||
maxY = Math.Max(rayStart.Y, rayEnd.Y);
|
||||
|
||||
segment = i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +856,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
//hacky fix to exc excessively large light volumes (they used to be up to 4x the range of the light if there was nothing to block the rays).
|
||||
//might want to tweak the raycast logic in a way that this isn't necessary
|
||||
float boundRadius = Range * 1.1f / (1.0f - Math.Max(Math.Abs(uvOffset.X), Math.Abs(uvOffset.Y)));
|
||||
/*float boundRadius = Range * 1.1f / (1.0f - Math.Max(Math.Abs(uvOffset.X), Math.Abs(uvOffset.Y)));
|
||||
Rectangle boundArea = new Rectangle((int)(drawPos.X - boundRadius), (int)(drawPos.Y + boundRadius), (int)(boundRadius * 2), (int)(boundRadius * 2));
|
||||
for (int i = 0; i < rayCastHits.Count; i++)
|
||||
{
|
||||
@@ -805,7 +864,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
rayCastHits[i] = intersection;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Add all the other encounter points as vertices
|
||||
// storing their world position as UV coordinates
|
||||
@@ -818,7 +877,7 @@ namespace Barotrauma.Lights
|
||||
//so we can add new vertices based on these normals
|
||||
Vector2 prevVertex = rayCastHits[i > 0 ? i - 1 : rayCastHits.Count - 1];
|
||||
Vector2 nextVertex = rayCastHits[i < rayCastHits.Count - 1 ? i + 1 : 0];
|
||||
|
||||
|
||||
Vector2 rawDiff = vertex - drawPos;
|
||||
|
||||
//calculate normal of first segment
|
||||
@@ -836,12 +895,18 @@ namespace Barotrauma.Lights
|
||||
//if the normal is pointing towards the light origin
|
||||
//rather than away from it, invert it
|
||||
if (Vector2.DistanceSquared(nDiff2, rawDiff) > Vector2.DistanceSquared(-nDiff2, rawDiff)) nDiff2 = -nDiff2;
|
||||
|
||||
|
||||
//add the normals together and use some magic numbers to create
|
||||
//a somewhat useful/good-looking blur
|
||||
Vector2 nDiff = nDiff1 + nDiff2;
|
||||
nDiff /= Math.Max(Math.Abs(nDiff.X), Math.Abs(nDiff.Y));
|
||||
nDiff *= 50.0f;
|
||||
Vector2 nDiff = nDiff1 * 40.0f;
|
||||
if (MathUtils.GetLineIntersection(vertex + (nDiff1 * 40.0f), nextVertex + (nDiff1 * 40.0f), vertex + (nDiff2 * 40.0f), prevVertex + (nDiff2 * 40.0f), true, out Vector2 intersection))
|
||||
{
|
||||
nDiff = intersection - vertex;
|
||||
if (nDiff.LengthSquared() > 10000.0f)
|
||||
{
|
||||
nDiff /= Math.Max(Math.Abs(nDiff.X), Math.Abs(nDiff.Y)); nDiff *= 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 diff = rawDiff;
|
||||
diff /= Range * 2.0f;
|
||||
@@ -948,6 +1013,50 @@ namespace Barotrauma.Lights
|
||||
/// <param name="spriteBatch"></param>
|
||||
public void DrawSprite(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null)
|
||||
{
|
||||
drawPos += ParentSub.DrawPosition;
|
||||
}
|
||||
drawPos.Y = -drawPos.Y;
|
||||
|
||||
float cosAngle = (float)Math.Cos(Rotation);
|
||||
float sinAngle = -(float)Math.Sin(Rotation);
|
||||
|
||||
float bounds = TextureRange;
|
||||
|
||||
if (OverrideLightTexture != null)
|
||||
{
|
||||
var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTexture.Origin;
|
||||
|
||||
origin /= Math.Max(overrideTextureDims.X, overrideTextureDims.Y);
|
||||
origin *= TextureRange;
|
||||
|
||||
drawPos.X += origin.X * sinAngle + origin.Y * cosAngle;
|
||||
drawPos.Y += origin.X * cosAngle + origin.Y * sinAngle;
|
||||
}
|
||||
|
||||
//add a square-shaped boundary to make sure we've got something to construct the triangles from
|
||||
//even if there aren't enough hull segments around the light source
|
||||
|
||||
//(might be more effective to calculate if we actually need these extra points)
|
||||
var boundaryCorners = new SegmentPoint[] {
|
||||
new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y + bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X + bounds, drawPos.Y - bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y - bounds), null),
|
||||
new SegmentPoint(new Vector2(drawPos.X - bounds, drawPos.Y + bounds), null)
|
||||
};
|
||||
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch, boundaryCorners[i].Pos, boundaryCorners[(i + 1) % 4].Pos, Color.White, 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (DeformableLightSprite != null)
|
||||
{
|
||||
Vector2 origin = DeformableLightSprite.Origin;
|
||||
@@ -976,11 +1085,11 @@ namespace Barotrauma.Lights
|
||||
if (LightSprite != null)
|
||||
{
|
||||
Vector2 origin = LightSprite.Origin;
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
|
||||
if ((LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
origin.X = LightSprite.SourceRect.Width - origin.X;
|
||||
}
|
||||
if (LightSpriteEffect == SpriteEffects.FlipVertically)
|
||||
if ((LightSpriteEffect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically)
|
||||
{
|
||||
origin.Y = LightSprite.SourceRect.Height - origin.Y;
|
||||
}
|
||||
@@ -1088,7 +1197,7 @@ namespace Barotrauma.Lights
|
||||
PrimitiveType.TriangleList, 0, 0, indexCount / 3
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
hullsInRange.Clear();
|
||||
|
||||
@@ -9,8 +9,6 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Map
|
||||
{
|
||||
public bool AllowDebugTeleport;
|
||||
|
||||
class MapAnim
|
||||
{
|
||||
public Location StartLocation;
|
||||
@@ -380,6 +378,7 @@ namespace Barotrauma
|
||||
Location prevLocation = CurrentDisplayLocation;
|
||||
CurrentLocation = HighlightedLocation;
|
||||
Level.Loaded.DebugSetStartLocation(CurrentLocation);
|
||||
Level.Loaded.DebugSetEndLocation(null);
|
||||
|
||||
CurrentLocation.Discovered = true;
|
||||
CurrentLocation.CreateStore();
|
||||
@@ -573,7 +572,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.DebugDraw && location == HighlightedLocation)
|
||||
if (GameMain.DebugDraw && location == HighlightedLocation && (!location.Discovered || !location.Type.HasOutpost))
|
||||
{
|
||||
if (location.Reputation != null)
|
||||
{
|
||||
@@ -589,7 +588,7 @@ namespace Barotrauma
|
||||
Color barColor = ToolBox.GradientLerp(location.Reputation.NormalizedValue, Color.Red, Color.Yellow, Color.LightGreen);
|
||||
GUI.DrawRectangle(spriteBatch, bgRect, Color.Black * 0.8f, isFilled: true);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)dPos.X, (int)dPos.Y, (int)(location.Reputation.NormalizedValue * 255), 32), barColor, isFilled: true);
|
||||
string reputationValue = location.Reputation.Value.ToString(CultureInfo.InvariantCulture);
|
||||
string reputationValue = ((int)location.Reputation.Value).ToString();
|
||||
Vector2 repValueSize = GUI.SubHeadingFont.MeasureString(reputationValue);
|
||||
GUI.DrawString(spriteBatch, dPos + (new Vector2(256, 32) / 2) - (repValueSize / 2), reputationValue, Color.White, Color.Black, font: GUI.SubHeadingFont);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)dPos.X, (int)dPos.Y, 256, 32), Color.White);
|
||||
@@ -607,12 +606,34 @@ namespace Barotrauma
|
||||
Vector2 nameSize = GUI.LargeFont.MeasureString(HighlightedLocation.Name);
|
||||
Vector2 typeSize = GUI.Font.MeasureString(HighlightedLocation.Type.Name);
|
||||
Vector2 size = new Vector2(Math.Max(nameSize.X, typeSize.X), nameSize.Y + typeSize.Y);
|
||||
bool showReputation = HighlightedLocation.Discovered && HighlightedLocation.Type.HasOutpost && HighlightedLocation.Reputation != null;
|
||||
string repLabelText = null, repValueText = null;
|
||||
Vector2 repLabelSize = Vector2.Zero, repBarSize = Vector2.Zero;
|
||||
if (showReputation)
|
||||
{
|
||||
repLabelText = TextManager.Get("reputation");
|
||||
repLabelSize = GUI.Font.MeasureString(repLabelText);
|
||||
size.X = Math.Max(size.X, repLabelSize.X);
|
||||
repBarSize = new Vector2(Math.Max(0.75f * size.X, 100), repLabelSize.Y);
|
||||
size.X = Math.Max(size.X, (4.0f / 3.0f) * repBarSize.X);
|
||||
size.Y += 2 * repLabelSize.Y + 4 + repBarSize.Y;
|
||||
repValueText = ((int)HighlightedLocation.Reputation.Value).ToString();
|
||||
}
|
||||
GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0].Draw(
|
||||
spriteBatch, new Rectangle((int)(pos.X - 60 * GUI.Scale), (int)(pos.Y - size.Y), (int)(size.X + 120 * GUI.Scale), (int)(size.Y * 2.2f)), Color.Black * hudVisibility);
|
||||
GUI.DrawString(spriteBatch, pos - new Vector2(0.0f, size.Y / 2),
|
||||
HighlightedLocation.Name, GUI.Style.TextColor * hudVisibility * 1.5f, font: GUI.LargeFont);
|
||||
GUI.DrawString(spriteBatch, pos + new Vector2(0.0f, size.Y / 2 - GUI.Font.MeasureString(HighlightedLocation.Type.Name).Y),
|
||||
HighlightedLocation.Type.Name, GUI.Style.TextColor * hudVisibility * 1.5f);
|
||||
spriteBatch, new Rectangle((int)(pos.X - 60 * GUI.Scale), (int)(pos.Y - size.Y), (int)(size.X + 120 * GUI.Scale), (int)(size.Y * 2.2f)), Color.Black * hudVisibility);
|
||||
var topLeftPos = pos - new Vector2(0.0f, size.Y / 2);
|
||||
GUI.DrawString(spriteBatch, topLeftPos, HighlightedLocation.Name, GUI.Style.TextColor * hudVisibility * 1.5f, font: GUI.LargeFont);
|
||||
topLeftPos += new Vector2(0.0f, nameSize.Y);
|
||||
GUI.DrawString(spriteBatch, topLeftPos, HighlightedLocation.Type.Name, GUI.Style.TextColor * hudVisibility * 1.5f);
|
||||
if (showReputation)
|
||||
{
|
||||
topLeftPos += new Vector2(0.0f, typeSize.Y + repLabelSize.Y);
|
||||
GUI.DrawString(spriteBatch, topLeftPos, repLabelText, GUI.Style.TextColor * hudVisibility * 1.5f);
|
||||
topLeftPos += new Vector2(0.0f, repLabelSize.Y + 4);
|
||||
Rectangle repBarRect = new Rectangle(new Point((int)topLeftPos.X, (int)topLeftPos.Y), new Point((int)repBarSize.X, (int)repBarSize.Y));
|
||||
RoundSummary.DrawReputationBar(spriteBatch, repBarRect, HighlightedLocation.Reputation.NormalizedValue);
|
||||
GUI.DrawString(spriteBatch, new Vector2(repBarRect.Right + 4, repBarRect.Top), repValueText, GUI.Style.TextColor);
|
||||
}
|
||||
}
|
||||
if (tooltip != null)
|
||||
{
|
||||
|
||||
@@ -159,6 +159,31 @@ namespace Barotrauma
|
||||
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
#if DEBUG
|
||||
if (PlayerInput.KeyHit(Keys.D))
|
||||
{
|
||||
bool terminate = false;
|
||||
foreach (MapEntity entity in selectedList)
|
||||
{
|
||||
if (entity is Item item && item.GetComponent<Planter>() is { } planter)
|
||||
{
|
||||
planter.Update(1.0f, cam);
|
||||
for (var i = 0; i < planter.GrowableSeeds.Length; i++)
|
||||
{
|
||||
Growable seed = planter.GrowableSeeds[i];
|
||||
PlantSlot slot = planter.PlantSlots.ContainsKey(i) ? planter.PlantSlots[i] : Planter.NullSlot;
|
||||
if (seed == null) { continue; }
|
||||
|
||||
seed.CreateDebugHUD(planter, slot);
|
||||
terminate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (terminate) { break; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (PlayerInput.KeyHit(Keys.C))
|
||||
{
|
||||
Copy(selectedList);
|
||||
@@ -897,8 +922,9 @@ namespace Barotrauma
|
||||
Clone(copiedList);
|
||||
|
||||
var clones = mapEntityList.Except(prevEntities).ToList();
|
||||
|
||||
var nonWireClones = clones.Where(c => !(c is Item item) || item.GetComponent<Wire>() == null);
|
||||
if (!nonWireClones.Any()) { nonWireClones = clones; }
|
||||
|
||||
Vector2 center = Vector2.Zero;
|
||||
nonWireClones.ForEach(c => center += c.WorldPosition);
|
||||
center = Submarine.VectorToWorldGrid(center / nonWireClones.Count());
|
||||
|
||||
@@ -185,9 +185,20 @@ namespace Barotrauma
|
||||
public override bool IsVisible(Rectangle worldView)
|
||||
{
|
||||
Rectangle worldRect = WorldRect;
|
||||
Vector2 worldPos = WorldPosition;
|
||||
|
||||
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) { return false; }
|
||||
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) { return false; }
|
||||
Vector2 min = new Vector2(worldRect.X, worldRect.Y - worldRect.Height);
|
||||
Vector2 max = new Vector2(worldRect.Right, worldRect.Y);
|
||||
foreach (DecorativeSprite decorativeSprite in Prefab.DecorativeSprites)
|
||||
{
|
||||
min.X = Math.Min(worldPos.X - decorativeSprite.Sprite.size.X * decorativeSprite.Sprite.RelativeOrigin.X * decorativeSprite.Scale * Scale, min.X);
|
||||
max.X = Math.Max(worldPos.X + decorativeSprite.Sprite.size.X * (1.0f - decorativeSprite.Sprite.RelativeOrigin.X) * decorativeSprite.Scale * Scale, max.X);
|
||||
min.Y = Math.Min(worldPos.Y - decorativeSprite.Sprite.size.Y * (1.0f - decorativeSprite.Sprite.RelativeOrigin.Y) * decorativeSprite.Scale * Scale, min.Y);
|
||||
max.Y = Math.Max(worldPos.Y + decorativeSprite.Sprite.size.Y * decorativeSprite.Sprite.RelativeOrigin.Y * decorativeSprite.Scale * Scale, max.Y);
|
||||
}
|
||||
|
||||
if (min.X > worldView.Right || max.X < worldView.X) { return false; }
|
||||
if ( min.Y > worldView.Y || max.Y < worldView.Y - worldView.Height) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -455,8 +466,16 @@ namespace Barotrauma
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
byte sectionCount = msg.ReadByte();
|
||||
if (sectionCount != Sections.Length)
|
||||
|
||||
bool invalidMessage = false;
|
||||
if (type != ServerNetObject.ENTITY_EVENT && type != ServerNetObject.ENTITY_EVENT_INITIAL)
|
||||
{
|
||||
DebugConsole.NewMessage($"Error while reading a network event for the structure \"{Name} ({ID})\". Invalid event type ({type}).", Color.Red);
|
||||
return;
|
||||
}
|
||||
else if (sectionCount != Sections.Length)
|
||||
{
|
||||
invalidMessage = true;
|
||||
string errorMsg = $"Error while reading a network event for the structure \"{Name} ({ID})\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
@@ -465,7 +484,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < sectionCount; i++)
|
||||
{
|
||||
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * MaxHealth;
|
||||
if (i < Sections.Length)
|
||||
if (!invalidMessage && i < Sections.Length)
|
||||
{
|
||||
SetDamage(i, damage);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -19,6 +20,7 @@ namespace Barotrauma
|
||||
public Sound Sound;
|
||||
public readonly float Volume;
|
||||
public readonly float Range;
|
||||
public readonly Vector2 FrequencyMultiplierRange;
|
||||
public readonly bool Stream;
|
||||
|
||||
public string Filename
|
||||
@@ -32,8 +34,34 @@ namespace Barotrauma
|
||||
Stream = sound.Stream;
|
||||
Range = element.GetAttributeFloat("range", 1000.0f);
|
||||
Volume = element.GetAttributeFloat("volume", 1.0f);
|
||||
FrequencyMultiplierRange = new Vector2(1.0f);
|
||||
string freqMultAttr = element.GetAttributeString("frequencymultiplier", element.GetAttributeString("frequency", "1.0"));
|
||||
if (!freqMultAttr.Contains(','))
|
||||
{
|
||||
if (float.TryParse(freqMultAttr, NumberStyles.Any, CultureInfo.InvariantCulture, out float freqMult))
|
||||
{
|
||||
FrequencyMultiplierRange = new Vector2(freqMult);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var freqMult = XMLExtensions.ParseVector2(freqMultAttr, false);
|
||||
if (freqMult.Y >= 0.25f)
|
||||
{
|
||||
FrequencyMultiplierRange = freqMult;
|
||||
}
|
||||
}
|
||||
if (FrequencyMultiplierRange.Y > 4.0f)
|
||||
{
|
||||
DebugConsole.ThrowError($"Loaded frequency range exceeds max value: {FrequencyMultiplierRange} (original string was \"{freqMultAttr}\")");
|
||||
}
|
||||
sound.IgnoreMuffling = element.GetAttributeBool("dontmuffle", false);
|
||||
}
|
||||
|
||||
public float GetRandomFrequencyMultiplier()
|
||||
{
|
||||
return Rand.Range(FrequencyMultiplierRange.X, FrequencyMultiplierRange.Y);
|
||||
}
|
||||
}
|
||||
|
||||
partial class Submarine : Entity, IServerSerializable
|
||||
@@ -288,6 +316,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawPaintedColors(SpriteBatch spriteBatch, bool editing = false, Predicate<MapEntity> predicate = null)
|
||||
{
|
||||
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList;
|
||||
|
||||
foreach (MapEntity e in entitiesToRender)
|
||||
{
|
||||
if (e is Hull hull)
|
||||
{
|
||||
if (hull.SupportsPaintedColors)
|
||||
{
|
||||
if (predicate != null)
|
||||
{
|
||||
if (!predicate(e)) continue;
|
||||
}
|
||||
|
||||
hull.DrawSectionColors(spriteBatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawBack(SpriteBatch spriteBatch, bool editing = false, Predicate<MapEntity> predicate = null)
|
||||
{
|
||||
var entitiesToRender = !editing && visibleEntities != null ? visibleEntities : MapEntity.mapEntityList;
|
||||
@@ -511,6 +560,11 @@ namespace Barotrauma
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (type != ServerNetObject.ENTITY_POSITION)
|
||||
{
|
||||
DebugConsole.NewMessage($"Error while reading a network event for the submarine \"{Info.Name} ({ID})\". Invalid event type ({type}).", Color.Red);
|
||||
}
|
||||
|
||||
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Info.Name);
|
||||
msg.ReadPadBits();
|
||||
|
||||
|
||||
@@ -238,42 +238,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnterIDCardDesc(GUITextBox textBox, string text)
|
||||
{
|
||||
IdCardDesc = text;
|
||||
textBox.Text = text;
|
||||
textBox.Color = GUI.Style.Green;
|
||||
|
||||
textBox.Deselect();
|
||||
|
||||
return true;
|
||||
}
|
||||
private bool EnterIDCardTags(GUITextBox textBox, string text)
|
||||
{
|
||||
IdCardTags = text.Split(',');
|
||||
textBox.Text = string.Join(",", IdCardTags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
textBox.Deselect();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool EnterTags(GUITextBox textBox, string text)
|
||||
{
|
||||
tags = text.Split(',').ToList();
|
||||
textBox.Text = string.Join(",", Tags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
textBox.Deselect();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TextBoxChanged(GUITextBox textBox, string text)
|
||||
{
|
||||
textBox.Color = GUI.Style.Red;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
private GUIComponent CreateEditingHUD()
|
||||
{
|
||||
int width = 500;
|
||||
int height = spawnType == SpawnType.Path ? 80 : 200;
|
||||
@@ -326,21 +291,48 @@ namespace Barotrauma
|
||||
GUITextBox propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), descText.RectTransform, Anchor.CenterRight), IdCardDesc)
|
||||
{
|
||||
MaxTextLength = 150,
|
||||
OnEnterPressed = EnterIDCardDesc,
|
||||
ToolTip = TextManager.Get("IDCardDescriptionTooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
propertyBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
IdCardDesc = text;
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnEnterPressed += (textBox, text) =>
|
||||
{
|
||||
IdCardDesc = text;
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnDeselected += (textBox, keys) =>
|
||||
{
|
||||
IdCardDesc = textBox.Text;
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
};
|
||||
|
||||
var idCardTagsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("IDCardTags"), font: GUI.SmallFont);
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), idCardTagsText.RectTransform, Anchor.CenterRight), string.Join(", ", idCardTags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
OnEnterPressed = EnterIDCardTags,
|
||||
ToolTip = TextManager.Get("IDCardTagsTooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
|
||||
propertyBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
IdCardTags = text.Split(',');
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnEnterPressed += (textBox, text) =>
|
||||
{
|
||||
textBox.Text = string.Join(",", IdCardTags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnDeselected += (textBox, keys) =>
|
||||
{
|
||||
textBox.Text = string.Join(",", IdCardTags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
};
|
||||
|
||||
var jobsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform),
|
||||
TextManager.Get("SpawnpointJobs"), font: GUI.SmallFont)
|
||||
@@ -368,12 +360,26 @@ namespace Barotrauma
|
||||
propertyBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), tagsText.RectTransform, Anchor.CenterRight), string.Join(", ", tags))
|
||||
{
|
||||
MaxTextLength = 60,
|
||||
OnEnterPressed = EnterTags,
|
||||
ToolTip = TextManager.Get("spawnpointtagstooltip")
|
||||
};
|
||||
propertyBox.OnTextChanged += TextBoxChanged;
|
||||
propertyBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
tags = text.Split(',').ToList();
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnEnterPressed += (textBox, text) =>
|
||||
{
|
||||
textBox.Text = string.Join(",", tags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
return true;
|
||||
};
|
||||
propertyBox.OnDeselected += (textBox, keys) =>
|
||||
{
|
||||
textBox.Text = string.Join(",", tags);
|
||||
textBox.Flash(GUI.Style.Green);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -7,12 +8,13 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class BannedPlayer
|
||||
{
|
||||
public BannedPlayer(string name, UInt16 uniqueIdentifier, bool isRangeBan, string ip, ulong steamID)
|
||||
public BannedPlayer(string name, UInt16 uniqueIdentifier, bool isRangeBan, string endPoint, ulong steamID)
|
||||
{
|
||||
this.Name = name;
|
||||
this.EndPoint = endPoint;
|
||||
this.SteamID = steamID;
|
||||
ParseEndPointAsSteamId();
|
||||
this.IsRangeBan = isRangeBan;
|
||||
this.IP = ip;
|
||||
this.UniqueIdentifier = uniqueIdentifier;
|
||||
}
|
||||
}
|
||||
@@ -66,13 +68,13 @@ namespace Barotrauma.Networking
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
|
||||
string ip = bannedPlayer.IP;
|
||||
if (localRangeBans.Contains(bannedPlayer.UniqueIdentifier)) ip = ToRange(ip);
|
||||
string endPoint = bannedPlayer.EndPoint;
|
||||
if (localRangeBans.Contains(bannedPlayer.UniqueIdentifier)) endPoint = ToRange(endPoint);
|
||||
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), topArea.RectTransform),
|
||||
bannedPlayer.Name + " (" + ip + ")");
|
||||
bannedPlayer.Name + " (" + endPoint + ")");
|
||||
textBlock.RectTransform.MinSize = new Point(textBlock.Rect.Width, 0);
|
||||
|
||||
if (bannedPlayer.IP.IndexOf(".x") <= -1)
|
||||
if (bannedPlayer.EndPoint.IndexOf(".x") <= -1)
|
||||
{
|
||||
var rangeBanButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.4f), topArea.RectTransform),
|
||||
TextManager.Get("BanRange"), style: "GUIButtonSmall")
|
||||
@@ -156,19 +158,19 @@ namespace Barotrauma.Networking
|
||||
UInt16 uniqueIdentifier = incMsg.ReadUInt16();
|
||||
bool isRangeBan = incMsg.ReadBoolean(); incMsg.ReadPadBits();
|
||||
|
||||
string ip = "";
|
||||
string endPoint = "";
|
||||
UInt64 steamID = 0;
|
||||
if (isOwner)
|
||||
{
|
||||
ip = incMsg.ReadString();
|
||||
endPoint = incMsg.ReadString();
|
||||
steamID = incMsg.ReadUInt64();
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = "IP concealed by host";
|
||||
endPoint = "Endpoint concealed by host";
|
||||
steamID = 0;
|
||||
}
|
||||
bannedPlayers.Add(new BannedPlayer(name, uniqueIdentifier, isRangeBan, ip, steamID));
|
||||
bannedPlayers.Add(new BannedPlayer(name, uniqueIdentifier, isRangeBan, endPoint, steamID));
|
||||
}
|
||||
|
||||
if (banFrame != null)
|
||||
|
||||
@@ -520,11 +520,13 @@ namespace Barotrauma.Networking
|
||||
msgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(msgBox.Content.RectTransform.MinSize.Y / msgBox.Content.RectTransform.RelativeSize.Y));
|
||||
|
||||
var okButton = msgBox.Buttons[0];
|
||||
okButton.OnClicked += msgBox.Close;
|
||||
var cancelButton = msgBox.Buttons[1];
|
||||
cancelButton.OnClicked += msgBox.Close;
|
||||
|
||||
okButton.OnClicked += (GUIButton button, object obj) =>
|
||||
{
|
||||
clientPeer.SendPassword(passwordBox.Text);
|
||||
clientPeer?.SendPassword(passwordBox.Text);
|
||||
requiresPw = false;
|
||||
return true;
|
||||
};
|
||||
@@ -855,22 +857,6 @@ namespace Barotrauma.Networking
|
||||
traitorResults.Add(new TraitorMissionResult(inc));
|
||||
}
|
||||
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode mpCampaign)
|
||||
{
|
||||
if (inc.ReadBoolean())
|
||||
{
|
||||
Dictionary<string, int> clientUpgrades = UpgradeManager.GetMetadataLevels(mpCampaign.CampaignMetadata);
|
||||
Dictionary<string, int> serverUpgrades = new Dictionary<string, int>();
|
||||
|
||||
int length = inc.ReadUInt16();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
serverUpgrades.Add(inc.ReadString(), inc.ReadByte());
|
||||
}
|
||||
UpgradeManager.CompareUpgrades(clientUpgrades, serverUpgrades);
|
||||
}
|
||||
}
|
||||
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
CoroutineManager.StartCoroutine(EndGame(endMessage, traitorResults, transitionType), "EndGame");
|
||||
break;
|
||||
@@ -934,7 +920,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
private void ReadStartGameFinalize(IReadMessage inc)
|
||||
{
|
||||
TaskPool.ListTasks(null);
|
||||
TaskPool.ListTasks();
|
||||
ushort contentToPreloadCount = inc.ReadUInt16();
|
||||
List<ContentFile> contentToPreload = new List<ContentFile>();
|
||||
for (int i = 0; i < contentToPreloadCount; i++)
|
||||
@@ -1006,8 +992,19 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
|
||||
private void OnDisconnect()
|
||||
private void OnDisconnect(bool disableReconnect)
|
||||
{
|
||||
CoroutineManager.StopCoroutines("WaitForStartingInfo");
|
||||
reconnectBox?.Close();
|
||||
reconnectBox = null;
|
||||
|
||||
GameMain.Config.RestoreBackupPackages();
|
||||
|
||||
GUI.ClearCursorWait();
|
||||
|
||||
if (disableReconnect) { allowReconnect = false; }
|
||||
if (!this.allowReconnect) { CancelConnect(); }
|
||||
|
||||
if (SteamManager.IsInitialized)
|
||||
{
|
||||
Steamworks.SteamFriends.ClearRichPresence();
|
||||
@@ -1107,8 +1104,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
reconnectBox?.Close();
|
||||
reconnectBox = new GUIMessageBox(
|
||||
TextManager.Get("ConnectionLost"),
|
||||
msg, new string[0]);
|
||||
TextManager.Get("ConnectionLost"), msg,
|
||||
new string[] { TextManager.Get("Cancel") });
|
||||
reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
|
||||
connected = false;
|
||||
ConnectToServer(serverEndpoint, serverName);
|
||||
}
|
||||
@@ -1385,6 +1383,7 @@ namespace Barotrauma.Networking
|
||||
if (gameMode == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Game mode \"" + modeIdentifier + "\" not found!");
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
@@ -1415,11 +1414,13 @@ namespace Barotrauma.Networking
|
||||
int missionIndex = inc.ReadInt16();
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(subName, subHash, GameMain.NetLobbyScreen.SubList))
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
if (!GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox))
|
||||
{
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -1448,6 +1449,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
if (GameMain.NetLobbyScreen.SelectedShuttle == null ||
|
||||
@@ -1459,6 +1461,7 @@ namespace Barotrauma.Networking
|
||||
string errorMsg = "Failed to select shuttle \"" + shuttleName + "\" (hash: " + shuttleHash + ").";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
@@ -1487,6 +1490,7 @@ namespace Barotrauma.Networking
|
||||
gameStarted = true;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
else if (campaign.Map == null)
|
||||
@@ -1495,6 +1499,7 @@ namespace Barotrauma.Networking
|
||||
gameStarted = true;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
@@ -1515,6 +1520,11 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.Client?.ServerSettings?.Voting != null)
|
||||
{
|
||||
GameMain.Client.ServerSettings.Voting.ResetVotes(GameMain.Client.ConnectedClients);
|
||||
}
|
||||
|
||||
if (loadTask != null)
|
||||
{
|
||||
while (!loadTask.IsCompleted && !loadTask.IsFaulted && !loadTask.IsCanceled)
|
||||
@@ -1626,7 +1636,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (respawnAllowed) { respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null); }
|
||||
if (respawnAllowed)
|
||||
{
|
||||
respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle && gameMode != GameModePreset.MultiPlayerCampaign ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||
}
|
||||
|
||||
gameStarted = true;
|
||||
ServerSettings.ServerDetailsChanged = true;
|
||||
@@ -1645,6 +1658,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
public IEnumerable<object> EndGame(string endMessage, List<TraitorMissionResult> traitorResults = null, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
|
||||
{
|
||||
//round starting up, wait for it to finish
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 60);
|
||||
while (TaskPool.IsTaskRunning("AsyncCampaignStartRound"))
|
||||
{
|
||||
if (DateTime.Now > timeOut)
|
||||
{
|
||||
throw new Exception("Failed to end a round (async campaign round start timed out).");
|
||||
}
|
||||
yield return new WaitForSeconds(1.0f);
|
||||
}
|
||||
|
||||
if (!gameStarted)
|
||||
{
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
@@ -2086,7 +2110,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
while ((objHeader = (ServerNetObject)inc.ReadByte()) != ServerNetObject.END_OF_MESSAGE)
|
||||
{
|
||||
bool eventReadFailed = false;
|
||||
switch (objHeader)
|
||||
{
|
||||
case ServerNetObject.SYNC_IDS:
|
||||
@@ -2110,7 +2133,13 @@ namespace Barotrauma.Networking
|
||||
int msgEndPos = (int)(inc.BitPosition + msgLength * 8);
|
||||
|
||||
var entity = Entity.FindEntityByID(id) as IServerSerializable;
|
||||
if (entity != null)
|
||||
if (msgEndPos > inc.LengthBits)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error while reading a position update for the entity \"({entity?.ToString() ?? "null"})\". Message length exceeds the size of the buffer.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (entity != null && (entity is Item || entity is Character || entity is Submarine))
|
||||
{
|
||||
entity.ClientRead(objHeader.Value, inc, sendingTime);
|
||||
}
|
||||
@@ -2127,8 +2156,7 @@ namespace Barotrauma.Networking
|
||||
case ServerNetObject.ENTITY_EVENT_INITIAL:
|
||||
if (!entityEventManager.Read(objHeader.Value, inc, sendingTime, entities))
|
||||
{
|
||||
eventReadFailed = true;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ServerNetObject.CHAT_MESSAGE:
|
||||
@@ -2138,16 +2166,11 @@ namespace Barotrauma.Networking
|
||||
throw new Exception($"Unknown object header \"{objHeader}\"!)");
|
||||
}
|
||||
prevBitLength = inc.BitPosition - prevBitPos;
|
||||
prevByteLength = inc.BytePosition - prevByteLength;
|
||||
prevByteLength = inc.BytePosition - prevBytePos;
|
||||
|
||||
prevObjHeader = objHeader;
|
||||
prevBitPos = inc.BitPosition;
|
||||
prevBytePos = inc.BytePosition;
|
||||
|
||||
if (eventReadFailed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2618,7 +2641,7 @@ namespace Barotrauma.Networking
|
||||
public void VoteForKick(Client votedClient)
|
||||
{
|
||||
if (votedClient == null) { return; }
|
||||
votedClient.AddKickVote(ConnectedClients.First(c => c.ID == ID));
|
||||
votedClient.AddKickVote(ConnectedClients.FirstOrDefault(c => c.ID == myID));
|
||||
Vote(VoteType.Kick, votedClient);
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,19 @@ namespace Barotrauma.Networking
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
//16 = entity ID, 8 = msg length
|
||||
if (msg.BitPosition + 16 + 8 > msg.LengthBits)
|
||||
{
|
||||
string errorMsg = $"Error while reading a message from the server. Entity event data exceeds the size of the buffer (current position: {msg.BitPosition}, length: {msg.LengthBits}).";
|
||||
errorMsg += "\nPrevious entities:";
|
||||
for (int j = entities.Count - 1; j >= 0; j--)
|
||||
{
|
||||
errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString());
|
||||
}
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
|
||||
@@ -176,7 +189,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
entities.Add(null);
|
||||
if (thisEventID == (UInt16)(lastReceivedID + 1)) lastReceivedID++;
|
||||
if (thisEventID == (UInt16)(lastReceivedID + 1)) { lastReceivedID++; }
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -248,10 +261,8 @@ namespace Barotrauma.Networking
|
||||
errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString());
|
||||
}
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
|
||||
}
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
|
||||
|
||||
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
msg.BitPosition = (int)(msgPosition + msgLength * 8);
|
||||
|
||||
@@ -1,13 +1,56 @@
|
||||
using System;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Steam;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class ClientPeer
|
||||
{
|
||||
protected class ServerContentPackage
|
||||
{
|
||||
public string Name;
|
||||
public string Hash;
|
||||
public UInt64 WorkshopId;
|
||||
|
||||
public ContentPackage RegularPackage
|
||||
{
|
||||
get
|
||||
{
|
||||
return ContentPackage.RegularPackages.Find(p => p.MD5hash.Hash.Equals(Hash));
|
||||
}
|
||||
}
|
||||
|
||||
public ContentPackage CorePackage
|
||||
{
|
||||
get
|
||||
{
|
||||
return ContentPackage.CorePackages.Find(p => p.MD5hash.Hash.Equals(Hash));
|
||||
}
|
||||
}
|
||||
|
||||
public ServerContentPackage(string name, string hash, UInt64 workshopId)
|
||||
{
|
||||
Name = name;
|
||||
Hash = hash;
|
||||
WorkshopId = workshopId;
|
||||
}
|
||||
}
|
||||
|
||||
protected string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
protected string GetPackageStr(ServerContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + Md5Hash.GetShortHash(contentPackage.Hash) + ")";
|
||||
}
|
||||
|
||||
public delegate void MessageCallback(IReadMessage message);
|
||||
public delegate void DisconnectCallback();
|
||||
public delegate void DisconnectCallback(bool disableReconnect);
|
||||
public delegate void DisconnectMessageCallback(string message);
|
||||
public delegate void PasswordCallback(int salt, int retries);
|
||||
public delegate void InitializationCompleteCallback();
|
||||
@@ -25,11 +68,150 @@ namespace Barotrauma.Networking
|
||||
public NetworkConnection ServerConnection { get; protected set; }
|
||||
|
||||
public abstract void Start(object endPoint, int ownerKey);
|
||||
public abstract void Close(string msg = null);
|
||||
public abstract void Close(string msg = null, bool disableReconnect = false);
|
||||
public abstract void Update(float deltaTime);
|
||||
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod);
|
||||
public abstract void SendPassword(string password);
|
||||
|
||||
protected abstract void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg);
|
||||
|
||||
protected ConnectionInitialization initializationStep;
|
||||
protected bool contentPackageOrderReceived;
|
||||
protected int ownerKey = 0;
|
||||
protected int passwordSalt;
|
||||
protected Steamworks.AuthTicket steamAuthTicket;
|
||||
protected void ReadConnectionInitializationStep(IReadMessage inc)
|
||||
{
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
IWriteMessage outMsg;
|
||||
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(ownerKey);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
outMsg.Write((UInt16)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
}
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
outMsg.Write(GameMain.Config.Language);
|
||||
|
||||
SendMsgInternal(DeliveryMethod.Reliable, outMsg);
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
|
||||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
|
||||
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
|
||||
|
||||
string serverName = inc.ReadString();
|
||||
|
||||
UInt32 cpCount = inc.ReadVariableUInt32();
|
||||
ServerContentPackage corePackage = null;
|
||||
List<ServerContentPackage> regularPackages = new List<ServerContentPackage>();
|
||||
List<ServerContentPackage> missingPackages = new List<ServerContentPackage>();
|
||||
for (int i = 0; i < cpCount; i++)
|
||||
{
|
||||
string name = inc.ReadString();
|
||||
string hash = inc.ReadString();
|
||||
UInt64 workshopId = inc.ReadUInt64();
|
||||
var pkg = new ServerContentPackage(name, hash, workshopId);
|
||||
if (pkg.CorePackage != null)
|
||||
{
|
||||
corePackage = pkg;
|
||||
}
|
||||
else if (pkg.RegularPackage != null)
|
||||
{
|
||||
regularPackages.Add(pkg);
|
||||
}
|
||||
else
|
||||
{
|
||||
missingPackages.Add(pkg);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingPackages.Count > 0)
|
||||
{
|
||||
var nonDownloadable = missingPackages.Where(p => p.WorkshopId == 0);
|
||||
|
||||
if (nonDownloadable.Any())
|
||||
{
|
||||
string disconnectMsg;
|
||||
if (nonDownloadable.Count() == 1)
|
||||
{
|
||||
disconnectMsg = $"DisconnectMessage.MissingContentPackage~[missingcontentpackage]={GetPackageStr(missingPackages[0])}";
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
nonDownloadable.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
disconnectMsg = $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}";
|
||||
}
|
||||
Close(disconnectMsg, disableReconnect: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close(disableReconnect: true);
|
||||
|
||||
string missingModNames = "\n- " + string.Join("\n\n- ", missingPackages.Select(p => GetPackageStr(p))) + "\n\n";
|
||||
|
||||
var msgBox = new GUIMessageBox(
|
||||
TextManager.Get("WorkshopItemDownloadTitle"),
|
||||
TextManager.GetWithVariable("WorkshopItemDownloadPrompt", "[items]", missingModNames),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
|
||||
{
|
||||
GameMain.ServerListScreen.Select();
|
||||
GameMain.ServerListScreen.DownloadWorkshopItems(missingPackages.Select(p => p.WorkshopId), serverName, ServerConnection.EndPointString);
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!contentPackageOrderReceived)
|
||||
{
|
||||
GameMain.Config.SwapPackages(corePackage.CorePackage, regularPackages.Select(p => p.RegularPackage).ToList());
|
||||
contentPackageOrderReceived = true;
|
||||
}
|
||||
|
||||
SendMsgInternal(DeliveryMethod.Reliable, outMsg);
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public abstract void ForceTimeOut();
|
||||
#endif
|
||||
|
||||
@@ -14,11 +14,6 @@ namespace Barotrauma.Networking
|
||||
private NetClient netClient;
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private bool contentPackageOrderReceived;
|
||||
private int ownerKey;
|
||||
private int passwordSalt;
|
||||
private Steamworks.AuthTicket steamAuthTicket;
|
||||
List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
public LidgrenClientPeer(string name)
|
||||
@@ -128,7 +123,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
ReadConnectionInitializationStep(inc);
|
||||
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,99 +153,6 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
//Console.WriteLine(step + " " + initializationStep);
|
||||
NetOutgoingMessage outMsg; NetSendResult result;
|
||||
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(ownerKey);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
outMsg.Write((UInt16)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
}
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableInt32(mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send "+initializationStep.ToString()+" message to host: " + result);
|
||||
}
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
|
||||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
|
||||
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
|
||||
outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
|
||||
|
||||
Int32 cpCount = inc.ReadVariableInt32();
|
||||
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
|
||||
for (int i = 0; i < cpCount; i++)
|
||||
{
|
||||
string hash = inc.ReadString();
|
||||
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
|
||||
}
|
||||
|
||||
if (!contentPackageOrderReceived)
|
||||
{
|
||||
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
|
||||
serverContentPackages.IndexOf(cp) :
|
||||
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
|
||||
contentPackageOrderReceived = true;
|
||||
}
|
||||
|
||||
result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
|
||||
}
|
||||
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
@@ -269,7 +171,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
public override void Close(string msg = null, bool disableReconnect = false)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
@@ -278,7 +180,7 @@ namespace Barotrauma.Networking
|
||||
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
|
||||
netClient = null;
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
OnDisconnect?.Invoke();
|
||||
OnDisconnect?.Invoke(disableReconnect);
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
@@ -320,6 +222,18 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
{
|
||||
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
|
||||
lidgrenMsg.Write(msg.Buffer, 0, msg.LengthBytes);
|
||||
|
||||
NetSendResult result = netClient.SendMessage(lidgrenMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to host: " + result + "\n" + Environment.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
|
||||
@@ -12,10 +12,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
private bool isActive;
|
||||
private UInt64 hostSteamId;
|
||||
private ConnectionInitialization initializationStep;
|
||||
private bool contentPackageOrderReceived;
|
||||
private int passwordSalt;
|
||||
private Steamworks.AuthTicket steamAuthTicket;
|
||||
private double timeout;
|
||||
private double heartbeatTimer;
|
||||
private double connectionStatusTimer;
|
||||
@@ -89,6 +85,7 @@ namespace Barotrauma.Networking
|
||||
Steamworks.SteamNetworking.AcceptP2PSessionWithUser(steamId);
|
||||
}
|
||||
else if (initializationStep != ConnectionInitialization.Password &&
|
||||
initializationStep != ConnectionInitialization.ContentPackageOrder &&
|
||||
initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
DebugConsole.ThrowError($"Connection from incorrect SteamID was rejected: "+
|
||||
@@ -105,7 +102,7 @@ namespace Barotrauma.Networking
|
||||
OnDisconnectMessageReceived?.Invoke($"SteamP2P connection failed: {error}");
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
if (steamId != hostSteamId) { return; }
|
||||
@@ -165,6 +162,7 @@ namespace Barotrauma.Networking
|
||||
heartbeatTimer -= deltaTime;
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Password &&
|
||||
initializationStep != ConnectionInitialization.ContentPackageOrder &&
|
||||
initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
connectionStatusTimer -= deltaTime;
|
||||
@@ -194,7 +192,7 @@ namespace Barotrauma.Networking
|
||||
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
|
||||
if (packet.HasValue)
|
||||
{
|
||||
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0, 0);
|
||||
OnP2PData(packet?.SteamId ?? 0, packet?.Data, packet?.Data.Length ?? 0);
|
||||
receivedBytes += packet?.Data.Length ?? 0;
|
||||
}
|
||||
}
|
||||
@@ -249,88 +247,6 @@ namespace Barotrauma.Networking
|
||||
incomingDataMessages.Clear();
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(IReadMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
IWriteMessage outMsg;
|
||||
|
||||
//DebugConsole.NewMessage(step + " " + initializationStep);
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
sentBytes += outMsg.LengthBytes;
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion ||
|
||||
initializationStep == ConnectionInitialization.Password) { initializationStep = ConnectionInitialization.ContentPackageOrder; }
|
||||
if (initializationStep != ConnectionInitialization.ContentPackageOrder) { return; }
|
||||
outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ContentPackageOrder);
|
||||
|
||||
UInt32 cpCount = inc.ReadVariableUInt32();
|
||||
List<ContentPackage> serverContentPackages = new List<ContentPackage>();
|
||||
for (int i = 0; i < cpCount; i++)
|
||||
{
|
||||
string hash = inc.ReadString();
|
||||
serverContentPackages.Add(GameMain.Config.SelectedContentPackages.Find(cp => cp.MD5hash.Hash == hash));
|
||||
}
|
||||
|
||||
if (!contentPackageOrderReceived)
|
||||
{
|
||||
GameMain.Config.ReorderSelectedContentPackages(cp => serverContentPackages.Contains(cp) ?
|
||||
serverContentPackages.IndexOf(cp) :
|
||||
serverContentPackages.Count + GameMain.Config.SelectedContentPackages.IndexOf(cp));
|
||||
contentPackageOrderReceived = true;
|
||||
}
|
||||
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes, 0, Steamworks.P2PSend.Reliable);
|
||||
sentBytes += outMsg.LengthBytes;
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
@@ -339,8 +255,7 @@ namespace Barotrauma.Networking
|
||||
buf[0] = (byte)deliveryMethod;
|
||||
|
||||
byte[] bufAux = new byte[msg.LengthBytes];
|
||||
bool isCompressed; int length;
|
||||
msg.PrepareForSending(ref bufAux, out isCompressed, out length);
|
||||
msg.PrepareForSending(ref bufAux, out bool isCompressed, out int length);
|
||||
|
||||
buf[1] = (byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None);
|
||||
|
||||
@@ -426,7 +341,7 @@ namespace Barotrauma.Networking
|
||||
sentBytes += outMsg.LengthBytes;
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
public override void Close(string msg = null, bool disableReconnect = false)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
@@ -451,7 +366,7 @@ namespace Barotrauma.Networking
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
hostSteamId = 0;
|
||||
|
||||
OnDisconnect?.Invoke();
|
||||
OnDisconnect?.Invoke(disableReconnect);
|
||||
}
|
||||
|
||||
~SteamP2PClientPeer()
|
||||
@@ -460,6 +375,31 @@ namespace Barotrauma.Networking
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
{
|
||||
Steamworks.P2PSend sendType;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Reliable:
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
break;
|
||||
default:
|
||||
sendType = Steamworks.P2PSend.Unreliable;
|
||||
break;
|
||||
}
|
||||
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
msgToSend.Write((byte)deliveryMethod);
|
||||
msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
Steamworks.SteamNetworking.SendP2PPacket(hostSteamId, msgToSend.Buffer, msgToSend.LengthBytes, 0, sendType);
|
||||
sentBytes += msg.LengthBytes;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using Barotrauma.Steam;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Barotrauma.Steam;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
@@ -12,7 +10,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
private bool isActive;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private readonly UInt64 selfSteamID;
|
||||
|
||||
private long sentBytes, receivedBytes;
|
||||
@@ -61,7 +58,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
ServerConnection = new PipeConnection();
|
||||
ServerConnection = new PipeConnection(selfSteamID);
|
||||
ServerConnection.Status = NetworkConnectionStatus.Connected;
|
||||
|
||||
remotePeers = new List<RemotePeer>();
|
||||
@@ -161,6 +158,7 @@ namespace Barotrauma.Networking
|
||||
remotePeer.Authenticating = true;
|
||||
|
||||
authMsg.ReadString(); //skip name
|
||||
authMsg.ReadInt32(); //skip owner key
|
||||
authMsg.ReadUInt64(); //skip steamid
|
||||
UInt16 ticketLength = authMsg.ReadUInt16();
|
||||
byte[] ticket = authMsg.ReadBytes(ticketLength);
|
||||
@@ -395,7 +393,7 @@ namespace Barotrauma.Networking
|
||||
return; //owner doesn't send passwords
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
public override void Close(string msg = null, bool disableReconnect = false)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
@@ -415,7 +413,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
ChildServerRelay.ClosePipes();
|
||||
|
||||
OnDisconnect?.Invoke();
|
||||
OnDisconnect?.Invoke(disableReconnect);
|
||||
|
||||
SteamManager.LeaveLobby();
|
||||
Steamworks.SteamNetworking.ResetActions();
|
||||
@@ -445,6 +443,12 @@ namespace Barotrauma.Networking
|
||||
Close();
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
{
|
||||
//not currently used by SteamP2POwnerPeer
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
public override void ForceTimeOut()
|
||||
{
|
||||
|
||||
@@ -73,26 +73,25 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
private set;
|
||||
} = new List<string>();
|
||||
public List<string> ContentPackageWorkshopUrls
|
||||
public List<ulong> ContentPackageWorkshopIds
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<string>();
|
||||
} = new List<ulong>();
|
||||
|
||||
public bool ContentPackagesMatch(IEnumerable<ContentPackage> myContentPackages)
|
||||
public bool ContentPackagesMatch()
|
||||
{
|
||||
var myContentPackages = ContentPackage.AllPackages;
|
||||
//make sure we have all the packages the server requires
|
||||
foreach (string hash in ContentPackageHashes)
|
||||
if (ContentPackageHashes.Count != ContentPackageWorkshopIds.Count) { return false; }
|
||||
for (int i = 0; i < ContentPackageWorkshopIds.Count; i++)
|
||||
{
|
||||
if (!myContentPackages.Any(myPackage => myPackage.MD5hash.Hash == hash)) { return false; }
|
||||
}
|
||||
|
||||
//make sure the server isn't missing any of our packages that cause multiplayer incompatibility
|
||||
foreach (ContentPackage myPackage in myContentPackages)
|
||||
{
|
||||
if (myPackage.HasMultiplayerIncompatibleContent)
|
||||
string hash = ContentPackageHashes[i];
|
||||
UInt64 id = ContentPackageWorkshopIds[i];
|
||||
if (!myContentPackages.Any(myPackage => myPackage.MD5hash.Hash == hash))
|
||||
{
|
||||
if (!ContentPackageHashes.Any(hash => hash == myPackage.MD5hash.Hash)) { return false; }
|
||||
if (myContentPackages.Any(p => p.SteamWorkshopId == id)) { return false; }
|
||||
if (id == 0) { return false; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,19 +144,22 @@ namespace Barotrauma.Networking
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), previewContainer.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("ServerListVersion"), string.IsNullOrEmpty(GameVersion) ? TextManager.Get("Unknown") : GameVersion));
|
||||
|
||||
PlayStyle playStyle = PlayStyle ?? Networking.PlayStyle.Serious;
|
||||
bool hidePlaystyleBanner = previewContainer.Rect.Height < 380 || !PlayStyle.HasValue;
|
||||
if (!hidePlaystyleBanner)
|
||||
{
|
||||
PlayStyle playStyle = PlayStyle ?? Networking.PlayStyle.Serious;
|
||||
Sprite playStyleBannerSprite = ServerListScreen.PlayStyleBanners[(int)playStyle];
|
||||
float playStyleBannerAspectRatio = playStyleBannerSprite.SourceRect.Width / playStyleBannerSprite.SourceRect.Height;
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(previewContainer.Rect.Width, (int)(previewContainer.Rect.Width / playStyleBannerAspectRatio)), previewContainer.RectTransform),
|
||||
playStyleBannerSprite, null, true);
|
||||
|
||||
Sprite playStyleBannerSprite = ServerListScreen.PlayStyleBanners[(int)playStyle];
|
||||
float playStyleBannerAspectRatio = playStyleBannerSprite.SourceRect.Width / playStyleBannerSprite.SourceRect.Height;
|
||||
var playStyleBanner = new GUIImage(new RectTransform(new Point(previewContainer.Rect.Width, (int)(previewContainer.Rect.Width / playStyleBannerAspectRatio)), previewContainer.RectTransform),
|
||||
playStyleBannerSprite, null, true);
|
||||
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.01f, 0.06f) },
|
||||
TextManager.AddPunctuation(':', TextManager.Get("serverplaystyle"), TextManager.Get("servertag."+ playStyle)), textColor: Color.White,
|
||||
font: GUI.SmallFont, textAlignment: Alignment.Center,
|
||||
color: ServerListScreen.PlayStyleColors[(int)playStyle], style: "GUISlopedHeader");
|
||||
playStyleName.RectTransform.NonScaledSize = (playStyleName.Font.MeasureString(playStyleName.Text) + new Vector2(20, 5) * GUI.Scale).ToPoint();
|
||||
playStyleName.RectTransform.IsFixedSize = true;
|
||||
var playStyleName = new GUITextBlock(new RectTransform(new Vector2(0.15f, 0.0f), playStyleBanner.RectTransform) { RelativeOffset = new Vector2(0.01f, 0.06f) },
|
||||
TextManager.AddPunctuation(':', TextManager.Get("serverplaystyle"), TextManager.Get("servertag."+ playStyle)), textColor: Color.White,
|
||||
font: GUI.SmallFont, textAlignment: Alignment.Center,
|
||||
color: ServerListScreen.PlayStyleColors[(int)playStyle], style: "GUISlopedHeader");
|
||||
playStyleName.RectTransform.NonScaledSize = (playStyleName.Font.MeasureString(playStyleName.Text) + new Vector2(20, 5) * GUI.Scale).ToPoint();
|
||||
playStyleName.RectTransform.IsFixedSize = true;
|
||||
}
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.6f), previewContainer.RectTransform))
|
||||
{
|
||||
@@ -207,8 +209,13 @@ namespace Barotrauma.Networking
|
||||
TextManager.Get(string.IsNullOrEmpty(GameMode) ? "Unknown" : "GameMode." + GameMode, returnNull: true) ?? GameMode,
|
||||
textAlignment: Alignment.Right);
|
||||
|
||||
/*var traitors = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), bodyContainer.RectTransform), TextManager.Get("Traitors"));
|
||||
new GUITextBlock(new RectTransform(Vector2.One, traitors.RectTransform), TextManager.Get(!TraitorsEnabled.HasValue ? "Unknown" : TraitorsEnabled.Value.ToString()), textAlignment: Alignment.Right);*/
|
||||
GUITextBlock playStyleText = null;
|
||||
if (hidePlaystyleBanner && PlayStyle.HasValue)
|
||||
{
|
||||
PlayStyle playStyle = PlayStyle.Value;
|
||||
playStyleText = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), content.RectTransform), TextManager.Get("serverplaystyle"));
|
||||
new GUITextBlock(new RectTransform(Vector2.One, playStyleText.RectTransform), TextManager.Get("servertag." + playStyle), textAlignment: Alignment.Right);
|
||||
}
|
||||
|
||||
var subSelection = new GUITextBlock(new RectTransform(new Vector2(1.0f, elementHeight), content.RectTransform), TextManager.Get("ServerListSubSelection"));
|
||||
new GUITextBlock(new RectTransform(Vector2.One, subSelection.RectTransform), TextManager.Get(!SubSelectionMode.HasValue ? "Unknown" : SubSelectionMode.Value.ToString()), textAlignment: Alignment.Right);
|
||||
@@ -222,6 +229,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
gameMode.Font = subSelection.Font = modeSelection.Font = GUI.SmallFont;
|
||||
gameMode.GetChild<GUITextBlock>().Font = subSelection.GetChild<GUITextBlock>().Font = modeSelection.GetChild<GUITextBlock>().Font = GUI.SmallFont;
|
||||
if (playStyleText != null)
|
||||
{
|
||||
playStyleText.Font = playStyleText.GetChild<GUITextBlock>().Font = GUI.SmallFont;
|
||||
}
|
||||
}
|
||||
|
||||
var allowSpectating = new GUITickBox(new RectTransform(new Vector2(1, elementHeight), content.RectTransform), TextManager.Get("ServerListAllowSpectating"))
|
||||
@@ -279,7 +290,6 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> availableWorkshopUrls = new List<string>();
|
||||
for (int i = 0; i < ContentPackageNames.Count; i++)
|
||||
{
|
||||
var packageText = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.15f), contentPackageList.Content.RectTransform) { MinSize = new Point(0, 15) },
|
||||
@@ -289,22 +299,15 @@ namespace Barotrauma.Networking
|
||||
};
|
||||
if (i < ContentPackageHashes.Count)
|
||||
{
|
||||
if (GameMain.Config.SelectedContentPackages.Any(cp => cp.MD5hash.Hash == ContentPackageHashes[i]))
|
||||
if (ContentPackage.AllPackages.Any(cp => cp.MD5hash.Hash == ContentPackageHashes[i]))
|
||||
{
|
||||
packageText.Selected = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
//matching content package found, but it hasn't been enabled
|
||||
if (ContentPackage.List.Any(cp => cp.MD5hash.Hash == ContentPackageHashes[i]))
|
||||
{
|
||||
packageText.TextColor = GUI.Style.Orange;
|
||||
packageText.ToolTip = TextManager.GetWithVariable("ServerListContentPackageNotEnabled", "[contentpackage]", ContentPackageNames[i]);
|
||||
}
|
||||
//workshop download link found
|
||||
else if (i < ContentPackageWorkshopUrls.Count && !string.IsNullOrEmpty(ContentPackageWorkshopUrls[i]))
|
||||
if (i < ContentPackageWorkshopIds.Count && ContentPackageWorkshopIds[i] != 0)
|
||||
{
|
||||
availableWorkshopUrls.Add(ContentPackageWorkshopUrls[i]);
|
||||
packageText.TextColor = Color.Yellow;
|
||||
packageText.ToolTip = TextManager.GetWithVariable("ServerListIncompatibleContentPackageWorkshopAvailable", "[contentpackage]", ContentPackageNames[i]);
|
||||
}
|
||||
@@ -316,21 +319,6 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
}
|
||||
if (availableWorkshopUrls.Count > 0)
|
||||
{
|
||||
var workshopBtn = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), content.RectTransform), TextManager.Get("ServerListSubscribeMissingPackages"))
|
||||
{
|
||||
ToolTip = TextManager.Get(SteamManager.IsInitialized ? "ServerListSubscribeMissingPackagesTooltip" : "ServerListSubscribeMissingPackagesTooltipNoSteam"),
|
||||
Enabled = SteamManager.IsInitialized,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
GameMain.SteamWorkshopScreen.SubscribeToPackages(availableWorkshopUrls);
|
||||
GameMain.SteamWorkshopScreen.Select();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
workshopBtn.TextBlock.AutoScaleHorizontal = true;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -391,7 +379,7 @@ namespace Barotrauma.Networking
|
||||
if (bool.TryParse(element.GetAttributeString("UsingWhiteList", ""), out bool whitelistTemp)) { info.UsingWhiteList = whitelistTemp; }
|
||||
if (Enum.TryParse(element.GetAttributeString("TraitorsEnabled", ""), out YesNoMaybe traitorsTemp)) { info.TraitorsEnabled = traitorsTemp; }
|
||||
if (Enum.TryParse(element.GetAttributeString("SubSelectionMode", ""), out SelectionMode subSelectionTemp)) { info.SubSelectionMode = subSelectionTemp; }
|
||||
if (Enum.TryParse(element.GetAttributeString("ModeSelectionMode", ""), out SelectionMode modeSelectionTemp)) { info.ModeSelectionMode = subSelectionTemp; }
|
||||
if (Enum.TryParse(element.GetAttributeString("ModeSelectionMode", ""), out SelectionMode modeSelectionTemp)) { info.ModeSelectionMode = modeSelectionTemp; }
|
||||
if (bool.TryParse(element.GetAttributeString("VoipEnabled", ""), out bool voipTemp)) { info.VoipEnabled = voipTemp; }
|
||||
if (bool.TryParse(element.GetAttributeString("KarmaEnabled", ""), out bool karmaTemp)) { info.KarmaEnabled = karmaTemp; }
|
||||
if (bool.TryParse(element.GetAttributeString("FriendlyFireEnabled", ""), out bool friendlyFireTemp)) { info.FriendlyFireEnabled = friendlyFireTemp; }
|
||||
|
||||
@@ -477,10 +477,6 @@ namespace Barotrauma.Networking
|
||||
GUITextBlock.AutoScaleAndNormalize(playStyleTickBoxes.Select(t => t.TextBlock));
|
||||
playstyleList.RectTransform.MinSize = new Point(0, (int)(playstyleList.Content.Children.First().Rect.Height * 2.0f + playstyleList.Padding.Y + playstyleList.Padding.W));
|
||||
|
||||
var endBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
|
||||
TextManager.Get("ServerSettingsEndRoundWhenDestReached"));
|
||||
GetPropertyData("EndRoundAtLevelEnd").AssignGUIComponent(endBox);
|
||||
|
||||
var endVoteBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
|
||||
TextManager.Get("ServerSettingsEndRoundVoting"));
|
||||
GetPropertyData("AllowEndVoting").AssignGUIComponent(endVoteBox);
|
||||
@@ -569,6 +565,8 @@ namespace Barotrauma.Networking
|
||||
};
|
||||
slider.OnMoved(slider, slider.BarScroll);
|
||||
|
||||
var traitorsMinPlayerCount = CreateLabeledNumberInput(roundsTab, "ServerSettingsTraitorsMinPlayerCount", 1, 16, "ServerSettingsTraitorsMinPlayerCountToolTip");
|
||||
GetPropertyData("TraitorsMinPlayerCount").AssignGUIComponent(traitorsMinPlayerCount);
|
||||
|
||||
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
|
||||
@@ -576,53 +574,6 @@ namespace Barotrauma.Networking
|
||||
var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
|
||||
GetPropertyData("DisableBotConversations").AssignGUIComponent(disableBotConversationsBox);
|
||||
|
||||
/*var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||
|
||||
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||
var traitorRatioSlider = slider;
|
||||
traitorRatioBox.OnSelected = (GUITickBox) =>
|
||||
{
|
||||
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (TraitorUseRatio)
|
||||
{
|
||||
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
traitorRatioSlider.Range = new Vector2(1.0f, maxPlayers);
|
||||
}
|
||||
|
||||
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio") + " ";
|
||||
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount") + " ";
|
||||
|
||||
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
|
||||
traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
{
|
||||
GUITextBlock traitorText = scrollBar.UserData as GUITextBlock;
|
||||
if (traitorRatioBox.Selected)
|
||||
{
|
||||
scrollBar.Step = 0.01f;
|
||||
scrollBar.Range = new Vector2(0.1f, 1.0f);
|
||||
traitorText.Text = traitorRatioLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 1.0f) + " %";
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollBar.Step = 1f / (maxPlayers - 1);
|
||||
scrollBar.Range = new Vector2(1.0f, maxPlayers);
|
||||
traitorText.Text = traitorCountLabel + scrollBar.BarScrollValue;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
GetPropertyData("TraitorUseRatio").AssignGUIComponent(traitorRatioBox);
|
||||
GetPropertyData("TraitorRatio").AssignGUIComponent(traitorRatioSlider);
|
||||
|
||||
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
|
||||
traitorRatioBox.OnSelected(traitorRatioBox);*/
|
||||
|
||||
var buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), roundsTab.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
@@ -919,7 +870,7 @@ namespace Barotrauma.Networking
|
||||
slider.UserData = label;
|
||||
}
|
||||
|
||||
private GUINumberInput CreateLabeledNumberInput(GUIComponent parent, string labelTag, int min, int max)
|
||||
private GUINumberInput CreateLabeledNumberInput(GUIComponent parent, string labelTag, int min, int max, string toolTipTag = null)
|
||||
{
|
||||
var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -928,11 +879,15 @@ namespace Barotrauma.Networking
|
||||
ToolTip = TextManager.Get(labelTag)
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), container.RectTransform),
|
||||
var label = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), container.RectTransform),
|
||||
TextManager.Get(labelTag), textAlignment: Alignment.CenterLeft, font: GUI.SmallFont)
|
||||
{
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
if (!string.IsNullOrEmpty(toolTipTag))
|
||||
{
|
||||
label.ToolTip = TextManager.Get(toolTipTag);
|
||||
}
|
||||
var input = new GUINumberInput(new RectTransform(new Vector2(0.3f, 1.0f), container.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = min,
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Networking;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using RestSharp.Contrib;
|
||||
using System.Xml.Linq;
|
||||
using Color = Microsoft.Xna.Framework.Color;
|
||||
using System.Runtime.InteropServices;
|
||||
using NLog.Fluent;
|
||||
|
||||
namespace Barotrauma.Steam
|
||||
{
|
||||
static partial class SteamManager
|
||||
{
|
||||
private static Dictionary<Steamworks.Data.PublishedFileId, Task> modCopiesInProgress = new Dictionary<Steamworks.Data.PublishedFileId, Task>();
|
||||
private static readonly Dictionary<Steamworks.Data.PublishedFileId, Task> modCopiesInProgress = new Dictionary<Steamworks.Data.PublishedFileId, Task>();
|
||||
|
||||
private static void InitializeProjectSpecific()
|
||||
{
|
||||
@@ -49,6 +45,9 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if !DEBUG
|
||||
DebugConsole.ThrowError("SteamManager initialization threw an exception", e);
|
||||
#endif
|
||||
isInitialized = false;
|
||||
initializationErrors.Add("SteamClientInitFailed");
|
||||
}
|
||||
@@ -85,28 +84,6 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void UpdateProjectSpecific(float deltaTime)
|
||||
{
|
||||
if (ugcSubscriptionTasks != null)
|
||||
{
|
||||
var ugcSubscriptionKeys = ugcSubscriptionTasks.Keys.ToList();
|
||||
foreach (var key in ugcSubscriptionKeys)
|
||||
{
|
||||
var task = ugcSubscriptionTasks[key];
|
||||
|
||||
if (task.IsCompleted)
|
||||
{
|
||||
if (!task.IsCompletedSuccessfully)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to subscribe to a Steam Workshop item with id " + key.ToString() + ": TaskStatus = " + task.Status.ToString());
|
||||
}
|
||||
ugcSubscriptionTasks.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task InitRelayNetworkAccess()
|
||||
{
|
||||
if (!IsInitialized) { return; }
|
||||
@@ -209,13 +186,13 @@ namespace Barotrauma.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
var contentPackages = GameMain.Config.SelectedContentPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
var contentPackages = GameMain.Config.AllEnabledPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
|
||||
currentLobby?.SetData("name", serverSettings.ServerName);
|
||||
currentLobby?.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count ?? 0).ToString());
|
||||
currentLobby?.SetData("maxplayernum", serverSettings.MaxPlayers.ToString());
|
||||
//currentLobby?.SetData("hostipaddress", lobbyIP);
|
||||
string pingLocation = Steamworks.SteamNetworkingUtils.LocalPingLocation.ToString();
|
||||
string pingLocation = Steamworks.SteamNetworkingUtils.LocalPingLocation?.ToString();
|
||||
currentLobby?.SetData("pinglocation", pingLocation ?? "");
|
||||
currentLobby?.SetData("lobbyowner", SteamIDUInt64ToString(GetSteamID()));
|
||||
currentLobby?.SetData("haspassword", serverSettings.HasPassword.ToString());
|
||||
@@ -225,7 +202,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
currentLobby?.SetData("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
|
||||
currentLobby?.SetData("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash)));
|
||||
currentLobby?.SetData("contentpackageurl", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
|
||||
currentLobby?.SetData("contentpackageid", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopId)));
|
||||
currentLobby?.SetData("usingwhitelist", (serverSettings.Whitelist != null && serverSettings.Whitelist.Enabled).ToString());
|
||||
currentLobby?.SetData("modeselectionmode", serverSettings.ModeSelectionMode.ToString());
|
||||
currentLobby?.SetData("subselectionmode", serverSettings.SubSelectionMode.ToString());
|
||||
@@ -280,9 +257,8 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
if (!isInitialized) { return false; }
|
||||
|
||||
|
||||
int doneTasks = 0;
|
||||
Action taskDone = () =>
|
||||
void taskDone()
|
||||
{
|
||||
doneTasks++;
|
||||
if (doneTasks >= 2)
|
||||
@@ -290,52 +266,64 @@ namespace Barotrauma.Steam
|
||||
serverQueryFinished?.Invoke();
|
||||
serverQueryFinished = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//TODO: find a better strategy to fetch all lobbies, this is gonna take forever if we actually have 10000 lobbies
|
||||
Steamworks.Data.LobbyQuery lobbyQuery = Steamworks.SteamMatchmaking.CreateLobbyQuery().FilterDistanceWorldwide().WithMaxResults(10000);
|
||||
|
||||
Steamworks.Dispatch.OnDebugCallback = (callbackType, contents, isServer) =>
|
||||
{
|
||||
DebugConsole.NewMessage($"{callbackType}: " + contents, Color.Yellow);
|
||||
};
|
||||
TaskPool.Add("LobbyQueryRequest", lobbyQuery.RequestAsync(),
|
||||
(t) =>
|
||||
{
|
||||
var lobbies = ((Task<Steamworks.Data.Lobby[]>)t).Result;
|
||||
foreach (var lobby in lobbies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(lobby.GetData("name"))) { continue; }
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo();
|
||||
serverInfo.ServerName = lobby.GetData("name");
|
||||
serverInfo.OwnerID = SteamIDStringToUInt64(lobby.GetData("lobbyowner"));
|
||||
serverInfo.LobbyID = lobby.Id;
|
||||
bool.TryParse(lobby.GetData("haspassword"), out serverInfo.HasPassword);
|
||||
serverInfo.PlayerCount = int.TryParse(lobby.GetData("playercount"), out int playerCount) ? playerCount : 0;
|
||||
serverInfo.MaxPlayers = int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers) ? maxPlayers : 1;
|
||||
serverInfo.RespondedToSteamQuery = true;
|
||||
|
||||
AssignLobbyDataToServerInfo(lobby, serverInfo);
|
||||
|
||||
addToServerList(serverInfo);
|
||||
}
|
||||
taskDone();
|
||||
Steamworks.Dispatch.OnDebugCallback = null;
|
||||
if (t.Status == TaskStatus.Faulted)
|
||||
{
|
||||
TaskPool.PrintTaskExceptions(t, "Failed to retrieve SteamP2P lobbies");
|
||||
taskDone();
|
||||
return;
|
||||
}
|
||||
var lobbies = ((Task<Steamworks.Data.Lobby[]>)t).Result;
|
||||
if (lobbies != null)
|
||||
{
|
||||
foreach (var lobby in lobbies)
|
||||
{
|
||||
if (string.IsNullOrEmpty(lobby.GetData("name"))) { continue; }
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo();
|
||||
serverInfo.ServerName = lobby.GetData("name");
|
||||
serverInfo.OwnerID = SteamIDStringToUInt64(lobby.GetData("lobbyowner"));
|
||||
serverInfo.LobbyID = lobby.Id;
|
||||
bool.TryParse(lobby.GetData("haspassword"), out serverInfo.HasPassword);
|
||||
serverInfo.PlayerCount = int.TryParse(lobby.GetData("playercount"), out int playerCount) ? playerCount : 0;
|
||||
serverInfo.MaxPlayers = int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers) ? maxPlayers : 1;
|
||||
serverInfo.RespondedToSteamQuery = true;
|
||||
|
||||
AssignLobbyDataToServerInfo(lobby, serverInfo);
|
||||
|
||||
addToServerList(serverInfo);
|
||||
}
|
||||
}
|
||||
taskDone();
|
||||
});
|
||||
|
||||
Steamworks.ServerList.Internet serverQuery = new Steamworks.ServerList.Internet();
|
||||
Action<Steamworks.Data.ServerInfo, bool> onServer = (Steamworks.Data.ServerInfo info, bool responsive) =>
|
||||
void onServer(Steamworks.Data.ServerInfo info, bool responsive)
|
||||
{
|
||||
if (string.IsNullOrEmpty(info.Name)) { return; }
|
||||
|
||||
ServerInfo serverInfo = new ServerInfo();
|
||||
serverInfo.ServerName = info.Name;
|
||||
serverInfo.IP = info.Address.ToString();
|
||||
serverInfo.Port = info.ConnectionPort.ToString();
|
||||
serverInfo.PlayerCount = info.Players;
|
||||
serverInfo.MaxPlayers = info.MaxPlayers;
|
||||
serverInfo.RespondedToSteamQuery = responsive;
|
||||
ServerInfo serverInfo = new ServerInfo
|
||||
{
|
||||
ServerName = info.Name,
|
||||
HasPassword = info.Passworded,
|
||||
IP = info.Address.ToString(),
|
||||
Port = info.ConnectionPort.ToString(),
|
||||
PlayerCount = info.Players,
|
||||
MaxPlayers = info.MaxPlayers,
|
||||
RespondedToSteamQuery = responsive
|
||||
};
|
||||
|
||||
if (responsive)
|
||||
{
|
||||
@@ -344,11 +332,11 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
if (t.Status == TaskStatus.Faulted)
|
||||
{
|
||||
TaskPool.PrintTaskExceptions(t, "Failed to retrieve rules for "+info.Name);
|
||||
TaskPool.PrintTaskExceptions(t, "Failed to retrieve rules for " + info.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
var rules = ((Task<Dictionary<string,string>>)t).Result;
|
||||
var rules = ((Task<Dictionary<string, string>>)t).Result;
|
||||
AssignServerRulesToServerInfo(rules, serverInfo);
|
||||
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
@@ -365,7 +353,7 @@ namespace Barotrauma.Steam
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
serverQuery.OnResponsiveServer += (info) => onServer(info, true);
|
||||
serverQuery.OnUnresponsiveServer += (info) => onServer(info, false);
|
||||
|
||||
@@ -393,11 +381,20 @@ namespace Barotrauma.Steam
|
||||
|
||||
serverInfo.ContentPackageNames.AddRange(lobby.GetData("contentpackage").Split(','));
|
||||
serverInfo.ContentPackageHashes.AddRange(lobby.GetData("contentpackagehash").Split(','));
|
||||
serverInfo.ContentPackageWorkshopUrls.AddRange(lobby.GetData("contentpackageurl").Split(','));
|
||||
|
||||
string workshopIdData = lobby.GetData("contentpackageid");
|
||||
if (!string.IsNullOrEmpty(workshopIdData))
|
||||
{
|
||||
serverInfo.ContentPackageWorkshopIds.AddRange(ParseWorkshopIds(workshopIdData));
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] workshopUrls = lobby.GetData("contentpackageurl").Split(',');
|
||||
serverInfo.ContentPackageWorkshopIds.AddRange(WorkshopUrlsToIds(workshopUrls));
|
||||
}
|
||||
|
||||
serverInfo.UsingWhiteList = getLobbyBool("usingwhitelist");
|
||||
SelectionMode selectionMode;
|
||||
if (Enum.TryParse(lobby.GetData("modeselectionmode"), out selectionMode)) { serverInfo.ModeSelectionMode = selectionMode; }
|
||||
if (Enum.TryParse(lobby.GetData("modeselectionmode"), out SelectionMode selectionMode)) { serverInfo.ModeSelectionMode = selectionMode; }
|
||||
if (Enum.TryParse(lobby.GetData("subselectionmode"), out selectionMode)) { serverInfo.SubSelectionMode = selectionMode; }
|
||||
|
||||
serverInfo.AllowSpectating = getLobbyBool("allowspectating");
|
||||
@@ -412,11 +409,12 @@ namespace Barotrauma.Steam
|
||||
if (Enum.TryParse(lobby.GetData("playstyle"), out PlayStyle playStyle)) serverInfo.PlayStyle = playStyle;
|
||||
|
||||
if (serverInfo.ContentPackageNames.Count != serverInfo.ContentPackageHashes.Count ||
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopUrls.Count)
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopIds.Count)
|
||||
{
|
||||
//invalid contentpackage info
|
||||
serverInfo.ContentPackageNames.Clear();
|
||||
serverInfo.ContentPackageHashes.Clear();
|
||||
serverInfo.ContentPackageWorkshopIds.Clear();
|
||||
}
|
||||
|
||||
string pingLocation = lobby.GetData("pinglocation");
|
||||
@@ -449,10 +447,18 @@ namespace Barotrauma.Steam
|
||||
|
||||
serverInfo.ContentPackageNames.Clear();
|
||||
serverInfo.ContentPackageHashes.Clear();
|
||||
serverInfo.ContentPackageWorkshopUrls.Clear();
|
||||
serverInfo.ContentPackageWorkshopIds.Clear();
|
||||
if (rules.ContainsKey("contentpackage")) serverInfo.ContentPackageNames.AddRange(rules["contentpackage"].Split(','));
|
||||
if (rules.ContainsKey("contentpackagehash")) serverInfo.ContentPackageHashes.AddRange(rules["contentpackagehash"].Split(','));
|
||||
if (rules.ContainsKey("contentpackageurl")) serverInfo.ContentPackageWorkshopUrls.AddRange(rules["contentpackageurl"].Split(','));
|
||||
if (rules.ContainsKey("contentpackageid"))
|
||||
{
|
||||
serverInfo.ContentPackageWorkshopIds.AddRange(ParseWorkshopIds(rules["contentpackageid"]));
|
||||
}
|
||||
else if (rules.ContainsKey("contentpackageurl"))
|
||||
{
|
||||
string[] workshopUrls = rules["contentpackageurl"].Split(',');
|
||||
serverInfo.ContentPackageWorkshopIds.AddRange(WorkshopUrlsToIds(workshopUrls));
|
||||
}
|
||||
|
||||
if (rules.ContainsKey("usingwhitelist")) serverInfo.UsingWhiteList = rules["usingwhitelist"] == "True";
|
||||
if (rules.ContainsKey("modeselectionmode"))
|
||||
@@ -479,37 +485,16 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
if (serverInfo.ContentPackageNames.Count != serverInfo.ContentPackageHashes.Count ||
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopUrls.Count)
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopIds.Count)
|
||||
{
|
||||
//invalid contentpackage info
|
||||
serverInfo.ContentPackageNames.Clear();
|
||||
serverInfo.ContentPackageHashes.Clear();
|
||||
serverInfo.ContentPackageWorkshopIds.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static ulong GetWorkshopItemIDFromUrl(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
Uri uri = new Uri(url);
|
||||
string idStr = HttpUtility.ParseQueryString(uri.Query).Get("id");
|
||||
if (ulong.TryParse(idStr, out ulong id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to get Workshop item ID from the url \"" + url + "\"!", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#region Connecting to servers
|
||||
|
||||
//TODO: reimplement server list queries
|
||||
|
||||
#region Connecting to servers
|
||||
private static Steamworks.AuthTicket currentTicket = null;
|
||||
public static Steamworks.AuthTicket GetAuthSessionTicket()
|
||||
{
|
||||
@@ -545,9 +530,9 @@ namespace Barotrauma.Steam
|
||||
Steamworks.SteamUser.EndAuthSession(clientSteamID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Workshop
|
||||
#region Workshop
|
||||
|
||||
public const string WorkshopItemPreviewImageFolder = "Workshop";
|
||||
public const string PreviewImageName = "PreviewImage.png";
|
||||
@@ -620,7 +605,8 @@ namespace Barotrauma.Steam
|
||||
.WithLongDescription();
|
||||
if (requireTags != null) query.WithTags(requireTags);
|
||||
|
||||
TaskPool.Add("GetPopularWorkshopItems", GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) => {
|
||||
TaskPool.Add("GetPopularWorkshopItems", GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) =>
|
||||
{
|
||||
var entries = ((Task<List<Steamworks.Ugc.Item>>)task).Result;
|
||||
|
||||
//count the number of each unique tag
|
||||
@@ -669,47 +655,82 @@ namespace Barotrauma.Steam
|
||||
TaskPool.Add("GetPublishedWorkshopItems", GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(((Task<List<Steamworks.Ugc.Item>>)task).Result); });
|
||||
}
|
||||
|
||||
private static Dictionary<ulong, Task> ugcSubscriptionTasks;
|
||||
private static readonly HashSet<ulong> pendingWorkshopSubscriptions = new HashSet<ulong>();
|
||||
|
||||
public static void SubscribeToWorkshopItem(string itemUrl)
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
ulong id = GetWorkshopItemIDFromUrl(itemUrl);
|
||||
|
||||
SubscribeToWorkshopItem(id);
|
||||
}
|
||||
|
||||
public static void SubscribeToWorkshopItem(ulong id)
|
||||
public static void SubscribeToWorkshopItem(ulong id, Action onInstalled = null)
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
if (id == 0) { return; }
|
||||
|
||||
if (ugcSubscriptionTasks?.ContainsKey(id) ?? false) { return; }
|
||||
if (pendingWorkshopSubscriptions.Contains(id)) { return; }
|
||||
|
||||
ugcSubscriptionTasks ??= new Dictionary<ulong, Task>();
|
||||
ugcSubscriptionTasks.Add(id, Task.Run(async () =>
|
||||
{
|
||||
Steamworks.Ugc.Item? item = await Steamworks.SteamUGC.QueryFileAsync(id);
|
||||
pendingWorkshopSubscriptions.Add(id);
|
||||
TaskPool.Add(
|
||||
$"SubscribeToWorkshopItem({id})",
|
||||
Task.Run(async () =>
|
||||
{
|
||||
Steamworks.Ugc.Item? item = await Steamworks.SteamUGC.QueryFileAsync(id);
|
||||
|
||||
if (!item.HasValue)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to find a Steam Workshop item with the ID " + id.ToString() + ".");
|
||||
return;
|
||||
}
|
||||
if (!item.HasValue)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to find a Steam Workshop item with the ID {id}.");
|
||||
return null;
|
||||
}
|
||||
|
||||
bool subscribed = await item?.Subscribe();
|
||||
if (!subscribed)
|
||||
if (!(item?.IsSubscribed ?? false))
|
||||
{
|
||||
bool subscribed = await item?.Subscribe();
|
||||
if (!subscribed)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to subscribe to Steam Workshop item with the ID {id}.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}),
|
||||
(t) =>
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to subscribe to Steam Workshop item with the ID " + id.ToString() + ".");
|
||||
}
|
||||
bool downloading = item?.Download() ?? false;
|
||||
if (!downloading)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to start downloading Steam Workshop item with the ID " + id.ToString() + ".");
|
||||
}
|
||||
}));
|
||||
bool shouldCleanup = true;
|
||||
if (t.IsFaulted)
|
||||
{
|
||||
TaskPool.PrintTaskExceptions(t, $"Workshop subscription task {id} faulted");
|
||||
}
|
||||
else
|
||||
{
|
||||
var item = ((Task<Steamworks.Ugc.Item?>)t).Result;
|
||||
if (item != null)
|
||||
{
|
||||
if (item?.IsInstalled ?? false)
|
||||
{
|
||||
onInstalled?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
void _onInstalled()
|
||||
{
|
||||
onInstalled?.Invoke();
|
||||
pendingWorkshopSubscriptions.Remove(id);
|
||||
}
|
||||
bool downloading = item?.Download(_onInstalled) ?? false;
|
||||
if (!downloading)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to start downloading Steam Workshop item with the ID {id}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldCleanup = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldCleanup)
|
||||
{
|
||||
pendingWorkshopSubscriptions.Remove(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void CreateWorkshopItemStaging(ContentPackage contentPackage, out Steamworks.Ugc.Editor? itemEditor)
|
||||
@@ -790,9 +811,9 @@ namespace Barotrauma.Steam
|
||||
itemEditor = itemEditor?.WithPrivateVisibility();
|
||||
}
|
||||
|
||||
if (!CheckWorkshopItemEnabled(existingItem))
|
||||
if (!CheckWorkshopItemInstalled(existingItem))
|
||||
{
|
||||
if (!EnableWorkShopItem(existingItem, out string errorMsg))
|
||||
if (!InstallWorkshopItem(existingItem, out string errorMsg))
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
new GUIMessageBox(
|
||||
@@ -804,9 +825,9 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem?.Directory, MetadataFileName)) { SteamWorkshopUrl = existingItem.Value.Url };
|
||||
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem?.Directory, MetadataFileName)) { SteamWorkshopId = existingItem.Value.Id };
|
||||
string installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage));
|
||||
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
|
||||
contentPackage = ContentPackage.AllPackages.FirstOrDefault(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
|
||||
|
||||
itemEditor = itemEditor?.WithContent(Path.GetDirectoryName(installedContentPackagePath));
|
||||
|
||||
@@ -923,7 +944,7 @@ namespace Barotrauma.Steam
|
||||
workshopPublishStatus.Result = task.Result;
|
||||
DebugConsole.NewMessage("Published workshop item " + item?.Title + " successfully.", Microsoft.Xna.Framework.Color.LightGreen);
|
||||
|
||||
contentPackage.SteamWorkshopUrl = $"http://steamcommunity.com/sharedfiles/filedetails/?source=Facepunch.Steamworks&id={task.Result.FileId.Value}";
|
||||
contentPackage.SteamWorkshopId = task.Result.FileId.Value;
|
||||
//NOTE: This sets InstallTime one hour into the future to guarantee
|
||||
//that the published content package won't be autoupdated incorrectly.
|
||||
//Change if it causes issues.
|
||||
@@ -937,9 +958,9 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables a workshop item by moving it to the game folder.
|
||||
/// Installs a workshop item by moving it to the game folder.
|
||||
/// </summary>
|
||||
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
|
||||
public static bool InstallWorkshopItem(Steamworks.Ugc.Item? item, out string errorMsg, bool enableContentPackage = false, bool suppressInstallNotif = false)
|
||||
{
|
||||
if (!(item?.IsInstalled ?? false))
|
||||
{
|
||||
@@ -959,11 +980,11 @@ namespace Barotrauma.Steam
|
||||
|
||||
ContentPackage contentPackage = new ContentPackage(metaDataFilePath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url
|
||||
SteamWorkshopId = item?.Id ?? 0
|
||||
};
|
||||
string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);
|
||||
|
||||
List<ContentPackage> existingPackages = ContentPackage.List.Where(cp => cp.Path.CleanUpPath() == newContentPackagePath.CleanUpPath()).ToList();
|
||||
List<ContentPackage> existingPackages = ContentPackage.AllPackages.Where(cp => cp.Path.CleanUpPath() == newContentPackagePath.CleanUpPath()).ToList();
|
||||
if (existingPackages.Any())
|
||||
{
|
||||
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
|
||||
@@ -975,7 +996,7 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl,
|
||||
RemoveMods(cp => cp.SteamWorkshopId != 0 && cp.SteamWorkshopId == contentPackage.SteamWorkshopId,
|
||||
false);
|
||||
}
|
||||
}
|
||||
@@ -1024,7 +1045,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url,
|
||||
SteamWorkshopId = item?.Id ?? 0,
|
||||
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
|
||||
};
|
||||
|
||||
@@ -1045,17 +1066,17 @@ namespace Barotrauma.Steam
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
ContentPackage.AddPackage(newPackage);
|
||||
|
||||
if (selectContentPackage)
|
||||
if (enableContentPackage)
|
||||
{
|
||||
if (newPackage.CorePackage)
|
||||
if (newPackage.IsCorePackage)
|
||||
{
|
||||
GameMain.Config.SelectCorePackage(newPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(newPackage);
|
||||
GameMain.Config.EnableRegularPackage(newPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
@@ -1213,40 +1234,21 @@ namespace Barotrauma.Steam
|
||||
return "";
|
||||
}
|
||||
|
||||
private static bool CheckFileEquality(string filePath1, string filePath2)
|
||||
{
|
||||
if (filePath1 == filePath2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
using (FileStream fs1 = File.OpenRead(filePath1))
|
||||
using (FileStream fs2 = File.OpenRead(filePath2))
|
||||
{
|
||||
Md5Hash hash1 = new Md5Hash(fs1);
|
||||
Md5Hash hash2 = new Md5Hash(fs2);
|
||||
return hash1.Hash == hash2.Hash;
|
||||
}
|
||||
}
|
||||
|
||||
private static void RemoveMods(Func<ContentPackage, bool> predicate, bool delete = true)
|
||||
{
|
||||
var toRemove = ContentPackage.List.Where(predicate).ToList();
|
||||
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
|
||||
var toRemoveCore = ContentPackage.CorePackages.Where(predicate).ToList();
|
||||
if (toRemoveCore.Contains(GameMain.Config.CurrentCorePackage)) { GameMain.Config.AutoSelectCorePackage(toRemoveCore); }
|
||||
|
||||
var toRemoveRegular = ContentPackage.RegularPackages.Where(predicate).ToList();
|
||||
var packagesToDeselect = GameMain.Config.EnabledRegularPackages.Where(p => toRemoveRegular.Contains(p)).ToList();
|
||||
foreach (var cp in packagesToDeselect)
|
||||
{
|
||||
if (cp.CorePackage)
|
||||
{
|
||||
GameMain.Config.AutoSelectCorePackage(toRemove);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Config.DeselectContentPackage(cp);
|
||||
}
|
||||
GameMain.Config.DisableRegularPackage(cp);
|
||||
}
|
||||
|
||||
if (delete)
|
||||
{
|
||||
var toRemove = toRemoveCore.Concat(toRemoveRegular);
|
||||
foreach (var cp in toRemove)
|
||||
{
|
||||
try
|
||||
@@ -1258,22 +1260,19 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
|
||||
}
|
||||
ContentPackage.RemovePackage(cp);
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
|
||||
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
|
||||
|
||||
ContentPackage.SortContentPackages();
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
GameMain.Config.WarnIfContentPackageSelectionDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables a workshop item by removing the files from the game folder.
|
||||
/// Uninstalls a workshop item by removing the files from the game folder.
|
||||
/// </summary>
|
||||
public static bool DisableWorkShopItem(Steamworks.Ugc.Item? item, bool noLog, out string errorMsg)
|
||||
public static bool UninstallWorkshopItem(Steamworks.Ugc.Item? item, bool noLog, out string errorMsg)
|
||||
{
|
||||
errorMsg = null;
|
||||
if (!(item?.IsInstalled ?? false))
|
||||
@@ -1288,13 +1287,13 @@ namespace Barotrauma.Steam
|
||||
|
||||
ContentPackage contentPackage = new ContentPackage(Path.Combine(item?.Directory, MetadataFileName))
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url
|
||||
SteamWorkshopId = item?.Id ?? 0
|
||||
};
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
try
|
||||
{
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl);
|
||||
RemoveMods(cp => cp.SteamWorkshopId != 0 && cp.SteamWorkshopId == contentPackage.SteamWorkshopId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1330,7 +1329,7 @@ namespace Barotrauma.Steam
|
||||
return contentPackage.IsCompatible();
|
||||
}
|
||||
|
||||
public static bool CheckWorkshopItemEnabled(Steamworks.Ugc.Item? item)
|
||||
public static bool CheckWorkshopItemInstalled(Steamworks.Ugc.Item? item)
|
||||
{
|
||||
if (!(item?.IsInstalled ?? false)) { return false; }
|
||||
|
||||
@@ -1359,7 +1358,7 @@ namespace Barotrauma.Steam
|
||||
string errorMessage = "Metadata file for the Workshop item \"" + item?.Title +
|
||||
"\" not found. Could not combine path (" + (item?.Directory ?? "directory name empty") + ").";
|
||||
DebugConsole.ThrowError(errorMessage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemEnabled:PathCombineException" + item?.Title,
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemInstalled:PathCombineException" + item?.Title,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMessage);
|
||||
return false;
|
||||
@@ -1373,12 +1372,12 @@ namespace Barotrauma.Steam
|
||||
|
||||
ContentPackage contentPackage = new ContentPackage(metaDataPath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url
|
||||
SteamWorkshopId = item?.Id ?? 0
|
||||
};
|
||||
//make sure the contentpackage file is present
|
||||
if (!File.Exists(GetWorkshopItemContentPackagePath(contentPackage)) ||
|
||||
!ContentPackage.List.Any(cp => cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl ||
|
||||
(string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.Name == contentPackage.Name)))
|
||||
!ContentPackage.AllPackages.Any(cp => cp.SteamWorkshopId == contentPackage.SteamWorkshopId ||
|
||||
(cp.SteamWorkshopId == 0 && cp.Name == contentPackage.Name)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1399,9 +1398,9 @@ namespace Barotrauma.Steam
|
||||
|
||||
ContentPackage steamPackage = new ContentPackage(metaDataPath)
|
||||
{
|
||||
SteamWorkshopUrl = item?.Url
|
||||
SteamWorkshopId = item?.Id ?? 0
|
||||
};
|
||||
ContentPackage myPackage = ContentPackage.List.Find(cp => cp.SteamWorkshopUrl == steamPackage.SteamWorkshopUrl);
|
||||
ContentPackage myPackage = ContentPackage.AllPackages.FirstOrDefault(cp => cp.SteamWorkshopId == steamPackage.SteamWorkshopId);
|
||||
|
||||
if (myPackage?.InstallTime == null)
|
||||
{
|
||||
@@ -1427,7 +1426,7 @@ namespace Barotrauma.Steam
|
||||
GameMain.Config.SuppressModFolderWatcher = true;
|
||||
|
||||
//remove mods that the player is no longer subscribed to
|
||||
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && !items.Any(it => it.Id == GetWorkshopItemIDFromUrl(cp.SteamWorkshopUrl)));
|
||||
RemoveMods(cp => cp.SteamWorkshopId != 0 && !items.Any(it => it.Id == cp.SteamWorkshopId));
|
||||
|
||||
GameMain.Config.SuppressModFolderWatcher = false;
|
||||
|
||||
@@ -1441,9 +1440,9 @@ namespace Barotrauma.Steam
|
||||
|
||||
bool installedSuccessfully = false;
|
||||
string errorMsg;
|
||||
if (!CheckWorkshopItemEnabled(item))
|
||||
if (!CheckWorkshopItemInstalled(item))
|
||||
{
|
||||
installedSuccessfully = EnableWorkShopItem(item, out errorMsg);
|
||||
installedSuccessfully = InstallWorkshopItem(item, out errorMsg);
|
||||
}
|
||||
else if (!CheckWorkshopItemUpToDate(item))
|
||||
{
|
||||
@@ -1529,12 +1528,12 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
errorMsg = "";
|
||||
if (!(item?.IsInstalled ?? false)) { return false; }
|
||||
bool reenable = GameMain.Config.SelectedContentPackages.Any(p => !string.IsNullOrEmpty(p.SteamWorkshopUrl) && GetWorkshopItemIDFromUrl(p.SteamWorkshopUrl) == item?.Id);
|
||||
bool reenable = GameMain.Config.AllEnabledPackages.Any(p => p.SteamWorkshopId != 0 && p.SteamWorkshopId == item?.Id);
|
||||
if (item?.Owner.Id != Steamworks.SteamClient.SteamId)
|
||||
{
|
||||
if (!DisableWorkShopItem(item, false, out errorMsg)) { return false; }
|
||||
if (!UninstallWorkshopItem(item, false, out errorMsg)) { return false; }
|
||||
}
|
||||
if (!EnableWorkShopItem(item, errorMsg: out errorMsg, selectContentPackage: reenable)) { return false; }
|
||||
if (!InstallWorkshopItem(item, errorMsg: out errorMsg, enableContentPackage: reenable)) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1543,7 +1542,7 @@ namespace Barotrauma.Steam
|
||||
string packageName = contentPackage.Name.Trim();
|
||||
packageName = ToolBox.RemoveInvalidFileNameChars(packageName);
|
||||
while (packageName.Last() == '.') { packageName = packageName.Substring(0, packageName.Length-1); }
|
||||
//packageName = packageName + "_" + GetWorkshopItemIDFromUrl(contentPackage.SteamWorkshopUrl);
|
||||
//packageName = packageName + "_" + contentPackage.SteamWorkshopId.ToString();
|
||||
|
||||
return Path.Combine("Mods", packageName, MetadataFileName);
|
||||
}
|
||||
@@ -1559,8 +1558,7 @@ namespace Barotrauma.Steam
|
||||
attr.Name.ToString() == "characterfile") &&
|
||||
attr.Value.CleanUpPath().Contains("/"))
|
||||
{
|
||||
ContentType type = ContentType.None;
|
||||
Enum.TryParse(attr.Name.LocalName, true, out type);
|
||||
Enum.TryParse(attr.Name.LocalName, true, out ContentType type);
|
||||
attr.Value = CorrectContentFilePath(attr.Value, type, package, true);
|
||||
}
|
||||
}
|
||||
@@ -1615,8 +1613,7 @@ namespace Barotrauma.Steam
|
||||
if (checkIfFileExists)
|
||||
{
|
||||
bool exists = File.Exists(contentFilePath);
|
||||
if (type == ContentType.Executable ||
|
||||
type == ContentType.ServerExecutable)
|
||||
if (type == ContentType.ServerExecutable)
|
||||
{
|
||||
exists |= File.Exists(Path.GetFileNameWithoutExtension(contentFilePath) + ".dll");
|
||||
}
|
||||
@@ -1634,7 +1631,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
if (checkIfFileExists)
|
||||
{
|
||||
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.Equals(splitPath[1], StringComparison.OrdinalIgnoreCase));
|
||||
ContentPackage otherContentPackage = ContentPackage.AllPackages.FirstOrDefault(cp => cp.Name.Equals(splitPath[1], StringComparison.OrdinalIgnoreCase));
|
||||
if (otherContentPackage != null)
|
||||
{
|
||||
string otherPackageName = Path.GetDirectoryName(otherContentPackage.Path);
|
||||
|
||||
@@ -167,7 +167,7 @@ namespace Barotrauma.Networking
|
||||
bool prevCaptured = true;
|
||||
int captureTimer;
|
||||
|
||||
void UpdateCapture()
|
||||
private void UpdateCapture()
|
||||
{
|
||||
Array.Copy(uncompressedBuffer, 0, prevUncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
|
||||
Array.Clear(uncompressedBuffer, 0, VoipConfig.BUFFER_SIZE);
|
||||
@@ -273,6 +273,11 @@ namespace Barotrauma.Networking
|
||||
if (allowEnqueue || captureTimer > 0)
|
||||
{
|
||||
LastEnqueueAudio = DateTime.Now;
|
||||
if (GameMain.Client?.Character != null)
|
||||
{
|
||||
var messageType = !ForceLocal && ChatMessage.CanUseRadio(GameMain.Client.Character, out _) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
GameMain.Client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||
}
|
||||
//encode audio and enqueue it
|
||||
lock (buffers)
|
||||
{
|
||||
|
||||
@@ -91,13 +91,13 @@ namespace Barotrauma
|
||||
if (userData == null) return;
|
||||
foreach (GUIComponent comp in listBox.Content.Children)
|
||||
{
|
||||
if (comp.UserData != userData) continue;
|
||||
GUITextBlock voteText = comp.FindChild("votes") as GUITextBlock;
|
||||
if (voteText == null)
|
||||
if (comp.UserData != userData) { continue; }
|
||||
if (!(comp.FindChild("votes") is GUITextBlock voteText))
|
||||
{
|
||||
voteText = new GUITextBlock(new RectTransform(new Point(30, comp.Rect.Height), comp.RectTransform, Anchor.CenterRight),
|
||||
"", textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Padding = Vector4.Zero,
|
||||
UserData = "votes"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
@@ -61,6 +62,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
public bool HighQualityCollisionDetection;
|
||||
|
||||
public Vector4 ColorMultiplier;
|
||||
|
||||
public bool DrawOnTop { get; private set; }
|
||||
|
||||
public ParticlePrefab.DrawTargetType DrawTarget
|
||||
@@ -141,7 +144,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
color = prefab.StartColor;
|
||||
changeColor = prefab.StartColor != prefab.EndColor;
|
||||
|
||||
ColorMultiplier = Vector4.One;
|
||||
|
||||
velocityChange = prefab.VelocityChangeDisplay;
|
||||
velocityChangeWater = prefab.VelocityChangeWaterDisplay;
|
||||
|
||||
@@ -287,22 +291,42 @@ namespace Barotrauma.Particles
|
||||
Vector2 collisionNormal = Vector2.Zero;
|
||||
if (velocity.Y < 0.0f && position.Y - prefab.CollisionRadius * size.Y < hullRect.Y - hullRect.Height)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) return false;
|
||||
if (prefab.DeleteOnCollision) { return false; }
|
||||
collisionNormal = new Vector2(0.0f, 1.0f);
|
||||
}
|
||||
else if (velocity.Y > 0.0f && position.Y + prefab.CollisionRadius * size.Y > hullRect.Y)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) return false;
|
||||
if (prefab.DeleteOnCollision) { return false; }
|
||||
collisionNormal = new Vector2(0.0f, -1.0f);
|
||||
}
|
||||
else if (velocity.X < 0.0f && position.X - prefab.CollisionRadius * size.X < hullRect.X)
|
||||
|
||||
if (collisionNormal != Vector2.Zero)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) return false;
|
||||
bool gapFound = false;
|
||||
foreach (Gap gap in hullGaps)
|
||||
{
|
||||
if (gap.Open <= 0.9f || gap.IsHorizontal) { continue; }
|
||||
|
||||
if (gap.WorldRect.X > position.X || gap.WorldRect.Right < position.X) { continue; }
|
||||
float hullCenterY = currentHull.WorldRect.Y - currentHull.WorldRect.Height / 2;
|
||||
int gapDir = Math.Sign(gap.WorldRect.Y - hullCenterY);
|
||||
if (Math.Sign(velocity.Y) != gapDir || Math.Sign(position.Y - hullCenterY) != gapDir) { continue; }
|
||||
|
||||
gapFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
handleCollision(gapFound, collisionNormal);
|
||||
}
|
||||
|
||||
if (velocity.X < 0.0f && position.X - prefab.CollisionRadius * size.X < hullRect.X)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) { return false; }
|
||||
collisionNormal = new Vector2(1.0f, 0.0f);
|
||||
}
|
||||
else if (velocity.X > 0.0f && position.X + prefab.CollisionRadius * size.X > hullRect.Right)
|
||||
{
|
||||
if (prefab.DeleteOnCollision) return false;
|
||||
if (prefab.DeleteOnCollision) { return false; }
|
||||
collisionNormal = new Vector2(-1.0f, 0.0f);
|
||||
}
|
||||
|
||||
@@ -311,26 +335,21 @@ namespace Barotrauma.Particles
|
||||
bool gapFound = false;
|
||||
foreach (Gap gap in hullGaps)
|
||||
{
|
||||
if (gap.Open <= 0.9f || gap.IsHorizontal != (collisionNormal.X != 0.0f)) continue;
|
||||
if (gap.Open <= 0.9f || !gap.IsHorizontal) { continue; }
|
||||
|
||||
if (gap.IsHorizontal)
|
||||
{
|
||||
if (gap.WorldRect.Y < position.Y || gap.WorldRect.Y - gap.WorldRect.Height > position.Y) continue;
|
||||
int gapDir = Math.Sign(gap.WorldRect.Center.X - currentHull.WorldRect.Center.X);
|
||||
if (Math.Sign(velocity.X) != gapDir || Math.Sign(position.X - currentHull.WorldRect.Center.X) != gapDir) continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gap.WorldRect.X > position.X || gap.WorldRect.Right < position.X) continue;
|
||||
float hullCenterY = currentHull.WorldRect.Y - currentHull.WorldRect.Height / 2;
|
||||
int gapDir = Math.Sign(gap.WorldRect.Y - hullCenterY);
|
||||
if (Math.Sign(velocity.Y) != gapDir || Math.Sign(position.Y - hullCenterY) != gapDir) continue;
|
||||
}
|
||||
if (gap.WorldRect.Y < position.Y || gap.WorldRect.Y - gap.WorldRect.Height > position.Y) { continue; }
|
||||
int gapDir = Math.Sign(gap.WorldRect.Center.X - currentHull.WorldRect.Center.X);
|
||||
if (Math.Sign(velocity.X) != gapDir || Math.Sign(position.X - currentHull.WorldRect.Center.X) != gapDir) { continue; }
|
||||
|
||||
gapFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
handleCollision(gapFound, collisionNormal);
|
||||
}
|
||||
|
||||
void handleCollision(bool gapFound, Vector2 collisionNormal)
|
||||
{
|
||||
if (!gapFound)
|
||||
{
|
||||
OnWallCollisionInside(currentHull, collisionNormal);
|
||||
@@ -378,6 +397,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
private void OnWallCollisionInside(Hull prevHull, Vector2 collisionNormal)
|
||||
{
|
||||
if (prevHull == null) { return; }
|
||||
|
||||
Rectangle prevHullRect = prevHull.WorldRect;
|
||||
|
||||
Vector2 subVel = prevHull?.Submarine != null ? ConvertUnits.ToDisplayUnits(prevHull.Submarine.Velocity) : Vector2.Zero;
|
||||
@@ -465,12 +486,14 @@ namespace Barotrauma.Particles
|
||||
drawSize *= ((totalLifeTime - lifeTime) / prefab.GrowTime);
|
||||
}
|
||||
|
||||
Color currColor = new Color(color.ToVector4() * ColorMultiplier);
|
||||
|
||||
if (prefab.Sprites[spriteIndex] is SpriteSheet)
|
||||
{
|
||||
((SpriteSheet)prefab.Sprites[spriteIndex]).Draw(
|
||||
spriteBatch, animFrame,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
color * (color.A / 255.0f),
|
||||
currColor * (currColor.A / 255.0f),
|
||||
prefab.Sprites[spriteIndex].Origin, drawRotation,
|
||||
drawSize, SpriteEffects.None, prefab.Sprites[spriteIndex].Depth);
|
||||
}
|
||||
@@ -478,7 +501,7 @@ namespace Barotrauma.Particles
|
||||
{
|
||||
prefab.Sprites[spriteIndex].Draw(spriteBatch,
|
||||
new Vector2(drawPosition.X, -drawPosition.Y),
|
||||
color * (color.A / 255.0f),
|
||||
currColor * (currColor.A / 255.0f),
|
||||
prefab.Sprites[spriteIndex].Origin, drawRotation,
|
||||
drawSize, SpriteEffects.None, prefab.Sprites[spriteIndex].Depth);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Barotrauma.Particles
|
||||
Prefab = prefab;
|
||||
}
|
||||
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f)
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null)
|
||||
{
|
||||
emitTimer += deltaTime * amountMultiplier;
|
||||
burstEmitTimer -= deltaTime;
|
||||
@@ -33,7 +33,7 @@ namespace Barotrauma.Particles
|
||||
float emitInterval = 1.0f / Prefab.ParticlesPerSecond;
|
||||
while (emitTimer > emitInterval)
|
||||
{
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier);
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier);
|
||||
emitTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
@@ -43,11 +43,11 @@ namespace Barotrauma.Particles
|
||||
burstEmitTimer = Prefab.EmitInterval;
|
||||
for (int i = 0; i < Prefab.ParticleAmount * amountMultiplier; i++)
|
||||
{
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier);
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier)
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null)
|
||||
{
|
||||
angle += Rand.Range(Prefab.AngleMin, Prefab.AngleMax);
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Barotrauma.Particles
|
||||
{
|
||||
particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax) * sizeMultiplier;
|
||||
particle.HighQualityCollisionDetection = Prefab.HighQualityCollisionDetection;
|
||||
if (colorMultiplier.HasValue) { particle.ColorMultiplier = colorMultiplier.Value.ToVector4(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -157,9 +157,9 @@ namespace Barotrauma
|
||||
sb.AppendLine("VSync " + (GameMain.Config.VSyncEnabled ? "ON" : "OFF"));
|
||||
sb.AppendLine("Language: " + (GameMain.Config.Language ?? "none"));
|
||||
}
|
||||
if (GameMain.SelectedPackages != null)
|
||||
if (GameMain.Config.AllEnabledPackages != null)
|
||||
{
|
||||
sb.AppendLine("Selected content packages: " + (!GameMain.SelectedPackages.Any() ? "None" : string.Join(", ", GameMain.SelectedPackages.Select(c => c.Name))));
|
||||
sb.AppendLine("Selected content packages: " + (!GameMain.Config.AllEnabledPackages.Any() ? "None" : string.Join(", ", GameMain.Config.AllEnabledPackages.Select(c => c.Name))));
|
||||
}
|
||||
sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
|
||||
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")"));
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace Barotrauma
|
||||
public Action<SubmarineInfo, string, string> StartNewGame;
|
||||
public Action<string> LoadGame;
|
||||
|
||||
private enum CategoryFilter { All = 0, Vanilla = 1, Custom = 2 };
|
||||
private CategoryFilter subFilter = CategoryFilter.All;
|
||||
|
||||
public GUIButton StartButton
|
||||
{
|
||||
get;
|
||||
@@ -74,6 +77,12 @@ namespace Barotrauma
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SelectedSub"), font: GUI.SubHeadingFont);
|
||||
|
||||
var moddedDropdown = new GUIDropDown(new RectTransform(new Vector2(1f, 0.02f), leftColumn.RectTransform), "", 3);
|
||||
moddedDropdown.AddItem(TextManager.Get("clientpermission.all"), CategoryFilter.All);
|
||||
moddedDropdown.AddItem(TextManager.Get("servertag.modded.false"), CategoryFilter.Vanilla);
|
||||
moddedDropdown.AddItem(TextManager.Get("customrank"), CategoryFilter.Custom);
|
||||
moddedDropdown.Select(0);
|
||||
|
||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true
|
||||
@@ -88,6 +97,14 @@ namespace Barotrauma
|
||||
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
|
||||
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
|
||||
|
||||
moddedDropdown.OnSelected = (component, data) =>
|
||||
{
|
||||
searchBox.Text = string.Empty;
|
||||
subFilter = (CategoryFilter)data;
|
||||
UpdateSubList(SubmarineInfo.SavedSubmarines);
|
||||
return true;
|
||||
};
|
||||
|
||||
subList.OnSelected = OnSubSelected;
|
||||
}
|
||||
else // Spacing to fix the multiplayer campaign setup layout
|
||||
@@ -234,7 +251,7 @@ namespace Barotrauma
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Language == "English" ? "Purchasable submarines" : TextManager.Get("workshoplabelsubmarines"), font: GUI.SubHeadingFont);
|
||||
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("purchasablesubmarines", fallBackTag: "workshoplabelsubmarines"), font: GUI.SubHeadingFont);
|
||||
|
||||
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), subHolder.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -395,7 +412,16 @@ namespace Barotrauma
|
||||
|
||||
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
|
||||
{
|
||||
var subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass).ToList();
|
||||
List<SubmarineInfo> subsToShow;
|
||||
if (!isMultiplayer && subFilter != CategoryFilter.All)
|
||||
{
|
||||
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && s.IsVanillaSubmarine() == (subFilter == CategoryFilter.Vanilla)).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass).ToList();
|
||||
}
|
||||
|
||||
subsToShow.Sort((s1, s2) =>
|
||||
{
|
||||
int p1 = s1.Price > CampaignMode.MaxInitialSubmarinePrice ? 10 : 0;
|
||||
@@ -428,18 +454,22 @@ namespace Barotrauma
|
||||
ToolTip = textBlock.ToolTip
|
||||
};
|
||||
#if !DEBUG
|
||||
if (sub.Price > CampaignMode.MaxInitialSubmarinePrice && !GameMain.DebugDraw)
|
||||
if (!GameMain.DebugDraw)
|
||||
{
|
||||
textBlock.CanBeFocused = false;
|
||||
if (sub.Price > CampaignMode.MaxInitialSubmarinePrice || !sub.IsCampaignCompatible)
|
||||
{
|
||||
textBlock.CanBeFocused = false;
|
||||
textBlock.TextColor *= 0.5f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (SubmarineInfo.SavedSubmarines.Any())
|
||||
{
|
||||
var nonShuttles = subsToShow.Where(s => s.Type == SubmarineType.Player && !s.HasTag(SubmarineTag.Shuttle) && s.Price <= CampaignMode.MaxInitialSubmarinePrice).ToList();
|
||||
if (nonShuttles.Count > 0)
|
||||
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.MaxInitialSubmarinePrice).ToList();
|
||||
if (validSubs.Count > 0)
|
||||
{
|
||||
subList.Select(nonShuttles[Rand.Int(nonShuttles.Count)]);
|
||||
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +478,7 @@ namespace Barotrauma
|
||||
public void UpdateLoadMenu(IEnumerable<string> saveFiles = null)
|
||||
{
|
||||
prevSaveFiles?.Clear();
|
||||
prevSaveFiles = null;
|
||||
loadGameContainer.ClearChildren();
|
||||
|
||||
if (saveFiles == null)
|
||||
@@ -504,6 +535,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
bool isCompatible = true;
|
||||
prevSaveFiles ??= new List<string>();
|
||||
if (!isMultiplayer)
|
||||
{
|
||||
nameText.Text = Path.GetFileNameWithoutExtension(saveFile);
|
||||
@@ -529,10 +561,10 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
prevSaveFiles?.Add(saveFile);
|
||||
string[] splitSaveFile = saveFile.Split(';');
|
||||
saveFrame.UserData = splitSaveFile[0];
|
||||
fileName = nameText.Text = Path.GetFileNameWithoutExtension(splitSaveFile[0]);
|
||||
prevSaveFiles?.Add(fileName);
|
||||
if (splitSaveFile.Length > 1) { subName = splitSaveFile[1]; }
|
||||
if (splitSaveFile.Length > 2) { saveTime = splitSaveFile[2]; }
|
||||
if (splitSaveFile.Length > 3) { contentPackageStr = splitSaveFile[3]; }
|
||||
@@ -545,7 +577,7 @@ namespace Barotrauma
|
||||
if (!string.IsNullOrEmpty(contentPackageStr))
|
||||
{
|
||||
List<string> contentPackagePaths = contentPackageStr.Split('|').ToList();
|
||||
if (!GameSession.IsCompatibleWithSelectedContentPackages(contentPackagePaths, out string errorMsg))
|
||||
if (!GameSession.IsCompatibleWithEnabledContentPackages(contentPackagePaths, out string errorMsg))
|
||||
{
|
||||
nameText.TextColor = GUI.Style.Red;
|
||||
saveFrame.ToolTip = string.Join("\n", errorMsg, TextManager.Get("campaignmode.contentpackagemismatchwarning"));
|
||||
@@ -696,9 +728,16 @@ namespace Barotrauma
|
||||
string saveFile = obj as string;
|
||||
if (obj == null) { return false; }
|
||||
|
||||
SaveUtil.DeleteSave(saveFile);
|
||||
prevSaveFiles?.Remove(saveFile);
|
||||
UpdateLoadMenu(prevSaveFiles);
|
||||
string header = TextManager.Get("deletedialoglabel");
|
||||
string body = TextManager.GetWithVariable("deletedialogquestion", "[file]", Path.GetFileNameWithoutExtension(saveFile));
|
||||
|
||||
EventEditorScreen.AskForConfirmation(header, body, () =>
|
||||
{
|
||||
SaveUtil.DeleteSave(saveFile);
|
||||
prevSaveFiles?.RemoveAll(s => s.StartsWith(saveFile));
|
||||
UpdateLoadMenu(prevSaveFiles.ToList());
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -497,7 +497,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
if (Level.Loaded != null &&
|
||||
connection.LevelData == Level.Loaded.LevelData &&
|
||||
connection?.LevelData == Level.Loaded.LevelData &&
|
||||
currentDisplayLocation == Campaign.Map?.CurrentLocation)
|
||||
{
|
||||
StartButton.Visible = false;
|
||||
|
||||
@@ -1655,9 +1655,9 @@ namespace Barotrauma.CharacterEditor
|
||||
if (contentPackage == null)
|
||||
{
|
||||
#if DEBUG
|
||||
contentPackage = GameMain.Config.SelectedContentPackages.LastOrDefault();
|
||||
contentPackage = GameMain.Config.AllEnabledPackages.LastOrDefault();
|
||||
#else
|
||||
contentPackage = GameMain.Config.SelectedContentPackages.LastOrDefault(cp => cp != vanilla);
|
||||
contentPackage = GameMain.Config.AllEnabledPackages.LastOrDefault(cp => cp != vanilla);
|
||||
#endif
|
||||
}
|
||||
if (contentPackage == null)
|
||||
@@ -1674,9 +1674,9 @@ namespace Barotrauma.CharacterEditor
|
||||
}
|
||||
#endif
|
||||
// Content package
|
||||
if (!GameMain.Config.SelectedContentPackages.Contains(contentPackage))
|
||||
if (!GameMain.Config.AllEnabledPackages.Contains(contentPackage))
|
||||
{
|
||||
GameMain.Config.SelectContentPackage(contentPackage);
|
||||
GameMain.Config.EnableRegularPackage(contentPackage);
|
||||
}
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
@@ -1757,9 +1757,10 @@ namespace Barotrauma.CharacterEditor
|
||||
#endif
|
||||
// Add to the selected content package
|
||||
contentPackage.AddFile(configFilePath, ContentType.Character);
|
||||
Barotrauma.IO.Validation.DevException = true;
|
||||
contentPackage.Save(contentPackage.Path);
|
||||
DebugConsole.NewMessage(GetCharacterEditorTranslation("ContentPackageSaved").Replace("[path]", contentPackage.Path));
|
||||
CharacterPrefab.LoadFromFile(configFilePath, contentPackage, forceOverride: true);
|
||||
Barotrauma.IO.Validation.DevException = false;
|
||||
DebugConsole.NewMessage(GetCharacterEditorTranslation("ContentPackageSaved").Replace("[path]", contentPackage.Path));
|
||||
|
||||
// Ragdoll
|
||||
RagdollParams.ClearCache();
|
||||
@@ -1783,7 +1784,11 @@ namespace Barotrauma.CharacterEditor
|
||||
element.SetAttributeValue("type", name);
|
||||
string fullPath = AnimationParams.GetDefaultFile(name, animation.AnimationType, contentPackage);
|
||||
element.Name = AnimationParams.GetDefaultFileName(name, animation.AnimationType);
|
||||
#if DEBUG
|
||||
element.Save(fullPath);
|
||||
#else
|
||||
element.SaveSafe(fullPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -305,7 +305,7 @@ namespace Barotrauma.CharacterEditor
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), mainElement.RectTransform, Anchor.CenterLeft), TextManager.Get("ContentPackage"));
|
||||
var rightContainer = new GUIFrame(new RectTransform(new Vector2(0.7f, 1), mainElement.RectTransform, Anchor.CenterRight), style: null);
|
||||
contentPackageDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.5f), rightContainer.RectTransform, Anchor.TopRight));
|
||||
foreach (ContentPackage cp in ContentPackage.List)
|
||||
foreach (ContentPackage cp in ContentPackage.AllPackages)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (cp == GameMain.VanillaContent) { continue; }
|
||||
@@ -334,15 +334,15 @@ namespace Barotrauma.CharacterEditor
|
||||
contentPackageNameElement.Flash();
|
||||
return false;
|
||||
}
|
||||
if (ContentPackage.List.Any(cp => cp.Name.ToLower() == contentPackageNameElement.Text.ToLower()))
|
||||
if (ContentPackage.AllPackages.Any(cp => cp.Name.ToLower() == contentPackageNameElement.Text.ToLower()))
|
||||
{
|
||||
new GUIMessageBox("", TextManager.Get("charactereditor.contentpackagenameinuse", fallBackTag: "leveleditorlevelobjnametaken"));
|
||||
return false;
|
||||
}
|
||||
string modName = ToolBox.RemoveInvalidFileNameChars(contentPackageNameElement.Text);
|
||||
ContentPackage = ContentPackage.CreatePackage(contentPackageNameElement.Text, Path.Combine("Mods", modName, Steam.SteamManager.MetadataFileName), false);
|
||||
ContentPackage.List.Add(ContentPackage);
|
||||
GameMain.Config.SelectContentPackage(ContentPackage);
|
||||
ContentPackage.AddPackage(ContentPackage);
|
||||
GameMain.Config.EnableRegularPackage(ContentPackage);
|
||||
contentPackageDropDown.AddItem(ContentPackage.Name, ContentPackage, ContentPackage.Path);
|
||||
contentPackageDropDown.SelectItem(ContentPackage);
|
||||
contentPackageNameElement.Text = "";
|
||||
|
||||
@@ -32,10 +32,13 @@ namespace Barotrauma
|
||||
private EditorNode? draggedNode;
|
||||
private Vector2 dragOffset;
|
||||
|
||||
private Dictionary<EditorNode, Vector2> markedNodes = new Dictionary<EditorNode, Vector2>();
|
||||
private readonly Dictionary<EditorNode, Vector2> markedNodes = new Dictionary<EditorNode, Vector2>();
|
||||
|
||||
private static string projectName = string.Empty;
|
||||
|
||||
private OutpostGenerationParams? lastTestParam;
|
||||
private LocationType? lastTestType;
|
||||
|
||||
private int CreateID()
|
||||
{
|
||||
int maxId = nodeList.Any() ? nodeList.Max(node => node.ID) : 0;
|
||||
@@ -292,6 +295,8 @@ namespace Barotrauma
|
||||
string filePath = System.IO.Path.Combine(directory, $"{projectName}.sevproj");
|
||||
File.WriteAllText(Path.Combine(directory, $"{projectName}.sevproj"), save.ToString());
|
||||
GUI.AddMessage($"Project saved to {filePath}", GUI.Style.Green);
|
||||
|
||||
AskForConfirmation(TextManager.Get("EventEditor.TestPromptHeader"), TextManager.Get("EventEditor.TestPromptBody"), CreateTestSetupMenu);
|
||||
return true;
|
||||
};
|
||||
return true;
|
||||
@@ -520,15 +525,12 @@ namespace Barotrauma
|
||||
|
||||
public override void Select()
|
||||
{
|
||||
Cam.Position = Vector2.Zero;
|
||||
nodeList.Clear();
|
||||
projectName = TextManager.Get("EventEditor.Unnamed");
|
||||
base.Select();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
nodeList.Clear();
|
||||
base.Deselect();
|
||||
}
|
||||
|
||||
@@ -597,9 +599,9 @@ namespace Barotrauma
|
||||
optionElement.Add(new XAttribute("text", text));
|
||||
if (end) { optionElement.Add(new XAttribute("endconversation", true)); }
|
||||
|
||||
if (node != null)
|
||||
if (node is EventNode eventNode)
|
||||
{
|
||||
ExportChildNodes((EventNode) node, optionElement);
|
||||
ExportChildNodes(eventNode, optionElement);
|
||||
}
|
||||
|
||||
newElement.Add(optionElement);
|
||||
@@ -748,6 +750,57 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
private bool CreateTestSetupMenu()
|
||||
{
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("EventEditor.TestPromptHeader"), "", new[] { TextManager.Get("Cancel"), TextManager.Get("OK") },
|
||||
relativeSize: new Vector2(0.2f, 0.3f), minSize: new Point(300, 175));
|
||||
|
||||
var layout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), msgBox.Content.RectTransform));
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0.25f), layout.RectTransform), TextManager.Get("EventEditor.OutpostGenParams"), font: GUI.SubHeadingFont);
|
||||
GUIDropDown paramInput = new GUIDropDown(new RectTransform(new Vector2(1, 0.25f), layout.RectTransform), string.Empty, OutpostGenerationParams.Params.Count);
|
||||
foreach (OutpostGenerationParams param in OutpostGenerationParams.Params)
|
||||
{
|
||||
paramInput.AddItem(param.Identifier, param);
|
||||
}
|
||||
paramInput.OnSelected = (_, param) =>
|
||||
{
|
||||
lastTestParam = param as OutpostGenerationParams;
|
||||
return true;
|
||||
};
|
||||
paramInput.SelectItem(lastTestParam ?? OutpostGenerationParams.Params.FirstOrDefault());
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1, 0.25f), layout.RectTransform), TextManager.Get("EventEditor.LocationType"), font: GUI.SubHeadingFont);
|
||||
GUIDropDown typeInput = new GUIDropDown(new RectTransform(new Vector2(1, 0.25f), layout.RectTransform), string.Empty, LocationType.List.Count);
|
||||
foreach (LocationType type in LocationType.List)
|
||||
{
|
||||
typeInput.AddItem(type.Identifier, type);
|
||||
}
|
||||
typeInput.OnSelected = (_, type) =>
|
||||
{
|
||||
lastTestType = type as LocationType;
|
||||
return true;
|
||||
};
|
||||
typeInput.SelectItem(lastTestType ?? LocationType.List.FirstOrDefault());
|
||||
|
||||
// Cancel button
|
||||
msgBox.Buttons[0].OnClicked = (button, o) =>
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// Ok button
|
||||
msgBox.Buttons[1].OnClicked = (button, o) =>
|
||||
{
|
||||
TestEvent(lastTestParam, lastTestType);
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CreateEditMenu(ValueNode? node, NodeConnection? connection = null)
|
||||
{
|
||||
@@ -860,6 +913,40 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
private bool TestEvent(OutpostGenerationParams? param, LocationType? type)
|
||||
{
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(info => info.HasTag(SubmarineTag.Shuttle));
|
||||
|
||||
XElement? eventXml = ExportXML();
|
||||
EventPrefab? prefab;
|
||||
if (eventXml != null)
|
||||
{
|
||||
prefab = new EventPrefab(eventXml);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.AddMessage("Unable to open test enviroment because the event contains errors.", GUI.Style.Red);
|
||||
return false;
|
||||
}
|
||||
|
||||
GameSession gameSession = new GameSession(subInfo, "", GameModePreset.TestMode, null);
|
||||
TestGameMode gameMode = (TestGameMode) gameSession.GameMode;
|
||||
|
||||
gameMode.SpawnOutpost = true;
|
||||
gameMode.OutpostParams = param;
|
||||
gameMode.OutpostType = type;
|
||||
gameMode.TriggeredEvent = prefab;
|
||||
gameMode.OnRoundEnd = () =>
|
||||
{
|
||||
Submarine.Unload();
|
||||
GameMain.EventEditorScreen.Select();
|
||||
};
|
||||
|
||||
GameMain.GameScreen.Select();
|
||||
gameSession.StartRound(null, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
||||
{
|
||||
DrawnTooltip = string.Empty;
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
|
||||
private Effect damageEffect;
|
||||
private Texture2D damageStencil;
|
||||
private Texture2D distortTexture;
|
||||
private Texture2D distortTexture;
|
||||
|
||||
private float fadeToBlackState;
|
||||
|
||||
@@ -171,6 +171,7 @@ namespace Barotrauma
|
||||
//These will be visible through the LOS effect.
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||
Submarine.DrawBack(spriteBatch, false, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null));
|
||||
Submarine.DrawPaintedColors(spriteBatch, false);
|
||||
spriteBatch.End();
|
||||
|
||||
graphics.SetRenderTarget(null);
|
||||
|
||||
@@ -274,9 +274,9 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//TODO: hacky workaround to check for wrecks and outposts, refactor SubmarineInfo and ContentType at some point
|
||||
var nonPlayerFiles = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Wreck).ToList();
|
||||
nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Outpost));
|
||||
nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.OutpostModule));
|
||||
var nonPlayerFiles = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Wreck).ToList();
|
||||
nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.Outpost));
|
||||
nonPlayerFiles.AddRange(ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.OutpostModule));
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name.Equals(GameMain.Config.QuickStartSubmarineName, StringComparison.InvariantCultureIgnoreCase));
|
||||
subInfo ??= SubmarineInfo.SavedSubmarines.GetRandom(s =>
|
||||
s.IsPlayer && !s.HasTag(SubmarineTag.Shuttle) &&
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace Barotrauma
|
||||
private Tab selectedTab;
|
||||
|
||||
private Sprite backgroundSprite;
|
||||
private Sprite backgroundVignette;
|
||||
|
||||
private readonly GUIComponent titleText;
|
||||
|
||||
@@ -65,8 +64,6 @@ namespace Barotrauma
|
||||
CreateCampaignSetupUI();
|
||||
};
|
||||
|
||||
backgroundVignette = new Sprite("Content/UI/MainMenuVignette.png", Vector2.Zero);
|
||||
|
||||
new GUIImage(new RectTransform(new Vector2(0.4f, 0.25f), Frame.RectTransform, Anchor.BottomRight)
|
||||
{ RelativeOffset = new Vector2(0.08f, 0.05f), AbsoluteOffset = new Point(-8, -8) },
|
||||
style: "TitleText")
|
||||
@@ -863,7 +860,7 @@ namespace Barotrauma
|
||||
GameMain.NetLobbyScreen = new NetLobbyScreen();
|
||||
try
|
||||
{
|
||||
string exeName = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.ServerExecutable)?.FirstOrDefault()?.Path;
|
||||
string exeName = ContentPackage.GetFilesOfType(GameMain.Config.AllEnabledPackages, ContentType.ServerExecutable)?.FirstOrDefault()?.Path;
|
||||
if (string.IsNullOrEmpty(exeName))
|
||||
{
|
||||
DebugConsole.ThrowError("No server executable defined in the selected content packages. Attempting to use the default executable...");
|
||||
@@ -947,14 +944,11 @@ namespace Barotrauma
|
||||
#if USE_STEAM
|
||||
if (GameMain.Config.UseSteamMatchmaking)
|
||||
{
|
||||
joinServerButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
hostServerButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
hostServerButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
}
|
||||
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
steamWorkshopButton.Enabled = Steam.SteamManager.IsInitialized;
|
||||
#endif
|
||||
#else
|
||||
joinServerButton.Enabled = true;
|
||||
hostServerButton.Enabled = true;
|
||||
#if USE_STEAM
|
||||
steamWorkshopButton.Enabled = true;
|
||||
#endif
|
||||
@@ -976,10 +970,14 @@ namespace Barotrauma
|
||||
aberrationStrength: 0.0f);
|
||||
}
|
||||
|
||||
spriteBatch.Begin(blendState: BlendState.NonPremultiplied);
|
||||
backgroundVignette.Draw(spriteBatch, Vector2.Zero, Color.White, Vector2.Zero, 0.0f,
|
||||
new Vector2(GameMain.GraphicsWidth / backgroundVignette.size.X, GameMain.GraphicsHeight / backgroundVignette.size.Y));
|
||||
spriteBatch.End();
|
||||
var vignette = GUI.Style.GetComponentStyle("mainmenuvignette")?.GetDefaultSprite();
|
||||
if (vignette != null)
|
||||
{
|
||||
spriteBatch.Begin(blendState: BlendState.NonPremultiplied);
|
||||
vignette.Draw(spriteBatch, Vector2.Zero, Color.White, Vector2.Zero, 0.0f,
|
||||
new Vector2(GameMain.GraphicsWidth / vignette.size.X, GameMain.GraphicsHeight / vignette.size.Y));
|
||||
spriteBatch.End();
|
||||
}
|
||||
}
|
||||
|
||||
readonly string[] legalCrap = new string[]
|
||||
|
||||
@@ -15,20 +15,20 @@ namespace Barotrauma
|
||||
private readonly List<Sprite> characterSprites = new List<Sprite>();
|
||||
//private readonly List<Sprite> jobPreferenceSprites = new List<Sprite>();
|
||||
|
||||
private GUIFrame infoFrame, modeFrame;
|
||||
private GUILayoutGroup infoFrameContent;
|
||||
private GUIFrame myCharacterFrame;
|
||||
private readonly GUIFrame infoFrame, modeFrame;
|
||||
private readonly GUILayoutGroup infoFrameContent;
|
||||
private readonly GUIFrame myCharacterFrame;
|
||||
|
||||
private GUIListBox subList, modeList;
|
||||
private readonly GUIListBox subList, modeList;
|
||||
|
||||
private GUIListBox chatBox, playerList;
|
||||
private GUIButton serverLogReverseButton;
|
||||
private GUIListBox serverLogBox, serverLogFilterTicks;
|
||||
private readonly GUIListBox chatBox, playerList;
|
||||
private readonly GUIButton serverLogReverseButton;
|
||||
private readonly GUIListBox serverLogBox, serverLogFilterTicks;
|
||||
|
||||
private GUIComponent jobVariantTooltip;
|
||||
|
||||
private GUITextBox chatInput;
|
||||
private GUITextBox serverLogFilter;
|
||||
private readonly GUITextBox chatInput;
|
||||
private readonly GUITextBox serverLogFilter;
|
||||
public GUITextBox ChatInput
|
||||
{
|
||||
get
|
||||
@@ -82,10 +82,10 @@ namespace Barotrauma
|
||||
private readonly GUITickBox autoRestartBox;
|
||||
private readonly GUITextBlock autoRestartText;
|
||||
|
||||
private GUIDropDown shuttleList;
|
||||
private GUITickBox shuttleTickBox;
|
||||
private readonly GUIDropDown shuttleList;
|
||||
private readonly GUITickBox shuttleTickBox;
|
||||
|
||||
private GUIComponent settingsBlocker;
|
||||
private readonly GUIComponent settingsBlocker;
|
||||
|
||||
private Sprite backgroundSprite;
|
||||
|
||||
@@ -123,15 +123,6 @@ namespace Barotrauma
|
||||
public GUIProgressBar FileTransferProgressBar { get; private set; }
|
||||
public GUITextBlock FileTransferProgressText { get; private set; }
|
||||
|
||||
private bool AllowSubSelection
|
||||
{
|
||||
get
|
||||
{
|
||||
return GameMain.NetworkMember.ServerSettings.Voting.AllowSubVoting ||
|
||||
(GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.SelectSub));
|
||||
}
|
||||
}
|
||||
|
||||
public GUITextBox ServerName
|
||||
{
|
||||
get;
|
||||
@@ -150,8 +141,8 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
private GUIButton showChatButton;
|
||||
private GUIButton showLogButton;
|
||||
private readonly GUIButton showChatButton;
|
||||
private readonly GUIButton showLogButton;
|
||||
|
||||
public GUIListBox SubList
|
||||
{
|
||||
@@ -268,9 +259,7 @@ namespace Barotrauma
|
||||
foreach (MissionType type in Enum.GetValues(typeof(MissionType)))
|
||||
{
|
||||
if (type == MissionType.None || type == MissionType.All) { continue; }
|
||||
|
||||
missionTypeTickBoxes[index].Selected = (((int)type & (int)value) != 0);
|
||||
|
||||
missionTypeTickBoxes[index].Selected = ((int)type & (int)value) != 0;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
@@ -290,8 +279,7 @@ namespace Barotrauma
|
||||
List<Pair<JobPrefab, int>> jobPreferences = new List<Pair<JobPrefab, int>>();
|
||||
foreach (GUIComponent child in JobList.Content.Children)
|
||||
{
|
||||
var jobPrefab = child.UserData as Pair<JobPrefab, int>;
|
||||
if (jobPrefab == null) { continue; }
|
||||
if (!(child.UserData is Pair<JobPrefab, int> jobPrefab)) { continue; }
|
||||
jobPreferences.Add(jobPrefab);
|
||||
}
|
||||
return jobPreferences;
|
||||
@@ -743,7 +731,7 @@ namespace Barotrauma
|
||||
foreach (GUIComponent child in subList.Content.Children)
|
||||
{
|
||||
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
||||
child.Visible = string.IsNullOrEmpty(text) ? true : sub.DisplayName.ToLower().Contains(text.ToLower());
|
||||
child.Visible = string.IsNullOrEmpty(text) || sub.DisplayName.ToLower().Contains(text.ToLower());
|
||||
}
|
||||
return true;
|
||||
};
|
||||
@@ -887,7 +875,12 @@ namespace Barotrauma
|
||||
ContinueCampaignButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
|
||||
TextManager.Get("campaigncontinue"), textAlignment: Alignment.Center)
|
||||
{
|
||||
OnClicked = (_, __) => { GameMain.Client?.RequestStartRound(true); return true; }
|
||||
OnClicked = (_, __) =>
|
||||
{
|
||||
CoroutineManager.StartCoroutine(WaitForStartRound(ContinueCampaignButton), "WaitForStartRound");
|
||||
GameMain.Client?.RequestStartRound(true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
QuitCampaignButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.3f), campaignContent.RectTransform),
|
||||
TextManager.Get("pausemenusavequit"), textAlignment: Alignment.Center)
|
||||
@@ -1356,6 +1349,7 @@ namespace Barotrauma
|
||||
if (GameMain.Client == null) { return; }
|
||||
string newName = Client.SanitizeName(tb.Text);
|
||||
newName = newName.Replace(":", "").Replace(";", "");
|
||||
if (newName == GameMain.Client.Name) return;
|
||||
if (string.IsNullOrWhiteSpace(newName))
|
||||
{
|
||||
tb.Text = GameMain.Client.Name;
|
||||
@@ -1365,6 +1359,8 @@ namespace Barotrauma
|
||||
if (isGameRunning)
|
||||
{
|
||||
GameMain.Client.PendingName = tb.Text;
|
||||
TabMenu.PendingChanges = true;
|
||||
CreateChangesPendingText();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1603,13 +1599,13 @@ namespace Barotrauma
|
||||
|
||||
private void AddSubmarine(GUIComponent subList, SubmarineInfo sub)
|
||||
{
|
||||
if (subList is GUIListBox)
|
||||
if (subList is GUIListBox listBox)
|
||||
{
|
||||
subList = ((GUIListBox)subList).Content;
|
||||
subList = listBox.Content;
|
||||
}
|
||||
else if (subList is GUIDropDown)
|
||||
else if (subList is GUIDropDown dropDown)
|
||||
{
|
||||
subList = ((GUIDropDown)subList).ListBox.Content;
|
||||
subList = dropDown.ListBox.Content;
|
||||
}
|
||||
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), subList.RectTransform) { MinSize = new Point(0, 20) },
|
||||
@@ -1655,7 +1651,7 @@ namespace Barotrauma
|
||||
|
||||
if (sub.HasTag(SubmarineTag.Shuttle))
|
||||
{
|
||||
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
||||
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
|
||||
TextManager.Get("Shuttle", fallBackTag: "RespawnShuttle"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = subTextBlock.TextColor * 0.8f,
|
||||
@@ -1665,16 +1661,16 @@ namespace Barotrauma
|
||||
//make shuttles more dim in the sub list (selecting a shuttle as the main sub is allowed but not recommended)
|
||||
if (subList == this.subList.Content)
|
||||
{
|
||||
subTextBlock.TextColor *= 0.5f;
|
||||
subTextBlock.TextColor *= 0.8f;
|
||||
foreach (GUIComponent child in frame.Children)
|
||||
{
|
||||
child.Color *= 0.5f;
|
||||
child.Color *= 0.8f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
||||
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
|
||||
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||
{
|
||||
UserData = "classtext",
|
||||
@@ -1816,20 +1812,20 @@ namespace Barotrauma
|
||||
|
||||
public void SetPlayerNameAndJobPreference(Client client)
|
||||
{
|
||||
var PlayerFrame = (GUITextBlock)PlayerList.Content.FindChild(client);
|
||||
if (PlayerFrame == null) { return; }
|
||||
PlayerFrame.Text = client.Name;
|
||||
var playerFrame = (GUITextBlock)PlayerList.Content.FindChild(client);
|
||||
if (playerFrame == null) { return; }
|
||||
playerFrame.Text = client.Name;
|
||||
|
||||
Color color = Color.White;
|
||||
if (JobPrefab.Prefabs.ContainsKey(client.PreferredJob))
|
||||
{
|
||||
color = JobPrefab.Prefabs[client.PreferredJob].UIColor;
|
||||
}
|
||||
PlayerFrame.Color = color * 0.4f;
|
||||
PlayerFrame.HoverColor = color * 0.6f;
|
||||
PlayerFrame.SelectedColor = color * 0.8f;
|
||||
PlayerFrame.OutlineColor = color * 0.5f;
|
||||
PlayerFrame.TextColor = color;
|
||||
playerFrame.Color = color * 0.4f;
|
||||
playerFrame.HoverColor = color * 0.6f;
|
||||
playerFrame.SelectedColor = color * 0.8f;
|
||||
playerFrame.OutlineColor = color * 0.5f;
|
||||
playerFrame.TextColor = color;
|
||||
}
|
||||
|
||||
public void SetPlayerVoiceIconState(Client client, bool muted, bool mutedLocally)
|
||||
@@ -2671,7 +2667,7 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool SwitchJob(GUIButton button, object obj)
|
||||
private bool SwitchJob(GUIButton _, object obj)
|
||||
{
|
||||
if (JobList == null) { return false; }
|
||||
|
||||
@@ -2724,7 +2720,7 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool OpenJobSelection(GUIComponent child, object userData)
|
||||
private bool OpenJobSelection(GUIComponent _, object __)
|
||||
{
|
||||
if (JobSelectionFrame != null)
|
||||
{
|
||||
@@ -2870,7 +2866,9 @@ namespace Barotrauma
|
||||
{
|
||||
Color = Color.Black,
|
||||
HoverColor = Color.Black,
|
||||
SelectedColor = Color.Black
|
||||
PressedColor = Color.Black,
|
||||
SelectedColor = Color.Black,
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
var textBlock = new GUITextBlock(
|
||||
@@ -2883,6 +2881,7 @@ namespace Barotrauma
|
||||
HoverColor = Color.Transparent,
|
||||
SelectedColor = Color.Transparent,
|
||||
TextColor = jobPrefab.UIColor,
|
||||
HoverTextColor = Color.Lerp(jobPrefab.UIColor, Color.White, 0.5f),
|
||||
CanBeFocused = false,
|
||||
AutoScaleHorizontal = true
|
||||
};
|
||||
@@ -2938,7 +2937,7 @@ namespace Barotrauma
|
||||
info.Head = new CharacterInfo.HeadInfo(info.HeadSpriteId, info.Gender, info.Race, info.HairIndex, info.BeardIndex, index, info.FaceAttachmentIndex);
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError($"Wearable type not implemented: {type.ToString()}");
|
||||
DebugConsole.ThrowError($"Wearable type not implemented: {type}");
|
||||
return false;
|
||||
}
|
||||
info.ReloadHeadAttachments();
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace Barotrauma
|
||||
|
||||
private RectTransform prevGuiElementParent;
|
||||
|
||||
public Exception LoadException;
|
||||
|
||||
public static RoundSummaryScreen Select(Sprite backgroundSprite, RoundSummary roundSummary)
|
||||
{
|
||||
var summaryScreen = new RoundSummaryScreen()
|
||||
@@ -51,5 +53,16 @@ namespace Barotrauma
|
||||
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
if (LoadException != null)
|
||||
{
|
||||
var temp = LoadException;
|
||||
LoadException = null;
|
||||
throw temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -6,13 +7,10 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -21,7 +19,7 @@ namespace Barotrauma
|
||||
class ServerListScreen : Screen
|
||||
{
|
||||
//how often the client is allowed to refresh servers
|
||||
private TimeSpan AllowedRefreshInterval = new TimeSpan(0, 0, 3);
|
||||
private readonly TimeSpan AllowedRefreshInterval = new TimeSpan(0, 0, 3);
|
||||
|
||||
private GUIFrame menu;
|
||||
|
||||
@@ -31,12 +29,20 @@ namespace Barotrauma
|
||||
private GUIButton joinButton;
|
||||
private ServerInfo selectedServer;
|
||||
|
||||
private GUIButton scanServersButton;
|
||||
|
||||
//friends list
|
||||
private GUILayoutGroup friendsButtonHolder;
|
||||
|
||||
private GUIButton friendsDropdownButton;
|
||||
private GUIListBox friendsDropdown;
|
||||
|
||||
//Workshop downloads
|
||||
private GUIFrame workshopDownloadsFrame = null;
|
||||
private Steamworks.Ugc.Item? currentlyDownloadingWorkshopItem = null;
|
||||
private Dictionary<ulong, Steamworks.Ugc.Item?> pendingWorkshopDownloads = null;
|
||||
private string autoConnectName; private string autoConnectEndpoint;
|
||||
|
||||
private class FriendInfo
|
||||
{
|
||||
public UInt64 SteamID;
|
||||
@@ -558,7 +564,7 @@ namespace Barotrauma
|
||||
OnClicked = GameMain.MainMenuScreen.ReturnToMainMenu
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.25f, 0.9f), buttonContainer.RectTransform),
|
||||
scanServersButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.9f), buttonContainer.RectTransform),
|
||||
TextManager.Get("ServerListRefresh"))
|
||||
{
|
||||
OnClicked = (btn, userdata) => { RefreshServers(); return true; }
|
||||
@@ -761,7 +767,7 @@ namespace Barotrauma
|
||||
info.GameStarted = Screen.Selected != GameMain.NetLobbyScreen;
|
||||
info.GameVersion = GameMain.Version.ToString();
|
||||
info.MaxPlayers = serverSettings.MaxPlayers;
|
||||
info.PlayStyle = PlayStyle.SomethingDifferent;
|
||||
info.PlayStyle = serverSettings.PlayStyle;
|
||||
info.RespondedToSteamQuery = true;
|
||||
info.UsingWhiteList = serverSettings.Whitelist.Enabled;
|
||||
info.TraitorsEnabled = serverSettings.TraitorsEnabled;
|
||||
@@ -892,11 +898,11 @@ namespace Barotrauma
|
||||
case "ServerListCompatible":
|
||||
bool? s1Compatible = NetworkMember.IsCompatible(GameMain.Version.ToString(), s1.GameVersion);
|
||||
if (!s1.ContentPackageHashes.Any()) { s1Compatible = null; }
|
||||
if (s1Compatible.HasValue) { s1Compatible = s1Compatible.Value && s1.ContentPackagesMatch(GameMain.SelectedPackages); };
|
||||
if (s1Compatible.HasValue) { s1Compatible = s1Compatible.Value && s1.ContentPackagesMatch(); };
|
||||
|
||||
bool? s2Compatible = NetworkMember.IsCompatible(GameMain.Version.ToString(), s2.GameVersion);
|
||||
if (!s2.ContentPackageHashes.Any()) { s2Compatible = null; }
|
||||
if (s2Compatible.HasValue) { s2Compatible = s2Compatible.Value && s2.ContentPackagesMatch(GameMain.SelectedPackages); };
|
||||
if (s2Compatible.HasValue) { s2Compatible = s2Compatible.Value && s2.ContentPackagesMatch(); };
|
||||
|
||||
//convert to int to make sorting easier
|
||||
//1 Compatible
|
||||
@@ -946,6 +952,9 @@ namespace Barotrauma
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
|
||||
pendingWorkshopDownloads?.Clear();
|
||||
workshopDownloadsFrame = null;
|
||||
}
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
@@ -965,6 +974,43 @@ namespace Barotrauma
|
||||
friendsDropdown.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentlyDownloadingWorkshopItem?.IsInstalled ?? true)
|
||||
{
|
||||
if (pendingWorkshopDownloads?.Any() ?? false)
|
||||
{
|
||||
Steamworks.Ugc.Item? item = pendingWorkshopDownloads.Values.FirstOrDefault(it => it != null);
|
||||
if (item != null)
|
||||
{
|
||||
ulong itemId = item.Value.Id;
|
||||
currentlyDownloadingWorkshopItem = item;
|
||||
SteamManager.SubscribeToWorkshopItem(itemId, () =>
|
||||
{
|
||||
pendingWorkshopDownloads.Remove(itemId);
|
||||
|
||||
if (SteamManager.CheckWorkshopItemInstalled(item))
|
||||
{
|
||||
SteamManager.UninstallWorkshopItem(item, false, out _);
|
||||
}
|
||||
|
||||
if (SteamManager.InstallWorkshopItem(item, out string errorMsg, enableContentPackage: false, suppressInstallNotif: true))
|
||||
{
|
||||
workshopDownloadsFrame?.FindChild((c) => c.UserData is ulong l && l == itemId, true)?.Flash(GUI.Style.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
workshopDownloadsFrame?.FindChild((c) => c.UserData is ulong l && l == itemId, true)?.Flash(GUI.Style.Red);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(autoConnectEndpoint))
|
||||
{
|
||||
JoinServer(autoConnectEndpoint, autoConnectName);
|
||||
autoConnectEndpoint = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterServers()
|
||||
@@ -992,7 +1038,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
bool incompatible =
|
||||
(!serverInfo.ContentPackageHashes.Any() && serverInfo.ContentPackagesMatch(GameMain.Config.SelectedContentPackages)) ||
|
||||
(!serverInfo.ContentPackageHashes.Any() && serverInfo.ContentPackagesMatch()) ||
|
||||
(remoteVersion != null && !NetworkMember.IsCompatible(GameMain.Version, remoteVersion));
|
||||
|
||||
child.Visible =
|
||||
@@ -1018,7 +1064,7 @@ namespace Barotrauma
|
||||
{
|
||||
var playStyle = (PlayStyle)tickBox.UserData;
|
||||
|
||||
if (!tickBox.Selected && serverInfo.PlayStyle == playStyle)
|
||||
if (!tickBox.Selected && (serverInfo.PlayStyle == playStyle || !serverInfo.PlayStyle.HasValue))
|
||||
{
|
||||
child.Visible = false;
|
||||
break;
|
||||
@@ -1136,7 +1182,7 @@ namespace Barotrauma
|
||||
Port = port.ToString(),
|
||||
QueryPort = NetConfig.DefaultQueryPort.ToString(),
|
||||
GameVersion = GameMain.Version.ToString(),
|
||||
PlayStyle = PlayStyle.Serious
|
||||
PlayStyle = null
|
||||
};
|
||||
|
||||
var serverFrame = serverList.Content.FindChild(d => (d.UserData is ServerInfo info) &&
|
||||
@@ -1546,6 +1592,7 @@ namespace Barotrauma
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
scanServersButton.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1555,6 +1602,7 @@ namespace Barotrauma
|
||||
AddToServerList(info);
|
||||
QueueInfoQuery(info);
|
||||
}
|
||||
scanServersButton.Enabled = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1712,7 +1760,7 @@ namespace Barotrauma
|
||||
CanBeFocused = false,
|
||||
Selected =
|
||||
(NetworkMember.IsCompatible(GameMain.Version.ToString(), serverInfo.GameVersion) ?? true) &&
|
||||
serverInfo.ContentPackagesMatch(GameMain.SelectedPackages),
|
||||
serverInfo.ContentPackagesMatch(),
|
||||
UserData = "compatible"
|
||||
};
|
||||
|
||||
@@ -1818,19 +1866,43 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < serverInfo.ContentPackageNames.Count; i++)
|
||||
{
|
||||
if (!GameMain.SelectedPackages.Any(cp => cp.MD5hash.Hash == serverInfo.ContentPackageHashes[i]))
|
||||
bool listAsIncompatible = false;
|
||||
if (serverInfo.ContentPackageWorkshopIds[i] == 0)
|
||||
{
|
||||
listAsIncompatible = !GameMain.Config.AllEnabledPackages.Any(cp => cp.MD5hash.Hash == serverInfo.ContentPackageHashes[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
listAsIncompatible = GameMain.Config.AllEnabledPackages.Any(cp => cp.MD5hash.Hash != serverInfo.ContentPackageHashes[i] &&
|
||||
cp.SteamWorkshopId == serverInfo.ContentPackageWorkshopIds[i]);
|
||||
}
|
||||
if (listAsIncompatible)
|
||||
{
|
||||
if (toolTip != "") toolTip += "\n";
|
||||
toolTip += TextManager.GetWithVariables("ServerListIncompatibleContentPackage", new string[2] { "[contentpackage]", "[hash]" },
|
||||
new string[2] { serverInfo.ContentPackageNames[i], Md5Hash.GetShortHash(serverInfo.ContentPackageHashes[i]) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
serverContent.Children.ForEach(c => c.ToolTip = toolTip);
|
||||
|
||||
serverName.TextColor *= 0.5f;
|
||||
serverPlayers.TextColor *= 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
string toolTip = "";
|
||||
for (int i = 0; i < serverInfo.ContentPackageNames.Count; i++)
|
||||
{
|
||||
if (!GameMain.Config.AllEnabledPackages.Any(cp => cp.MD5hash.Hash == serverInfo.ContentPackageHashes[i]))
|
||||
{
|
||||
if (toolTip != "") toolTip += "\n";
|
||||
toolTip += TextManager.GetWithVariable("ServerListIncompatibleContentPackageWorkshopAvailable", "[contentpackage]", serverInfo.ContentPackageNames[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
serverContent.Children.ForEach(c => c.ToolTip = toolTip);
|
||||
}
|
||||
|
||||
serverContent.Recalculate();
|
||||
|
||||
@@ -1921,17 +1993,17 @@ namespace Barotrauma
|
||||
serverList.ClearChildren();
|
||||
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"), TextManager.GetWithVariable("MasterServerErrorException", "[error]", masterServerResponse.ErrorException.ToString()));
|
||||
}
|
||||
else if (masterServerResponse.StatusCode != System.Net.HttpStatusCode.OK)
|
||||
else if (masterServerResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
serverList.ClearChildren();
|
||||
|
||||
switch (masterServerResponse.StatusCode)
|
||||
{
|
||||
case System.Net.HttpStatusCode.NotFound:
|
||||
case HttpStatusCode.NotFound:
|
||||
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
|
||||
TextManager.GetWithVariable("MasterServerError404", "[masterserverurl]", NetConfig.MasterServerUrl));
|
||||
break;
|
||||
case System.Net.HttpStatusCode.ServiceUnavailable:
|
||||
case HttpStatusCode.ServiceUnavailable:
|
||||
new GUIMessageBox(TextManager.Get("MasterServerErrorLabel"),
|
||||
TextManager.Get("MasterServerErrorUnavailable"));
|
||||
break;
|
||||
@@ -1958,6 +2030,79 @@ namespace Barotrauma
|
||||
masterServerResponded = true;
|
||||
}
|
||||
|
||||
public void DownloadWorkshopItems(IEnumerable<ulong> ids, string serverName, string endPointString)
|
||||
{
|
||||
if (workshopDownloadsFrame != null) { return; }
|
||||
int rowCount = ids.Count() + 2;
|
||||
|
||||
autoConnectName = serverName; autoConnectEndpoint = endPointString;
|
||||
|
||||
workshopDownloadsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), null, Color.Black * 0.5f);
|
||||
pendingWorkshopDownloads = new Dictionary<ulong, Steamworks.Ugc.Item?>();
|
||||
|
||||
var innerFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.1f + 0.03f * rowCount), workshopDownloadsFrame.RectTransform, Anchor.Center, Pivot.Center));
|
||||
var innerLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, (float)rowCount / (float)(rowCount + 3)), innerFrame.RectTransform, Anchor.Center, Pivot.Center));
|
||||
|
||||
foreach (ulong id in ids)
|
||||
{
|
||||
pendingWorkshopDownloads.Add(id, null);
|
||||
|
||||
var itemLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f / rowCount), innerLayout.RectTransform), true, Anchor.CenterLeft)
|
||||
{
|
||||
UserData = id
|
||||
};
|
||||
TaskPool.Add("RetrieveWorkshopItemData", Steamworks.SteamUGC.QueryFileAsync(id), (t) =>
|
||||
{
|
||||
if (t.IsFaulted)
|
||||
{
|
||||
TaskPool.PrintTaskExceptions(t, $"Failed to retrieve Workshop item info (ID {id})");
|
||||
return;
|
||||
}
|
||||
Steamworks.Ugc.Item? item = ((Task<Steamworks.Ugc.Item?>)t).Result;
|
||||
|
||||
if (!item.HasValue)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to find a Steam Workshop item with the ID {id}.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingWorkshopDownloads.ContainsKey(id))
|
||||
{
|
||||
pendingWorkshopDownloads[id] = item;
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.4f, 0.67f), itemLayout.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), item.Value.Title);
|
||||
|
||||
new GUIProgressBar(new RectTransform(new Vector2(0.6f, 0.67f), itemLayout.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), 0f, Color.Lime)
|
||||
{
|
||||
ProgressGetter = () =>
|
||||
{
|
||||
if (item.Value.IsInstalled) { return 1.0f; }
|
||||
else if (!item.Value.IsDownloading) { return 0.0f; }
|
||||
return item.Value.DownloadAmount;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 2.0f / rowCount), innerLayout.RectTransform), true, Anchor.CenterLeft)
|
||||
{
|
||||
UserData = "buttons"
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.3f, 0.67f), buttonLayout.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft), TextManager.Get("Cancel"))
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
autoConnectEndpoint = null;
|
||||
autoConnectName = null;
|
||||
pendingWorkshopDownloads.Clear();
|
||||
workshopDownloadsFrame = null;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private bool JoinServer(string endpoint, string serverName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ClientNameBox.Text))
|
||||
@@ -2113,6 +2258,8 @@ namespace Barotrauma
|
||||
friendPopup?.AddToGUIUpdateList();
|
||||
|
||||
friendsDropdown?.AddToGUIUpdateList();
|
||||
|
||||
workshopDownloadsFrame?.AddToGUIUpdateList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace Barotrauma
|
||||
{
|
||||
loadedSprites.ForEach(s => s.Remove());
|
||||
loadedSprites.Clear();
|
||||
var contentPackages = GameMain.Config.SelectedContentPackages.ToList();
|
||||
var contentPackages = GameMain.Config.AllEnabledPackages.ToList();
|
||||
|
||||
#if !DEBUG
|
||||
var vanilla = GameMain.VanillaContent;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Barotrauma.Steam;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using RestSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -44,7 +43,7 @@ namespace Barotrauma
|
||||
public int PendingLoads = 1;
|
||||
}
|
||||
private readonly Dictionary<ulong, PendingPreviewImageDownload> pendingPreviewImageDownloads = new Dictionary<ulong, PendingPreviewImageDownload>();
|
||||
private Dictionary<string, Sprite> itemPreviewSprites = new Dictionary<string, Sprite>();
|
||||
private readonly Dictionary<string, Sprite> itemPreviewSprites = new Dictionary<string, Sprite>();
|
||||
|
||||
private enum Tab
|
||||
{
|
||||
@@ -237,7 +236,7 @@ namespace Barotrauma
|
||||
|
||||
SelectTab(Tab.Mods);
|
||||
|
||||
subscribedCoroutine = CoroutineManager.StartCoroutine(PollSubscribedItems());
|
||||
CoroutineManager.StartCoroutine(PollSubscribedItems());
|
||||
}
|
||||
|
||||
private GUITextBox CreateFilterBox(GUIComponent parent, GUIListBox listbox)
|
||||
@@ -283,7 +282,7 @@ namespace Barotrauma
|
||||
RefreshSubscribedItems();
|
||||
}
|
||||
|
||||
CoroutineHandle subscribedCoroutine;
|
||||
float subscribePollAdditionalWait = 0.0f;
|
||||
|
||||
private IEnumerable<object> PollSubscribedItems()
|
||||
{
|
||||
@@ -293,6 +292,13 @@ namespace Barotrauma
|
||||
while (true)
|
||||
{
|
||||
while (CoroutineManager.IsCoroutineRunning("Load")) { yield return new WaitForSeconds(1.0f); }
|
||||
while (subscribePollAdditionalWait > 0.01f)
|
||||
{
|
||||
subscribePollAdditionalWait = Math.Min(subscribePollAdditionalWait, 3.0f);
|
||||
float wait = subscribePollAdditionalWait;
|
||||
yield return new WaitForSeconds(wait);
|
||||
subscribePollAdditionalWait -= wait;
|
||||
}
|
||||
uint newNumSubscribed = Steamworks.SteamUGC.NumSubscribedItems;
|
||||
if (newNumSubscribed != numSubscribed)
|
||||
{
|
||||
@@ -338,15 +344,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SubscribeToPackages(List<string> packageUrls)
|
||||
{
|
||||
foreach (string url in packageUrls)
|
||||
{
|
||||
SteamManager.SubscribeToWorkshopItem(url);
|
||||
}
|
||||
GameMain.SteamWorkshopScreen.Select();
|
||||
}
|
||||
|
||||
public IEnumerable<object> RefreshDownloadState()
|
||||
{
|
||||
bool isDownloading = true;
|
||||
@@ -420,14 +417,14 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
//ignore subs that are part of a workshop content package
|
||||
if (ContentPackage.List.Any(cp => !string.IsNullOrEmpty(cp.SteamWorkshopUrl) &&
|
||||
if (ContentPackage.AllPackages.Any(cp => cp.SteamWorkshopId != 0 &&
|
||||
cp.Files.Any(f => f.Type == ContentType.Submarine && Path.GetFullPath(f.Path) == subPath)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//ignore subs that are defined in a content package with more files than just the sub
|
||||
//(these will be listed in the "content packages" section)
|
||||
if (ContentPackage.List.Any(cp => cp.Files.Count > 1 &&
|
||||
if (ContentPackage.AllPackages.Any(cp => cp.Files.Count > 1 &&
|
||||
cp.Files.Any(f => f.Type == ContentType.Submarine && Path.GetFullPath(f.Path) == subPath)))
|
||||
{
|
||||
continue;
|
||||
@@ -441,9 +438,9 @@ namespace Barotrauma
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
foreach (ContentPackage contentPackage in ContentPackage.List)
|
||||
foreach (ContentPackage contentPackage in ContentPackage.AllPackages)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(contentPackage.SteamWorkshopUrl) || contentPackage.HideInWorkshopMenu) { continue; }
|
||||
if (contentPackage.SteamWorkshopId != 0 || contentPackage.HideInWorkshopMenu) { continue; }
|
||||
if (contentPackage == GameMain.VanillaContent) { continue; }
|
||||
//don't list content packages that only define one sub (they're visible in the "Submarines" section)
|
||||
if (contentPackage.Files.Count == 1 && contentPackage.Files[0].Type == ContentType.Submarine) { continue; }
|
||||
@@ -488,7 +485,7 @@ namespace Barotrauma
|
||||
text = topItemFilter.Text;
|
||||
}
|
||||
|
||||
bool visible = string.IsNullOrEmpty(text) ? true : (item?.Title?.ToLower().Contains(text.ToLower()) ?? false);
|
||||
bool visible = string.IsNullOrEmpty(text) || (item?.Title?.ToLower().Contains(text.ToLower()) ?? false);
|
||||
|
||||
int prevIndex = -1;
|
||||
var existingFrame = listBox.Content.FindChild((component) => { return (component.UserData is Steamworks.Ugc.Item?) && (component.UserData as Steamworks.Ugc.Item?)?.Id == item?.Id; });
|
||||
@@ -611,7 +608,7 @@ namespace Barotrauma
|
||||
|
||||
if ((item?.IsSubscribed ?? false) && (item?.IsInstalled ?? false) && Directory.Exists(item?.Directory))
|
||||
{
|
||||
bool installed = SteamManager.CheckWorkshopItemEnabled(item);
|
||||
bool installed = SteamManager.CheckWorkshopItemInstalled(item);
|
||||
|
||||
if (!installed)
|
||||
{
|
||||
@@ -626,7 +623,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
installed = SteamManager.EnableWorkShopItem(item, out string errorMsg, Selected == this);
|
||||
installed = SteamManager.InstallWorkshopItem(item, out string errorMsg, Selected == this);
|
||||
if (!installed)
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
@@ -660,7 +657,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), rightColumn.RectTransform), TextManager.Get("WorkshopItemDownloadPending"));
|
||||
}
|
||||
else if (!(item?.IsSubscribed ?? false))
|
||||
else if (!(item?.IsSubscribed ?? false) && (listBox != subscribedItemList))
|
||||
{
|
||||
var downloadBtn = new GUIButton(new RectTransform(new Point((int)(32 * GUI.Scale)), rightColumn.RectTransform), "", style: "GUIPlusButton")
|
||||
{
|
||||
@@ -684,9 +681,9 @@ namespace Barotrauma
|
||||
var elem = subscribedItemList.Content.GetChildByUserData(item);
|
||||
try
|
||||
{
|
||||
bool reselect = GameMain.Config.SelectedContentPackages.Any(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == item?.Url);
|
||||
if (!SteamManager.DisableWorkShopItem(item, false, out string errorMsg) ||
|
||||
!SteamManager.EnableWorkShopItem(item, out errorMsg, reselect, true))
|
||||
bool reselect = GameMain.Config.AllEnabledPackages.Any(cp => cp.SteamWorkshopId != 0 && cp.SteamWorkshopId == item?.Id);
|
||||
if (!SteamManager.UninstallWorkshopItem(item, false, out string errorMsg) ||
|
||||
!SteamManager.InstallWorkshopItem(item, out errorMsg, reselect, true))
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to reinstall \"{item?.Title}\": {errorMsg}", null, true);
|
||||
elem.Flash(GUI.Style.Red);
|
||||
@@ -707,8 +704,9 @@ namespace Barotrauma
|
||||
};
|
||||
unsubBtn.OnClicked = (btn, userdata) =>
|
||||
{
|
||||
SteamManager.DisableWorkShopItem(item, true, out _);
|
||||
subscribePollAdditionalWait += 1.0f;
|
||||
item?.Unsubscribe();
|
||||
SteamManager.UninstallWorkshopItem(item, true, out _);
|
||||
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
|
||||
return true;
|
||||
};
|
||||
@@ -819,31 +817,34 @@ namespace Barotrauma
|
||||
new Tuple<Steamworks.Ugc.Item?, GUIListBox>(item, listBox),
|
||||
(task, tuple) =>
|
||||
{
|
||||
(var it, var lb) = tuple;
|
||||
var previewImage = lb.Content.FindChild(item)?.GetChildByUserData("previewimage") as GUIImage;
|
||||
if (previewImage != null)
|
||||
//must be done in the main thread because creating/removing GUI elements is not thread-safe
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
previewImage.Sprite = ((Task<Sprite>)task).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateWorkshopItemFrame(it, lb);
|
||||
}
|
||||
(var it, var lb) = tuple;
|
||||
if (lb.Content.FindChild(item)?.GetChildByUserData("previewimage") is GUIImage previewImage)
|
||||
{
|
||||
previewImage.Sprite = ((Task<Sprite>)task).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateWorkshopItemFrame(it, lb);
|
||||
}
|
||||
|
||||
if (modsPreviewFrame.FindChild(it) != null)
|
||||
{
|
||||
ShowItemPreview(it, modsPreviewFrame);
|
||||
}
|
||||
if (browsePreviewFrame.FindChild(item) != null)
|
||||
{
|
||||
ShowItemPreview(it, browsePreviewFrame);
|
||||
}
|
||||
if (modsPreviewFrame.FindChild(it) != null)
|
||||
{
|
||||
ShowItemPreview(it, modsPreviewFrame);
|
||||
}
|
||||
if (browsePreviewFrame.FindChild(item) != null)
|
||||
{
|
||||
ShowItemPreview(it, browsePreviewFrame);
|
||||
}
|
||||
|
||||
lock (pendingPreviewImageDownloads)
|
||||
{
|
||||
pendingPreviewImageDownloads[it.Value.Id].PendingLoads--;
|
||||
if (pendingPreviewImageDownloads[it.Value.Id].PendingLoads <= 0) { pendingPreviewImageDownloads.Remove(it.Value.Id); }
|
||||
}
|
||||
lock (pendingPreviewImageDownloads)
|
||||
{
|
||||
pendingPreviewImageDownloads[it.Value.Id].PendingLoads--;
|
||||
if (pendingPreviewImageDownloads[it.Value.Id].PendingLoads <= 0) { pendingPreviewImageDownloads.Remove(it.Value.Id); }
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -872,15 +873,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (item == null) { return false; }
|
||||
|
||||
if (!(item?.IsSubscribed ?? false)) { item?.Subscribe(); }
|
||||
|
||||
var parentElement = downloadButton.Parent;
|
||||
parentElement.RemoveChild(downloadButton);
|
||||
var textBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), parentElement.RectTransform), TextManager.Get("WorkshopItemDownloading"));
|
||||
|
||||
item?.Download(onInstalled: () =>
|
||||
SteamManager.SubscribeToWorkshopItem(item.Value.Id, () =>
|
||||
{
|
||||
if (SteamManager.EnableWorkShopItem(item, out _))
|
||||
if (SteamManager.InstallWorkshopItem(item, out _))
|
||||
{
|
||||
textBlock.Text = TextManager.Get("workshopiteminstalled");
|
||||
frame.Flash(GUI.Style.Green);
|
||||
@@ -1022,8 +1021,9 @@ namespace Barotrauma
|
||||
UserData = item,
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
SteamManager.DisableWorkShopItem(item, true, out _);
|
||||
subscribePollAdditionalWait += 1.0f;
|
||||
item?.Unsubscribe();
|
||||
SteamManager.UninstallWorkshopItem(item, true, out _);
|
||||
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
|
||||
itemPreviewFrame.ClearChildren();
|
||||
return true;
|
||||
@@ -1294,7 +1294,7 @@ namespace Barotrauma
|
||||
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), topLeftColumn.RectTransform), TextManager.Get("WorkshopItemCorePackage"))
|
||||
{
|
||||
ToolTip = TextManager.Get("WorkshopItemCorePackageTooltip"),
|
||||
Selected = itemContentPackage.CorePackage,
|
||||
Selected = itemContentPackage.IsCorePackage,
|
||||
OnSelected = (tickbox) =>
|
||||
{
|
||||
if (tickbox.Selected)
|
||||
@@ -1309,12 +1309,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
itemContentPackage.CorePackage = tickbox.Selected;
|
||||
itemContentPackage.IsCorePackage = tickbox.Selected;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itemContentPackage.CorePackage = false;
|
||||
itemContentPackage.IsCorePackage = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1478,7 +1478,7 @@ namespace Barotrauma
|
||||
SelectTab(Tab.Browse);
|
||||
deleteVerification.Close();
|
||||
createItemFrame.ClearChildren();
|
||||
itemContentPackage.SteamWorkshopUrl = "";
|
||||
itemContentPackage.SteamWorkshopId = 0;
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
return true;
|
||||
};
|
||||
@@ -1535,9 +1535,17 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (filePath != previewImagePath)
|
||||
if (Path.GetFullPath(filePath) != previewImagePath)
|
||||
{
|
||||
File.Copy(filePath, previewImagePath, overwrite: true);
|
||||
try
|
||||
{
|
||||
File.Copy(filePath, previewImagePath, overwrite: true);
|
||||
}
|
||||
catch (System.IO.IOException e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to copy the preview image \"{previewImagePath}\" to the mod folder.", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemPreviewSprites.ContainsKey(previewImagePath))
|
||||
@@ -1560,13 +1568,12 @@ namespace Barotrauma
|
||||
|
||||
string modFolder = Path.GetDirectoryName(itemContentPackage.Path);
|
||||
string filePathRelativeToModFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, modFolder));
|
||||
string destinationPath;
|
||||
|
||||
//file is not inside the mod folder, we need to move it
|
||||
if (filePathRelativeToModFolder.StartsWith("..") ||
|
||||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
|
||||
{
|
||||
destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
|
||||
string destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
|
||||
//add a number to the filename if a file with the same name already exists
|
||||
i = 2;
|
||||
while (File.Exists(destinationPath))
|
||||
@@ -1582,11 +1589,7 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError("Copying the file \"" + file + "\" to the mod folder failed.", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
destinationPath = Path.Combine(modFolder, filePathRelativeToModFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
RefreshCreateItemFileList();
|
||||
@@ -1605,7 +1608,7 @@ namespace Barotrauma
|
||||
if (itemContentPackage == null) return;
|
||||
var contentTypes = Enum.GetValues(typeof(ContentType));
|
||||
|
||||
List<ContentFile> files = itemContentPackage.Files.ToList();
|
||||
List<ContentFile> files = itemContentPackage.FilesUnsaved.ToList();
|
||||
|
||||
for (int i = files.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -1613,15 +1616,14 @@ namespace Barotrauma
|
||||
|
||||
bool fileExists = File.Exists(contentFile.Path);
|
||||
|
||||
if (contentFile.Type == ContentType.Executable ||
|
||||
contentFile.Type == ContentType.ServerExecutable)
|
||||
if (contentFile.Type == ContentType.ServerExecutable)
|
||||
{
|
||||
fileExists |= File.Exists(Path.GetFileNameWithoutExtension(contentFile.Path) + ".dll");
|
||||
}
|
||||
|
||||
if (!fileExists)
|
||||
{
|
||||
itemContentPackage.Files.Remove(contentFile);
|
||||
itemContentPackage.RemoveFile(contentFile);
|
||||
files.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
@@ -1653,8 +1655,7 @@ namespace Barotrauma
|
||||
bool illegalPath = !ContentPackage.IsModFilePathAllowed(contentFile);
|
||||
bool fileExists = File.Exists(contentFile.Path);
|
||||
|
||||
if (contentFile.Type == ContentType.Executable ||
|
||||
contentFile.Type == ContentType.ServerExecutable)
|
||||
if (contentFile.Type == ContentType.ServerExecutable)
|
||||
{
|
||||
fileExists |= File.Exists(Path.GetFileNameWithoutExtension(contentFile.Path) + ".dll");
|
||||
}
|
||||
@@ -1674,7 +1675,7 @@ namespace Barotrauma
|
||||
|
||||
var tickBox = new GUITickBox(new RectTransform(Vector2.One, content.RectTransform, scaleBasis: ScaleBasis.BothHeight), "")
|
||||
{
|
||||
Selected = itemContentPackage.Files.Contains(contentFile),
|
||||
Selected = itemContentPackage.FilesUnsaved.Contains(contentFile),
|
||||
UserData = contentFile
|
||||
};
|
||||
|
||||
@@ -1683,11 +1684,11 @@ namespace Barotrauma
|
||||
ContentFile f = tb.UserData as ContentFile;
|
||||
if (tb.Selected)
|
||||
{
|
||||
if (!itemContentPackage.Files.Contains(f)) { itemContentPackage.Files.Add(f); }
|
||||
if (!itemContentPackage.FilesUnsaved.Contains(f)) { itemContentPackage.AddFile(f); }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (itemContentPackage.Files.Contains(f)) { itemContentPackage.Files.Remove(f); }
|
||||
if (itemContentPackage.FilesUnsaved.Contains(f)) { itemContentPackage.RemoveFile(f); }
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1702,7 +1703,7 @@ namespace Barotrauma
|
||||
nameText.TextColor = GUI.Style.Red;
|
||||
tickBox.ToolTip = TextManager.Get("WorkshopItemFileNotFound");
|
||||
}
|
||||
else if (illegalPath && !ContentPackage.List.Any(cp => cp.Files.Any(f => Path.GetFullPath(f.Path) == Path.GetFullPath(contentFile.Path))))
|
||||
else if (illegalPath && !ContentPackage.AllPackages.Any(cp => cp.FilesUnsaved.Any(f => Path.GetFullPath(f.Path) == Path.GetFullPath(contentFile.Path))))
|
||||
{
|
||||
nameText.TextColor = GUI.Style.Red;
|
||||
tickBox.ToolTip = TextManager.Get("WorkshopItemIllegalPath");
|
||||
@@ -1839,7 +1840,10 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", item?.Title) + " Task ended with status "+workshopPublishStatus?.TaskStatus?.ToString());
|
||||
TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", item?.Title) +
|
||||
(workshopPublishStatus?.TaskStatus != null ?
|
||||
" Task ended with status " +workshopPublishStatus?.TaskStatus?.ToString() :
|
||||
" Publish failed with result "+ workshopPublishStatus.Result?.Result.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user