v0.10.6.2
This commit is contained in:
@@ -414,7 +414,8 @@ namespace Barotrauma
|
||||
if (playSound)
|
||||
{
|
||||
var damageSound = character.GetSound(s => s.Type == CharacterSound.SoundType.Damage);
|
||||
SoundPlayer.PlayDamageSound(limbJoint.Params.BreakSound, 1.0f, limbJoint.LimbA.body.DrawPosition, range: damageSound != null ? damageSound.Range : 800);
|
||||
float range = damageSound != null ? damageSound.Range * 2 : ConvertUnits.ToDisplayUnits(character.AnimController.Collider.GetSize().Length() * 10);
|
||||
SoundPlayer.PlayDamageSound(limbJoint.Params.BreakSound, 1.0f, limbJoint.LimbA.body.DrawPosition, range: range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,10 +427,10 @@ namespace Barotrauma
|
||||
|
||||
if (Limbs == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace);
|
||||
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -559,6 +559,18 @@ namespace Barotrauma
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime, Camera cam)
|
||||
{
|
||||
if (InvisibleTimer > 0.0f)
|
||||
{
|
||||
if (Controlled == null || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
|
||||
{
|
||||
InvisibleTimer = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvisibleTimer -= deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (!enabled) { return; }
|
||||
|
||||
if (!IsDead && !IsIncapacitated)
|
||||
@@ -568,20 +580,29 @@ namespace Barotrauma
|
||||
soundTimer -= deltaTime;
|
||||
}
|
||||
else if (AIController != null)
|
||||
{
|
||||
{
|
||||
switch (AIController.State)
|
||||
{
|
||||
case AIState.Attack:
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
break;
|
||||
default:
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
var petBehavior = (AIController as EnemyAIController)?.PetBehavior;
|
||||
if (petBehavior != null && petBehavior.Happiness < petBehavior.MaxHappiness * 0.25f)
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Unhappy);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaySound(CharacterSound.SoundType.Idle);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info != null || Vitality < MaxVitality * 0.98f)
|
||||
if (info != null || Vitality < MaxVitality * 0.98f || IsPet)
|
||||
{
|
||||
hudInfoTimer -= deltaTime;
|
||||
if (hudInfoTimer <= 0.0f)
|
||||
@@ -653,7 +674,7 @@ namespace Barotrauma
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (!Enabled) { return; }
|
||||
if (!Enabled || InvisibleTimer > 0.0f) { return; }
|
||||
AnimController.Draw(spriteBatch, cam);
|
||||
}
|
||||
|
||||
@@ -665,7 +686,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void DrawFront(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (!Enabled) { return; }
|
||||
if (!Enabled || InvisibleTimer > 0.0f) { return; }
|
||||
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
@@ -760,49 +781,68 @@ namespace Barotrauma
|
||||
MathHelper.Clamp(1.0f - (cursorDist - (hoverRange - fadeOutRange)) / fadeOutRange, 0.2f, 1.0f) :
|
||||
1.0f;
|
||||
|
||||
if (!GUI.DisableCharacterNames && hudInfoVisible && info != null &&
|
||||
(controlled == null || this != controlled.FocusedCharacter) && cam.Zoom > 0.4f)
|
||||
if (!GUI.DisableCharacterNames && hudInfoVisible &&
|
||||
(controlled == null || this != controlled.FocusedCharacter || IsPet) && cam.Zoom > 0.4f)
|
||||
{
|
||||
string name = Info.DisplayName;
|
||||
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
|
||||
|
||||
Vector2 nameSize = GUI.Font.MeasureString(name);
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
|
||||
|
||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
|
||||
namePos *= screenSize / viewportSize;
|
||||
namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
|
||||
namePos *= viewportSize / screenSize;
|
||||
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
|
||||
|
||||
Color nameColor = Color.White;
|
||||
if (Controlled != null && TeamID != Controlled.TeamID)
|
||||
if (info != null)
|
||||
{
|
||||
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||
string name = Info.DisplayName;
|
||||
if (controlled == null && name != Info.Name) { name += " " + TextManager.Get("Disguised"); }
|
||||
|
||||
Vector2 nameSize = GUI.Font.MeasureString(name);
|
||||
Vector2 namePos = new Vector2(pos.X, pos.Y - 10.0f - (5.0f / cam.Zoom)) - nameSize * 0.5f / cam.Zoom;
|
||||
|
||||
Vector2 screenSize = new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
Vector2 viewportSize = new Vector2(cam.WorldView.Width, cam.WorldView.Height);
|
||||
namePos.X -= cam.WorldView.X; namePos.Y += cam.WorldView.Y;
|
||||
namePos *= screenSize / viewportSize;
|
||||
namePos.X = (float)Math.Floor(namePos.X); namePos.Y = (float)Math.Floor(namePos.Y);
|
||||
namePos *= viewportSize / screenSize;
|
||||
namePos.X += cam.WorldView.X; namePos.Y -= cam.WorldView.Y;
|
||||
|
||||
Color nameColor = Color.White;
|
||||
if (Controlled != null && TeamID != Controlled.TeamID)
|
||||
{
|
||||
nameColor = TeamID == TeamType.FriendlyNPC ? Color.SkyBlue : GUI.Style.Red;
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
|
||||
if (iconStyle != null)
|
||||
{
|
||||
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
|
||||
Vector2 iconPos = headPos;
|
||||
iconPos.Y = -iconPos.Y;
|
||||
nameColor = iconStyle.Color;
|
||||
var icon = iconStyle.Sprites[GUIComponent.ComponentState.None].First();
|
||||
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
|
||||
icon.Sprite.Draw(spriteBatch, iconPos + new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f);
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos, nameColor * hudInfoAlpha, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f);
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.Font.DrawString(spriteBatch, ID.ToString(), namePos - new Vector2(0.0f, 20.0f), Color.White);
|
||||
}
|
||||
}
|
||||
if (CampaignInteractionType != CampaignMode.InteractionType.None && AllowCustomInteract)
|
||||
|
||||
var petBehavior = (AIController as EnemyAIController)?.PetBehavior;
|
||||
if (petBehavior != null && !IsDead && !IsUnconscious)
|
||||
{
|
||||
var iconStyle = GUI.Style.GetComponentStyle("CampaignInteractionBubble." + CampaignInteractionType);
|
||||
var petStatus = petBehavior.GetCurrentStatusIndicatorType();
|
||||
var iconStyle = GUI.Style.GetComponentStyle("PetIcon." + petStatus);
|
||||
if (iconStyle != null)
|
||||
{
|
||||
Vector2 headPos = AnimController.GetLimb(LimbType.Head)?.WorldPosition ?? WorldPosition + Vector2.UnitY * 100.0f;
|
||||
Vector2 iconPos = headPos;
|
||||
iconPos.Y = -iconPos.Y;
|
||||
nameColor = iconStyle.Color;
|
||||
var icon = iconStyle.Sprites[GUIComponent.ComponentState.None].First();
|
||||
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
|
||||
float iconScale = 30.0f / icon.Sprite.size.X / cam.Zoom;
|
||||
icon.Sprite.Draw(spriteBatch, iconPos + new Vector2(-35.0f, -25.0f), iconStyle.Color * hudInfoAlpha, scale: iconScale);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f);
|
||||
GUI.Font.DrawString(spriteBatch, name, namePos, nameColor * hudInfoAlpha, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f);
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
GUI.Font.DrawString(spriteBatch, ID.ToString(), namePos - new Vector2(0.0f, 20.0f), Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDead) { return; }
|
||||
@@ -846,11 +886,12 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<CharacterSound> matchingSounds = new List<CharacterSound>();
|
||||
private SoundChannel soundChannel;
|
||||
public void PlaySound(CharacterSound.SoundType soundType)
|
||||
public void PlaySound(CharacterSound.SoundType soundType, float soundIntervalFactor = 1.0f)
|
||||
{
|
||||
if (sounds == null || sounds.Count == 0) { return; }
|
||||
if (soundChannel != null && soundChannel.IsPlaying) { return; }
|
||||
if (GameMain.SoundManager?.Disabled ?? true) { return; }
|
||||
if (soundTimer > soundInterval * soundIntervalFactor) { return; }
|
||||
matchingSounds.Clear();
|
||||
foreach (var s in sounds)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
{
|
||||
class CharacterHUD
|
||||
{
|
||||
private static Dictionary<Entity, int> orderIndicatorCount = new Dictionary<Entity, int>();
|
||||
private static Dictionary<ISpatialEntity, int> orderIndicatorCount = new Dictionary<ISpatialEntity, int>();
|
||||
const float ItemOverlayDelay = 1.0f;
|
||||
private static Item focusedItem;
|
||||
private static float focusedItemOverlayTimer;
|
||||
@@ -321,6 +321,17 @@ namespace Barotrauma
|
||||
{
|
||||
character.SelectedConstruction.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
}
|
||||
if (Character.Controlled.Inventory != null)
|
||||
{
|
||||
foreach (Item item in Character.Controlled.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
if (Character.Controlled.HasEquippedItem(item))
|
||||
{
|
||||
item.DrawHUD(spriteBatch, cam, Character.Controlled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCampaignInterfaceOpen) { return; }
|
||||
|
||||
@@ -415,7 +426,7 @@ namespace Barotrauma
|
||||
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
|
||||
startPos = cam.WorldToScreen(startPos);
|
||||
|
||||
string focusName = character.FocusedCharacter.DisplayName;
|
||||
string focusName = character.FocusedCharacter.Info == null ? character.FocusedCharacter.DisplayName : character.FocusedCharacter.Info.DisplayName;
|
||||
Vector2 textPos = startPos;
|
||||
Vector2 textSize = GUI.Font.MeasureString(focusName);
|
||||
Vector2 largeTextSize = GUI.SubHeadingFont.MeasureString(focusName);
|
||||
@@ -431,6 +442,14 @@ namespace Barotrauma
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2, GUI.SubHeadingFont);
|
||||
textPos.X += 10.0f * GUI.Scale;
|
||||
textPos.Y += GUI.SubHeadingFont.MeasureString(focusName).Y;
|
||||
|
||||
if (!character.FocusedCharacter.IsIncapacitated && character.FocusedCharacter.IsPet)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("PlayHint", GameMain.Config.KeyBindText(InputType.Use)),
|
||||
GUI.Style.Green, Color.Black, 2, GUI.SmallFont);
|
||||
textPos.Y += largeTextSize.Y;
|
||||
}
|
||||
|
||||
if (character.FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBindText(InputType.Grab)),
|
||||
@@ -458,6 +477,8 @@ namespace Barotrauma
|
||||
|
||||
private static void DrawOrderIndicator(SpriteBatch spriteBatch, Camera cam, Character character, Order order, float iconAlpha = 1.0f)
|
||||
{
|
||||
if (order?.SymbolSprite == null) { return; }
|
||||
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
if (order.OrderGiver != character && !order.HasAppropriateJob(character))
|
||||
@@ -466,7 +487,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Entity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetEntity;
|
||||
ISpatialEntity target = order.ConnectedController != null ? order.ConnectedController.Item : order.TargetSpatialEntity;
|
||||
if (target == null) { return; }
|
||||
|
||||
//don't show the indicator if far away and not inside the same sub
|
||||
@@ -479,7 +500,9 @@ namespace Barotrauma
|
||||
|
||||
if (!orderIndicatorCount.ContainsKey(target)) { orderIndicatorCount.Add(target, 0); }
|
||||
|
||||
Vector2 drawPos = target.DrawPosition + Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
|
||||
Vector2 drawPos = target is Entity ? (target as Entity).DrawPosition :
|
||||
target.Submarine == null ? target.Position : target.Position + target.Submarine.DrawPosition;
|
||||
drawPos += Vector2.UnitX * order.SymbolSprite.size.X * 1.5f * orderIndicatorCount[target];
|
||||
GUI.DrawIndicator(spriteBatch, drawPos, cam, 100.0f, order.SymbolSprite, order.Color * iconAlpha);
|
||||
|
||||
orderIndicatorCount[target] = orderIndicatorCount[target] + 1;
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace Barotrauma
|
||||
GUI.Style.Green,
|
||||
textPopupPos,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: Character.Controlled?.Info == this);
|
||||
playSound: false);
|
||||
}
|
||||
else if (prevLevel % 0.1f > 0.05f && newLevel % 0.1f < 0.05f)
|
||||
{
|
||||
@@ -163,7 +163,7 @@ namespace Barotrauma
|
||||
GUI.Style.Green,
|
||||
textPopupPos,
|
||||
Vector2.UnitY * 10.0f,
|
||||
playSound: Character.Controlled?.Info == this);
|
||||
playSound: false);
|
||||
}
|
||||
|
||||
if ((int)newLevel > (int)prevLevel)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
@@ -83,6 +84,10 @@ namespace Barotrauma
|
||||
{
|
||||
newMem.interact = FocusedCharacter.ID;
|
||||
}
|
||||
else if (newMem.states.HasFlag(InputNetFlags.Use) && (FocusedCharacter?.IsPet ?? false))
|
||||
{
|
||||
newMem.interact = FocusedCharacter.ID;
|
||||
}
|
||||
else if (focusedItem != null && !CharacterInventory.DraggingItemToWorld &&
|
||||
!newMem.states.HasFlag(InputNetFlags.Grab) && !newMem.states.HasFlag(InputNetFlags.Health))
|
||||
{
|
||||
@@ -253,6 +258,7 @@ namespace Barotrauma
|
||||
if (readStatus)
|
||||
{
|
||||
ReadStatus(msg);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ClientRead(msg);
|
||||
}
|
||||
|
||||
msg.ReadPadBits();
|
||||
@@ -444,14 +450,25 @@ namespace Barotrauma
|
||||
Entity targetEntity = FindEntityByID(inc.ReadUInt16());
|
||||
Character orderGiver = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
|
||||
int orderOptionIndex = inc.ReadByte();
|
||||
OrderTarget targetPosition = null;
|
||||
if (inc.ReadBoolean())
|
||||
{
|
||||
var x = inc.ReadSingle();
|
||||
var y = inc.ReadSingle();
|
||||
var hull = FindEntityByID(inc.ReadUInt16()) as Hull;
|
||||
targetPosition = new OrderTarget(new Vector2(x, y), hull, true);
|
||||
}
|
||||
|
||||
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
|
||||
{
|
||||
var orderPrefab = Order.PrefabList[orderPrefabIndex];
|
||||
if (!orderPrefab.MustSetTarget || (targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
|
||||
var component = orderPrefab.GetTargetItemComponent(targetEntity as Item);
|
||||
if (!orderPrefab.MustSetTarget || (targetEntity != null && component != null) || targetPosition != null)
|
||||
{
|
||||
character.SetOrder(
|
||||
new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
|
||||
var order = targetPosition == null ?
|
||||
new Order(orderPrefab, targetEntity, component, orderGiver: orderGiver) :
|
||||
new Order(orderPrefab, targetPosition, orderGiver: orderGiver);
|
||||
character.SetOrder(order,
|
||||
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
|
||||
orderGiver, speak: false);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
public enum SoundType
|
||||
{
|
||||
Idle, Attack, Die, Damage
|
||||
Idle, Attack, Die, Damage, Happy, Unhappy
|
||||
}
|
||||
|
||||
private readonly RoundSound roundSound;
|
||||
|
||||
@@ -1,38 +1,26 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class AfflictionPsychosis : Affliction
|
||||
{
|
||||
class FakeFireSource
|
||||
{
|
||||
public Vector2 Size;
|
||||
public Vector2 Position;
|
||||
public Hull Hull;
|
||||
|
||||
public float LifeTime;
|
||||
}
|
||||
|
||||
const int MaxFakeFireSources = 10;
|
||||
const float MinFakeFireSourceInterval = 30.0f, MaxFakeFireSourceInterval = 240.0f;
|
||||
private float createFireSourceTimer;
|
||||
private readonly List<FakeFireSource> fakeFireSources = new List<FakeFireSource>();
|
||||
private readonly List<DummyFireSource> fakeFireSources = new List<DummyFireSource>();
|
||||
|
||||
enum FloodType
|
||||
public enum FloodType
|
||||
{
|
||||
None,
|
||||
Minor,
|
||||
Major,
|
||||
HideFlooding
|
||||
}
|
||||
|
||||
const float MinSoundInterval = 10.0f, MaxSoundInterval = 180.0f;
|
||||
const float MinSoundInterval = 60.0f, MaxSoundInterval = 240.0f;
|
||||
private FloodType currentFloodType;
|
||||
private float soundTimer;
|
||||
|
||||
@@ -44,12 +32,21 @@ namespace Barotrauma
|
||||
private float fakeBrokenInterval = 30.0f;
|
||||
private float fakeBrokenTimer = 0.0f;
|
||||
|
||||
private float invisibleCharacterInterval = 30.0f;
|
||||
private float invisibleCharacterTimer = 0.0f;
|
||||
|
||||
public FloodType CurrentFloodType
|
||||
{
|
||||
get { return currentFloodType; }
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
if (Character.Controlled != characterHealth.Character) return;
|
||||
UpdateFloods(deltaTime);
|
||||
UpdateSounds(characterHealth.Character, deltaTime);
|
||||
UpdateFires(characterHealth.Character, deltaTime);
|
||||
UpdateInvisibleCharacters(deltaTime);
|
||||
UpdateFakeBroken(deltaTime);
|
||||
}
|
||||
|
||||
@@ -77,10 +74,14 @@ namespace Barotrauma
|
||||
{
|
||||
case FloodType.Minor:
|
||||
currentFloodState += deltaTime;
|
||||
//lerp the water surface in all hulls 50 units above the floor within 10 seconds
|
||||
//lerp the water surface in all hulls 15 units above the floor within 10 seconds
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 50.0f, currentFloodState / 10.0f);
|
||||
for (int i = hull.FakeFireSources.Count - 1; i >= 0; i--)
|
||||
{
|
||||
hull.FakeFireSources[i].Extinguish(deltaTime, 50.0f);
|
||||
}
|
||||
hull.DrawSurface = hull.Rect.Y - hull.Rect.Height + MathHelper.Lerp(0.0f, 15.0f, currentFloodState / 10.0f);
|
||||
}
|
||||
break;
|
||||
case FloodType.Major:
|
||||
@@ -88,6 +89,10 @@ namespace Barotrauma
|
||||
//create a full flood in 10 seconds
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
for (int i = hull.FakeFireSources.Count - 1; i >= 0; i--)
|
||||
{
|
||||
hull.FakeFireSources[i].Extinguish(deltaTime, 200.0f);
|
||||
}
|
||||
hull.DrawSurface = hull.Rect.Y - MathHelper.Lerp(hull.Rect.Height, 0.0f, currentFloodState / 10.0f);
|
||||
}
|
||||
break;
|
||||
@@ -104,6 +109,7 @@ namespace Barotrauma
|
||||
|
||||
if (createFloodTimer < MathHelper.Lerp(MaxFloodInterval, MinFloodInterval, Strength / 100.0f))
|
||||
{
|
||||
currentFloodType = FloodType.None;
|
||||
createFloodTimer += deltaTime;
|
||||
return;
|
||||
}
|
||||
@@ -114,10 +120,12 @@ namespace Barotrauma
|
||||
if (Rand.Range(0.0f, 1.0f) < 0.5f)
|
||||
{
|
||||
currentFloodType = FloodType.HideFlooding;
|
||||
currentFloodType = FloodType.Minor;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentFloodType = Strength < 50.0f ? FloodType.Minor : FloodType.Major;
|
||||
//disabled Major flooding because it's too easy to tell it's fake
|
||||
currentFloodType = FloodType.Minor;// Strength < 50.0f ? FloodType.Minor : FloodType.Major;
|
||||
}
|
||||
currentFloodDuration = Rand.Range(20.0f, 100.0f);
|
||||
}
|
||||
@@ -127,47 +135,46 @@ namespace Barotrauma
|
||||
private void UpdateFires(Character character, float deltaTime)
|
||||
{
|
||||
createFireSourceTimer += deltaTime;
|
||||
fakeFireSources.RemoveAll(fs => fs.Removed);
|
||||
if (fakeFireSources.Count < MaxFakeFireSources &&
|
||||
character.Submarine != null &&
|
||||
createFireSourceTimer > MathHelper.Lerp(MaxFakeFireSourceInterval, MinFakeFireSourceInterval, Strength / 100.0f))
|
||||
{
|
||||
Hull fireHull = Hull.hullList.GetRandom(h => h.Submarine == character.Submarine);
|
||||
|
||||
fakeFireSources.Add(new FakeFireSource()
|
||||
if (fireHull != null)
|
||||
{
|
||||
Size = Vector2.One * 20.0f,
|
||||
Hull = fireHull,
|
||||
Position = new Vector2(Rand.Range(0.0f, fireHull.Rect.Width), 30.0f),
|
||||
LifeTime = MathHelper.Lerp(10.0f, 100.0f, Strength / 100.0f)
|
||||
});
|
||||
createFireSourceTimer = 0.0f;
|
||||
}
|
||||
|
||||
foreach (FakeFireSource fakeFireSource in fakeFireSources)
|
||||
{
|
||||
if (fakeFireSource.Hull.DrawSurface > fakeFireSource.Hull.Rect.Y - fakeFireSource.Hull.Rect.Height + fakeFireSource.Position.Y)
|
||||
{
|
||||
fakeFireSource.LifeTime -= deltaTime * 100.0f;
|
||||
var fakeFire = new DummyFireSource(Vector2.One * 500.0f, new Vector2(Rand.Range(fireHull.WorldRect.X, fireHull.WorldRect.Right), fireHull.WorldPosition.Y), fireHull, isNetworkMessage: true)
|
||||
{
|
||||
CausedByPsychosis = true,
|
||||
DamagesItems = false,
|
||||
DamagesCharacters = false
|
||||
};
|
||||
fakeFireSources.Add(fakeFire);
|
||||
createFireSourceTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fakeFireSource.LifeTime -= deltaTime;
|
||||
float growAmount = deltaTime * 5.0f;
|
||||
fakeFireSource.Size.X += growAmount;
|
||||
fakeFireSource.Position.X = MathHelper.Clamp(fakeFireSource.Position.X - growAmount / 2.0f, 0.0f, fakeFireSource.Hull.Rect.Width);
|
||||
fakeFireSource.Position.Y = MathHelper.Clamp(fakeFireSource.Position.Y, 0.0f, fakeFireSource.Hull.Rect.Height);
|
||||
fakeFireSource.Size.X = Math.Min(fakeFireSource.Hull.Rect.Width - fakeFireSource.Position.X, fakeFireSource.Size.X);
|
||||
fakeFireSource.Size.Y = Math.Min(fakeFireSource.Hull.Rect.Height - fakeFireSource.Position.Y, fakeFireSource.Size.Y);
|
||||
private void UpdateInvisibleCharacters(float deltaTime)
|
||||
{
|
||||
invisibleCharacterTimer -= deltaTime;
|
||||
if (invisibleCharacterTimer > 0.0f) { return; }
|
||||
|
||||
FireSource.EmitParticles(
|
||||
fakeFireSource.Size,
|
||||
fakeFireSource.Hull.WorldRect.Location.ToVector2() + fakeFireSource.Position - Vector2.UnitY * fakeFireSource.Hull.Rect.Height,
|
||||
fakeFireSource.Hull,
|
||||
0.5f);
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.IsDead || c == Character.Controlled) { continue; }
|
||||
if (c.WorldPosition.X < GameMain.GameScreen.Cam.WorldView.X || c.WorldPosition.X > GameMain.GameScreen.Cam.WorldView.Right) { continue; }
|
||||
if (c.WorldPosition.Y < GameMain.GameScreen.Cam.WorldView.Y - GameMain.GameScreen.Cam.WorldView.Height || c.WorldPosition.Y > GameMain.GameScreen.Cam.WorldView.Y) { continue; }
|
||||
if (Rand.Range(0.0f, 500.0f) < Strength)
|
||||
{
|
||||
c.InvisibleTimer = 60.0f;
|
||||
}
|
||||
}
|
||||
|
||||
fakeFireSources.RemoveAll(fs => fs.LifeTime <= 0.0f);
|
||||
invisibleCharacterTimer = invisibleCharacterInterval;
|
||||
}
|
||||
|
||||
|
||||
private void UpdateFakeBroken(float deltaTime)
|
||||
{
|
||||
fakeBrokenTimer -= deltaTime;
|
||||
|
||||
@@ -225,7 +225,15 @@ namespace Barotrauma
|
||||
Character.Controlled.ResetInteract = true;
|
||||
if (openHealthWindow != null)
|
||||
{
|
||||
openHealthWindow.characterName.Text = value.Character.Name;
|
||||
if (value.Character.Info == null || Character.Controlled.HasEquippedItem("healthscanner"))
|
||||
{
|
||||
openHealthWindow.characterName.Text = value.Character.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
openHealthWindow.characterName.Text = value.Character.Info.DisplayName;
|
||||
}
|
||||
|
||||
if (Character.Controlled.SelectedConstruction != null && Character.Controlled.SelectedConstruction.GetComponent<Ladder>() == null)
|
||||
{
|
||||
Character.Controlled.SelectedConstruction = null;
|
||||
@@ -545,7 +553,7 @@ namespace Barotrauma
|
||||
|
||||
private void OnAttacked(Character attacker, AttackResult attackResult)
|
||||
{
|
||||
if (Math.Abs(attackResult.Damage) < 0.01f && attackResult.Afflictions.Count == 0) { return; }
|
||||
if (Math.Abs(attackResult.Damage) < 0.01f) { return; }
|
||||
DamageOverlayTimer = MathHelper.Clamp(attackResult.Damage / MaxVitality, DamageOverlayTimer, 1.0f);
|
||||
if (healthShadowDelay <= 0.0f) { healthShadowDelay = 1.0f; }
|
||||
|
||||
@@ -611,17 +619,41 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateOxygenProjSpecific(float prevOxygen)
|
||||
private float timeUntilNextHeartbeatSound = 0.0f;
|
||||
private bool nextHeartbeatSoundIsSystole = true;
|
||||
private const string diastoleSoundTag = "heartbeatdiastole", systoleSoundTag = "heartbeatsystole";
|
||||
|
||||
partial void UpdateOxygenProjSpecific(float prevOxygen, float deltaTime)
|
||||
{
|
||||
if (prevOxygen > 0.0f && OxygenAmount <= 0.0f &&
|
||||
Character.Controlled == Character)
|
||||
if (prevOxygen > 0.0f && OxygenAmount <= 0.0f && Character.Controlled == Character)
|
||||
{
|
||||
SoundPlayer.PlaySound(Character.Info != null && Character.Info.Gender == Gender.Female ? "drownfemale" : "drownmale");
|
||||
}
|
||||
|
||||
if (Character == Character.Controlled && !IsUnconscious && !Character.IsDead && OxygenAmount < LowOxygenThreshold)
|
||||
{
|
||||
timeUntilNextHeartbeatSound -= deltaTime;
|
||||
if (timeUntilNextHeartbeatSound < 0.0f)
|
||||
{
|
||||
if (nextHeartbeatSoundIsSystole)
|
||||
{
|
||||
SoundPlayer.PlaySound(systoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
|
||||
timeUntilNextHeartbeatSound = MathHelper.Lerp(0.18f, 0.3f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
SoundPlayer.PlaySound(diastoleSoundTag, 1.0f - (OxygenAmount / LowOxygenThreshold));
|
||||
timeUntilNextHeartbeatSound = MathHelper.Lerp(0.3f, 0.5f, Math.Clamp(OxygenAmount / InsufficientOxygenThreshold, 0.0f, 1.0f));
|
||||
}
|
||||
nextHeartbeatSoundIsSystole = !nextHeartbeatSoundIsSystole;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partial void UpdateBleedingProjSpecific(AfflictionBleeding affliction, Limb targetLimb, float deltaTime)
|
||||
{
|
||||
if (Character.InvisibleTimer > 0.0f) { return; }
|
||||
|
||||
bloodParticleTimer -= deltaTime * (affliction.Strength / 10.0f);
|
||||
if (bloodParticleTimer <= 0.0f)
|
||||
{
|
||||
@@ -664,7 +696,7 @@ namespace Barotrauma
|
||||
{
|
||||
forceAfflictionContainerUpdate = true;
|
||||
currentDisplayedAfflictions = GetAllAfflictions(mergeSameAfflictions: true)
|
||||
.FindAll(a => a.Strength >= a.Prefab.ShowIconThreshold && a.Prefab.Icon != null);
|
||||
.FindAll(a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
|
||||
currentDisplayedAfflictions.Sort((a1, a2) =>
|
||||
{
|
||||
int dmgPerSecond = Math.Sign(a2.DamagePerSecond - a1.DamagePerSecond);
|
||||
@@ -1147,7 +1179,7 @@ namespace Barotrauma
|
||||
afflictionIconContainer.Content.ClearChildren();
|
||||
return;
|
||||
}
|
||||
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.Strength >= a.Prefab.ShowIconThreshold);
|
||||
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
|
||||
var displayedAfflictions = afflictionIconContainer.Content.Children.Select(c => c.UserData as Affliction);
|
||||
if (currentAfflictions.Any(a => !displayedAfflictions.Contains(a)) ||
|
||||
displayedAfflictions.Any(a => !currentAfflictions.Contains(a)))
|
||||
@@ -1675,9 +1707,9 @@ namespace Barotrauma
|
||||
|
||||
var tempAfflictions = GetMatchingAfflictions(limbHealth, a => true);
|
||||
|
||||
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.Strength >= a.Prefab.ShowIconThreshold).Sum(a => a.Strength);
|
||||
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength);
|
||||
//float negativeMaxEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
|
||||
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.Strength >= a.Prefab.ShowIconThreshold).Sum(a => a.Strength * 0.2f);
|
||||
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength * 0.2f);
|
||||
//float positiveMaxEffect = tempAfflictions.Where(a => a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
|
||||
|
||||
float midPoint = (float)limbEffectiveArea.Center.Y / (float)limbHealth.IndicatorSprite.Texture.Height;
|
||||
@@ -1786,11 +1818,11 @@ namespace Barotrauma
|
||||
i = 0;
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.Strength >= a.Prefab.ShowIconThreshold);
|
||||
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.ShouldShowIcon(Character));
|
||||
thisAfflictions = thisAfflictions.Concat(afflictions.Where(a =>
|
||||
{
|
||||
Limb indicatorLimb = Character.AnimController.GetLimb(a.Prefab.IndicatorLimb);
|
||||
return (indicatorLimb != null && indicatorLimb.HealthIndex == i && a.Strength >= a.Prefab.ShowIconThreshold);
|
||||
return indicatorLimb != null && indicatorLimb.HealthIndex == i && a.ShouldShowIcon(Character);
|
||||
}));
|
||||
|
||||
if (thisAfflictions.Count() <= 0) { i++; continue; }
|
||||
@@ -1837,12 +1869,14 @@ namespace Barotrauma
|
||||
|
||||
private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction, float iconScale, ref Vector2 iconPos)
|
||||
{
|
||||
if (affliction.Strength < affliction.Prefab.ShowIconThreshold) return;
|
||||
Vector2 iconSize = (affliction.Prefab.Icon.size * iconScale);
|
||||
if (!affliction.ShouldShowIcon(Character)) { return; }
|
||||
Vector2 iconSize = affliction.Prefab.Icon.size * iconScale;
|
||||
|
||||
float showIconThreshold = Character.Controlled?.CharacterHealth == this ? affliction.Prefab.ShowIconThreshold : affliction.Prefab.ShowIconToOthersThreshold;
|
||||
|
||||
//afflictions that have a strength of less than 10 are faded out slightly
|
||||
float alpha = MathHelper.Lerp(0.3f, 1.0f,
|
||||
(affliction.Strength - affliction.Prefab.ShowIconThreshold) / Math.Min(affliction.Prefab.MaxStrength - affliction.Prefab.ShowIconThreshold, 10.0f));
|
||||
(affliction.Strength - showIconThreshold) / Math.Min(affliction.Prefab.MaxStrength - showIconThreshold, 10.0f));
|
||||
|
||||
affliction.Prefab.Icon.Draw(spriteBatch, iconPos - iconSize / 2.0f, GetAfflictionIconColor(affliction.Prefab, affliction) * alpha, 0, iconScale);
|
||||
iconPos += new Vector2(10.0f, 20.0f) * iconScale;
|
||||
|
||||
@@ -8,5 +8,12 @@
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize("", false), Editable]
|
||||
public string DamageParticle
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,17 +278,7 @@ namespace Barotrauma
|
||||
DamagedSprite = new Sprite(subElement, file: GetSpritePath(subElement, Params.damagedSpriteParams));
|
||||
break;
|
||||
case "conditionalsprite":
|
||||
ISerializableEntity targetEntity;
|
||||
string target = subElement.GetAttributeString("target", null);
|
||||
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetEntity = character;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetEntity = this;
|
||||
}
|
||||
var conditionalSprite = new ConditionalSprite(subElement, targetEntity, file: GetSpritePath(subElement, null));
|
||||
var conditionalSprite = new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement, null));
|
||||
ConditionalSprites.Add(conditionalSprite);
|
||||
if (conditionalSprite.DeformableSprite != null)
|
||||
{
|
||||
@@ -300,7 +290,7 @@ namespace Barotrauma
|
||||
CreateDeformations(subElement);
|
||||
break;
|
||||
case "lightsource":
|
||||
LightSource = new LightSource(subElement)
|
||||
LightSource = new LightSource(subElement, GetConditionalTarget())
|
||||
{
|
||||
ParentBody = body,
|
||||
SpriteScale = Vector2.One * Scale * TextureScale
|
||||
@@ -310,6 +300,21 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
|
||||
ISerializableEntity GetConditionalTarget()
|
||||
{
|
||||
ISerializableEntity targetEntity;
|
||||
string target = subElement.GetAttributeString("target", null);
|
||||
if (string.Equals(target, "character", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
targetEntity = character;
|
||||
}
|
||||
else
|
||||
{
|
||||
targetEntity = this;
|
||||
}
|
||||
return targetEntity;
|
||||
}
|
||||
|
||||
void CreateDeformations(XElement e)
|
||||
{
|
||||
foreach (XElement animationElement in e.GetChildElements("spritedeformation"))
|
||||
@@ -341,6 +346,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
LightSource?.CheckConditionals();
|
||||
}
|
||||
|
||||
public void RecreateSprites()
|
||||
@@ -459,18 +465,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
float damageMultiplier = 1;
|
||||
float bleedingDamageMultiplier = 1;
|
||||
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
|
||||
{
|
||||
foreach (var afflictionPrefab in AfflictionPrefab.List)
|
||||
if (damageModifier.MatchesAfflictionType("damage"))
|
||||
{
|
||||
if (damageModifier.MatchesAffliction(afflictionPrefab.Identifier, afflictionPrefab.AfflictionType))
|
||||
{
|
||||
if (afflictionPrefab.Effects.Any(e => e.MaxVitalityDecrease > 0))
|
||||
{
|
||||
damageMultiplier *= damageModifier.DamageMultiplier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
damageMultiplier *= damageModifier.DamageMultiplier;
|
||||
}
|
||||
else if (damageModifier.MatchesAfflictionType("bleeding"))
|
||||
{
|
||||
bleedingDamageMultiplier *= damageModifier.DamageMultiplier;
|
||||
}
|
||||
}
|
||||
if (playSound)
|
||||
@@ -488,20 +492,29 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// spawn damage particles
|
||||
float damageParticleAmount = Math.Min(damage / 5, 1.0f) * damageMultiplier;
|
||||
float damageParticleAmount = damage < 1 ? 0 : Math.Min(damage / 5, 1.0f) * damageMultiplier;
|
||||
if (damageParticleAmount > 0.001f)
|
||||
{
|
||||
foreach (ParticleEmitter emitter in character.DamageEmitters)
|
||||
{
|
||||
if (inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Air) { continue; }
|
||||
if (!inWater && emitter.Prefab.ParticlePrefab.DrawTarget == ParticlePrefab.DrawTargetType.Water) { continue; }
|
||||
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount);
|
||||
ParticlePrefab overrideParticle = null;
|
||||
foreach (DamageModifier damageModifier in result.AppliedDamageModifiers)
|
||||
{
|
||||
if (damageModifier.DamageMultiplier > 0 && !string.IsNullOrWhiteSpace(damageModifier.DamageParticle))
|
||||
{
|
||||
overrideParticle = GameMain.ParticleManager?.FindPrefab(damageModifier.DamageParticle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
emitter.Emit(1.0f, WorldPosition, character.CurrentHull, amountMultiplier: damageParticleAmount, overrideParticle: overrideParticle);
|
||||
}
|
||||
}
|
||||
|
||||
if (bleedingDamage > 0)
|
||||
{
|
||||
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * damageMultiplier;
|
||||
float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * bleedingDamageMultiplier;
|
||||
float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f);
|
||||
|
||||
foreach (ParticleEmitter emitter in character.BloodEmitters)
|
||||
@@ -554,6 +567,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var conditionalSprite in ConditionalSprites)
|
||||
{
|
||||
conditionalSprite.CheckConditionals();
|
||||
}
|
||||
|
||||
if (LightSource != null)
|
||||
{
|
||||
LightSource.ParentSub = body.Submarine;
|
||||
@@ -566,6 +584,7 @@ namespace Barotrauma
|
||||
{
|
||||
LightSource.DeformableLightSprite.Sprite.Depth = ActiveSprite.Depth;
|
||||
}
|
||||
LightSource.CheckConditionals();
|
||||
}
|
||||
|
||||
UpdateSpriteStates(deltaTime);
|
||||
@@ -930,6 +949,10 @@ namespace Barotrauma
|
||||
{
|
||||
depth -= depthStep;
|
||||
}
|
||||
if (wearableItemComponent.AllowedSlots.Contains(InvSlotType.Bag))
|
||||
{
|
||||
depth -= depthStep * 2;
|
||||
}
|
||||
wearableColor = wearableItemComponent.Item.GetSpriteColor();
|
||||
}
|
||||
float textureScale = wearable.InheritTextureScale ? TextureScale : 1;
|
||||
|
||||
@@ -2575,7 +2575,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to spawn a submarine. Arguments: \"" + string.Join(" ", args) + "\".";
|
||||
ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
},
|
||||
() =>
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace Barotrauma
|
||||
|
||||
private static List<GUIButton> CreateConversation(GUIListBox parentBox, string text, Character speaker, IEnumerable<string> options, bool drawChathead = true)
|
||||
{
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, parentBox.Content.RectTransform), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||
var content = new GUILayoutGroup(new RectTransform(Vector2.One, parentBox.Content.RectTransform), childAnchor: Anchor.TopLeft, isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
CanBeFocused = true,
|
||||
@@ -289,7 +289,7 @@ namespace Barotrauma
|
||||
});
|
||||
}
|
||||
|
||||
var textContent = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), content.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
var textContent = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0f), content.RectTransform), childAnchor: Anchor.TopCenter)
|
||||
{
|
||||
AbsoluteSpacing = GUI.IntScale(5)
|
||||
};
|
||||
@@ -316,7 +316,7 @@ namespace Barotrauma
|
||||
content.Recalculate();
|
||||
textContent.Recalculate();
|
||||
textBlock.CalculateHeightFromText();
|
||||
textBlock.RectTransform.MinSize = new Point(0, (int)(textBlock.Rect.Height * 1.2f));
|
||||
textBlock.RectTransform.MinSize = new Point(0, textBlock.Rect.Height);
|
||||
foreach (GUIButton btn in buttons)
|
||||
{
|
||||
btn.TextBlock.SetTextPos();
|
||||
@@ -324,10 +324,12 @@ namespace Barotrauma
|
||||
btn.RectTransform.MinSize = new Point(0, (int)(btn.TextBlock.Rect.Height * 1.2f));
|
||||
}
|
||||
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height + textContent.AbsoluteSpacing) + GUI.IntScale(16));
|
||||
textContent.RectTransform.MinSize = new Point(0, textContent.Children.Sum(c => c.Rect.Height) + GUI.IntScale(16));
|
||||
content.RectTransform.MinSize = new Point(0, content.Children.Sum(c => c.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();
|
||||
textBlock.TextAlignment = Alignment.TopLeft;
|
||||
//content.RectTransform.MinSize = new Point(0, textContent.Rect.Height);
|
||||
|
||||
return buttons;
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace Barotrauma
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
SetChannel(radio.Channel - 1, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -142,7 +142,7 @@ namespace Barotrauma
|
||||
{
|
||||
int.TryParse(channelText.Text, out int newChannel);
|
||||
SetChannel(newChannel, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
};
|
||||
|
||||
var buttonRight = new GUIButton(new RectTransform(new Vector2(0.1f, 0.8f), channelSettingsContent.RectTransform), style: "DeviceButton")
|
||||
@@ -152,7 +152,7 @@ namespace Barotrauma
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
SetChannel(radio.Channel + 1, setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ namespace Barotrauma
|
||||
channelText.Flash(GUI.Style.Green);
|
||||
}
|
||||
SetChannel(radio.GetChannelMemory(index), setText: true);
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -469,7 +469,7 @@ namespace Barotrauma
|
||||
soundType = GUISoundType.DeadMessage;
|
||||
}
|
||||
|
||||
GUI.PlayUISound(soundType);
|
||||
SoundPlayer.PlayUISound(soundType);
|
||||
}
|
||||
|
||||
public void SetVisibility(bool visible)
|
||||
@@ -650,6 +650,8 @@ namespace Barotrauma
|
||||
if (Character.Controlled != null && ChatMessage.CanUseRadio(Character.Controlled, out WifiComponent radio))
|
||||
{
|
||||
radio.Channel = channel;
|
||||
GameMain.Client?.CreateEntityEvent(radio.Item, new object[] { NetEntityEvent.Type.ChangeProperty, radio.SerializableProperties["channel"] });
|
||||
|
||||
if (setText)
|
||||
{
|
||||
string text = radio.Channel.ToString().PadLeft(4, '0');
|
||||
|
||||
@@ -205,6 +205,7 @@ namespace Barotrauma
|
||||
};
|
||||
validateHiresButton = new GUIButton(new RectTransform(new Vector2(1.0f / 3.0f, 1.0f), group.RectTransform), text: TextManager.Get("campaigncrew.validate"))
|
||||
{
|
||||
ClickSound = GUISoundType.HireRepairClick,
|
||||
ForceUpperCase = true,
|
||||
OnClicked = (b, o) => ValidatePendingHires(true)
|
||||
};
|
||||
@@ -390,12 +391,29 @@ namespace Barotrauma
|
||||
|
||||
if (listBox == hireableList)
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
var hireButton = new GUIButton(new RectTransform(new Vector2(width, 0.9f), mainGroup.RectTransform), style: "CrewManagementAddButton")
|
||||
{
|
||||
UserData = characterInfo,
|
||||
Enabled = HasPermission,
|
||||
OnClicked = (b, o) => AddPendingHire(o as CharacterInfo)
|
||||
};
|
||||
hireButton.OnAddedToGUIUpdateList += (GUIComponent btn) =>
|
||||
{
|
||||
if (PendingHires.Count + campaign.CrewManager.GetCharacterInfos().Count() >= CrewManager.MaxCrewSize)
|
||||
{
|
||||
if (btn.Enabled)
|
||||
{
|
||||
btn.ToolTip = TextManager.Get("canthiremorecharacters");
|
||||
btn.Enabled = false;
|
||||
}
|
||||
}
|
||||
else if (!btn.Enabled)
|
||||
{
|
||||
btn.ToolTip = string.Empty;
|
||||
btn.Enabled = true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
else if (listBox == pendingList)
|
||||
{
|
||||
@@ -514,6 +532,11 @@ namespace Barotrauma
|
||||
|
||||
private bool AddPendingHire(CharacterInfo characterInfo, bool createNetworkMessage = true)
|
||||
{
|
||||
if (PendingHires.Count + campaign.CrewManager.GetCharacters().Count() >= CrewManager.MaxCrewSize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hireableList.Content.RemoveChild(hireableList.Content.FindChild(c => (c.UserData as Tuple<CharacterInfo, float>).Item1 == characterInfo));
|
||||
hireableList.UpdateScrollBarSize();
|
||||
if (!PendingHires.Contains(characterInfo)) { PendingHires.Add(characterInfo); }
|
||||
|
||||
@@ -27,7 +27,11 @@ namespace Barotrauma
|
||||
PickItem,
|
||||
PickItemFail,
|
||||
DropItem,
|
||||
PopupMenu
|
||||
PopupMenu,
|
||||
DecreaseQuantity,
|
||||
IncreaseQuantity,
|
||||
HireRepairClick,
|
||||
UISwitch
|
||||
}
|
||||
|
||||
public enum CursorState
|
||||
@@ -135,7 +139,7 @@ namespace Barotrauma
|
||||
public static GraphicsDevice GraphicsDevice { get; private set; }
|
||||
|
||||
private static List<GUIMessage> messages = new List<GUIMessage>();
|
||||
private static Sound[] sounds;
|
||||
private static readonly Dictionary<GUISoundType, string> soundIdentifiers = new Dictionary<GUISoundType, string>();
|
||||
private static bool pauseMenuOpen, settingsMenuOpen;
|
||||
public static GUIFrame PauseMenu { get; private set; }
|
||||
private static Sprite arrow;
|
||||
@@ -256,23 +260,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void LoadContent(bool loadSounds = true)
|
||||
public static void LoadContent()
|
||||
{
|
||||
if (loadSounds)
|
||||
foreach (GUISoundType soundType in Enum.GetValues(typeof(GUISoundType)))
|
||||
{
|
||||
sounds = new Sound[Enum.GetValues(typeof(GUISoundType)).Length];
|
||||
|
||||
sounds[(int)GUISoundType.UIMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/UImsg.ogg", false);
|
||||
sounds[(int)GUISoundType.ChatMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/ChatMsg.ogg", false);
|
||||
sounds[(int)GUISoundType.RadioMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/RadioMsg.ogg", false);
|
||||
sounds[(int)GUISoundType.DeadMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/DeadMsg.ogg", false);
|
||||
sounds[(int)GUISoundType.Click] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/Click.ogg", false);
|
||||
sounds[(int)GUISoundType.PopupMenu] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/PopupMenu.ogg", false);
|
||||
|
||||
sounds[(int)GUISoundType.PickItem] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItem.ogg", false);
|
||||
sounds[(int)GUISoundType.PickItemFail] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItemFail.ogg", false);
|
||||
sounds[(int)GUISoundType.DropItem] = GameMain.SoundManager.LoadSound("Content/Sounds/DropItem.ogg", false);
|
||||
soundIdentifiers.Add(soundType, soundType.ToString().ToLowerInvariant());
|
||||
}
|
||||
|
||||
// create 1x1 texture for line drawing
|
||||
CrossThread.RequestExecutionOnMainThread(() =>
|
||||
{
|
||||
@@ -314,7 +308,7 @@ namespace Barotrauma
|
||||
|
||||
#if UNSTABLE
|
||||
string line1 = "Barotrauma Unstable v" + GameMain.Version;
|
||||
string line2 = "(" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")";
|
||||
string line2 = "(" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
|
||||
|
||||
Rectangle watermarkRect = new Rectangle(-50, GameMain.GraphicsHeight - 80, 50 + (int)(Math.Max(LargeFont.MeasureString(line1).X, Font.MeasureString(line2).X) * 1.2f), 100);
|
||||
float alpha = 1.0f;
|
||||
@@ -2282,13 +2276,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (messages.Any(msg => msg.Text == message)) { return; }
|
||||
messages.Add(new GUIMessage(message, color, lifeTime ?? MathHelper.Clamp(message.Length / 5.0f, 3.0f, 10.0f), font ?? LargeFont));
|
||||
if (playSound) PlayUISound(GUISoundType.UIMessage);
|
||||
if (playSound) SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
}
|
||||
|
||||
public static void AddMessage(string message, Color color, Vector2 worldPos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true)
|
||||
public static void AddMessage(string message, Color color, Vector2 worldPos, Vector2 velocity, float lifeTime = 3.0f, bool playSound = true, GUISoundType soundType = GUISoundType.UIMessage)
|
||||
{
|
||||
messages.Add(new GUIMessage(message, color, worldPos, velocity, lifeTime, Alignment.Center, LargeFont));
|
||||
if (playSound) PlayUISound(GUISoundType.UIMessage);
|
||||
if (playSound) SoundPlayer.PlayUISound(soundType);
|
||||
}
|
||||
|
||||
public static void ClearMessages()
|
||||
@@ -2296,16 +2290,6 @@ namespace Barotrauma
|
||||
messages.Clear();
|
||||
}
|
||||
|
||||
public static void PlayUISound(GUISoundType soundType)
|
||||
{
|
||||
if (sounds == null) { return; }
|
||||
|
||||
int soundIndex = (int)soundType;
|
||||
if (soundIndex < 0 || soundIndex >= sounds.Length) { return; }
|
||||
|
||||
sounds[soundIndex]?.Play(null, "ui");
|
||||
}
|
||||
|
||||
public static bool IsFourByThree()
|
||||
{
|
||||
float aspectRatio = HorizontalAspectRatio;
|
||||
|
||||
@@ -157,6 +157,8 @@ namespace Barotrauma
|
||||
private float pulseTimer;
|
||||
private float pulseExpand;
|
||||
private bool flashed;
|
||||
|
||||
public GUISoundType ClickSound { get; set; } = GUISoundType.Click;
|
||||
|
||||
public GUIButton(RectTransform rectT, string text = "", Alignment textAlignment = Alignment.Center, string style = "", Color? color = null) : base(style, rectT)
|
||||
{
|
||||
@@ -247,7 +249,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (PlayerInput.PrimaryMouseButtonClicked())
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.Click);
|
||||
SoundPlayer.PlayUISound(ClickSound);
|
||||
if (OnClicked != null)
|
||||
{
|
||||
if (OnClicked(this, UserData))
|
||||
|
||||
@@ -404,7 +404,7 @@ namespace Barotrauma
|
||||
/// <param name="component"></param>
|
||||
public void ScrollToElement(GUIComponent component)
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.Click);
|
||||
SoundPlayer.PlayUISound(GUISoundType.Click);
|
||||
List<GUIComponent> children = Content.Children.ToList();
|
||||
int index = children.IndexOf(component);
|
||||
if (index < 0) { return; }
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace Barotrauma
|
||||
|
||||
public GUITextBox TextBox { get; private set; }
|
||||
|
||||
private GUIButton plusButton, minusButton;
|
||||
public GUIButton PlusButton { get; private set; }
|
||||
public GUIButton MinusButton { get; private set; }
|
||||
|
||||
private NumberType inputType;
|
||||
public NumberType InputType
|
||||
@@ -142,14 +143,14 @@ namespace Barotrauma
|
||||
get => base.Enabled;
|
||||
set
|
||||
{
|
||||
plusButton.Enabled = true;
|
||||
minusButton.Enabled = true;
|
||||
PlusButton.Enabled = true;
|
||||
MinusButton.Enabled = true;
|
||||
if (InputType == NumberType.Int) { ClampIntValue(); } else { ClampFloatValue(); }
|
||||
TextBox.Enabled = value;
|
||||
if (!value)
|
||||
{
|
||||
plusButton.Enabled = false;
|
||||
minusButton.Enabled = false;
|
||||
PlusButton.Enabled = false;
|
||||
MinusButton.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,19 +194,19 @@ namespace Barotrauma
|
||||
TextBox.OnTextChanged += TextChanged;
|
||||
|
||||
var buttonArea = new GUIFrame(new RectTransform(new Vector2(_relativeButtonAreaWidth, 1.0f), LayoutGroup.RectTransform, Anchor.CenterRight), style: null);
|
||||
plusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), style: null);
|
||||
GUI.Style.Apply(plusButton, "PlusButton", this);
|
||||
plusButton.OnButtonDown += () =>
|
||||
PlusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform), style: null);
|
||||
GUI.Style.Apply(PlusButton, "PlusButton", this);
|
||||
PlusButton.OnButtonDown += () =>
|
||||
{
|
||||
pressedTimer = pressedDelay;
|
||||
return true;
|
||||
};
|
||||
plusButton.OnClicked += (button, data) =>
|
||||
PlusButton.OnClicked += (button, data) =>
|
||||
{
|
||||
IncreaseValue();
|
||||
return true;
|
||||
};
|
||||
plusButton.OnPressed += () =>
|
||||
PlusButton.OnPressed += () =>
|
||||
{
|
||||
if (!IsPressedTimerRunning)
|
||||
{
|
||||
@@ -214,19 +215,19 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
minusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), style: null);
|
||||
GUI.Style.Apply(minusButton, "MinusButton", this);
|
||||
minusButton.OnButtonDown += () =>
|
||||
MinusButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.5f), buttonArea.RectTransform, Anchor.BottomRight), style: null);
|
||||
GUI.Style.Apply(MinusButton, "MinusButton", this);
|
||||
MinusButton.OnButtonDown += () =>
|
||||
{
|
||||
pressedTimer = pressedDelay;
|
||||
return true;
|
||||
};
|
||||
minusButton.OnClicked += (button, data) =>
|
||||
MinusButton.OnClicked += (button, data) =>
|
||||
{
|
||||
ReduceValue();
|
||||
return true;
|
||||
};
|
||||
minusButton.OnPressed += () =>
|
||||
MinusButton.OnPressed += () =>
|
||||
{
|
||||
if (!IsPressedTimerRunning)
|
||||
{
|
||||
@@ -279,17 +280,17 @@ namespace Barotrauma
|
||||
|
||||
private void HidePlusMinusButtons()
|
||||
{
|
||||
plusButton.Parent.Visible = false;
|
||||
plusButton.Parent.IgnoreLayoutGroups = true;
|
||||
PlusButton.Parent.Visible = false;
|
||||
PlusButton.Parent.IgnoreLayoutGroups = true;
|
||||
TextBox.RectTransform.RelativeSize = Vector2.One;
|
||||
LayoutGroup.Recalculate();
|
||||
}
|
||||
|
||||
private void ShowPlusMinusButtons()
|
||||
{
|
||||
plusButton.Parent.Visible = true;
|
||||
plusButton.Parent.IgnoreLayoutGroups = false;
|
||||
TextBox.RectTransform.RelativeSize = new Vector2(1.0f - plusButton.Parent.RectTransform.RelativeSize.X, 1.0f);
|
||||
PlusButton.Parent.Visible = true;
|
||||
PlusButton.Parent.IgnoreLayoutGroups = false;
|
||||
TextBox.RectTransform.RelativeSize = new Vector2(1.0f - PlusButton.Parent.RectTransform.RelativeSize.X, 1.0f);
|
||||
LayoutGroup.Recalculate();
|
||||
}
|
||||
|
||||
@@ -369,12 +370,12 @@ namespace Barotrauma
|
||||
if (MinValueFloat != null)
|
||||
{
|
||||
floatValue = Math.Max(floatValue, MinValueFloat.Value);
|
||||
minusButton.Enabled = floatValue > MinValueFloat;
|
||||
MinusButton.Enabled = floatValue > MinValueFloat;
|
||||
}
|
||||
if (MaxValueFloat != null)
|
||||
{
|
||||
floatValue = Math.Min(floatValue, MaxValueFloat.Value);
|
||||
plusButton.Enabled = floatValue < MaxValueFloat;
|
||||
PlusButton.Enabled = floatValue < MaxValueFloat;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,8 +391,8 @@ namespace Barotrauma
|
||||
intValue = Math.Min(intValue, MaxValueInt.Value);
|
||||
UpdateText();
|
||||
}
|
||||
plusButton.Enabled = intValue < MaxValueInt;
|
||||
minusButton.Enabled = intValue > MinValueInt;
|
||||
PlusButton.Enabled = intValue < MaxValueInt;
|
||||
MinusButton.Enabled = intValue > MinValueInt;
|
||||
}
|
||||
|
||||
private void UpdateText()
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GUIProgressBar.BarSize_setter",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Attempted to set the BarSize of a GUIProgressBar to an invalid value (" + value + ")\n" + Environment.StackTrace);
|
||||
"Attempted to set the BarSize of a GUIProgressBar to an invalid value (" + value + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
barSize = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
@@ -106,7 +106,7 @@ namespace Barotrauma
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GUIProgressBar.Draw:GetProgress",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace);
|
||||
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -664,7 +664,7 @@ namespace Barotrauma
|
||||
case (char)0x1: // ctrl-a
|
||||
SelectAll();
|
||||
break;
|
||||
case (char)0x1A when !Readonly: // ctrl-z
|
||||
case (char)0x1A when !Readonly && !SubEditorScreen.IsSubEditor(): // ctrl-z
|
||||
text = memento.Undo();
|
||||
if (text != Text)
|
||||
{
|
||||
@@ -674,7 +674,7 @@ namespace Barotrauma
|
||||
OnTextChanged?.Invoke(this, Text);
|
||||
}
|
||||
break;
|
||||
case (char)0x12 when !Readonly: // ctrl-r
|
||||
case (char)0x12 when !Readonly && !SubEditorScreen.IsSubEditor(): // ctrl-r
|
||||
text = memento.Redo();
|
||||
if (text != Text)
|
||||
{
|
||||
|
||||
@@ -348,7 +348,7 @@ namespace Barotrauma
|
||||
spriteBatch.Draw(currSplashScreen.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
|
||||
spriteBatch.End();
|
||||
|
||||
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
|
||||
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Escape) || PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
|
||||
{
|
||||
currSplashScreen.Dispose(); currSplashScreen = null;
|
||||
}
|
||||
|
||||
@@ -519,7 +519,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (displayErrors)
|
||||
{
|
||||
DebugConsole.ThrowError("Parent null" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Parent null" + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -527,7 +527,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (displayErrors)
|
||||
{
|
||||
DebugConsole.ThrowError("The children of the parent does not contain this child. This should not be possible! " + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("The children of the parent does not contain this child. This should not be possible! " + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -535,7 +535,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (displayErrors)
|
||||
{
|
||||
DebugConsole.ThrowError("Unable to remove the child from the parent. " + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Unable to remove the child from the parent. " + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -31,9 +32,13 @@ namespace Barotrauma
|
||||
private GUITextBlock shoppingCrateTotal;
|
||||
private GUIButton clearAllButton, confirmButton;
|
||||
|
||||
private bool needsRefresh, needsBuyingRefresh, needsSellingRefresh, needsItemsToSellRefresh;
|
||||
|
||||
private Point resolutionWhenCreated;
|
||||
private bool hadPermissions;
|
||||
|
||||
private Dictionary<ItemPrefab, int> OwnedItems { get; } = new Dictionary<ItemPrefab, int>();
|
||||
|
||||
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
|
||||
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
|
||||
private int PlayerMoney => campaignUI.Campaign.Money;
|
||||
@@ -70,27 +75,30 @@ namespace Barotrauma
|
||||
campaignUI.Campaign.Map.OnLocationChanged += UpdateLocation;
|
||||
if (CurrentLocation?.Reputation != null)
|
||||
{
|
||||
CurrentLocation.Reputation.OnReputationValueChanged += Refresh;
|
||||
CurrentLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += RefreshBuying;
|
||||
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += RefreshBuying;
|
||||
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += RefreshSelling;
|
||||
campaignUI.Campaign.CargoManager.OnItemsInBuyCrateChanged += () => { needsBuyingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnPurchasedItemsChanged += () => { needsBuyingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnItemsInSellCrateChanged += () => { needsSellingRefresh = true; };
|
||||
campaignUI.Campaign.CargoManager.OnSoldItemsChanged += () =>
|
||||
{
|
||||
RefreshItemsToSell();
|
||||
RefreshSelling();
|
||||
needsItemsToSellRefresh = true;
|
||||
needsSellingRefresh = true;
|
||||
};
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
hadPermissions = HasPermissions;
|
||||
RefreshBuying();
|
||||
RefreshSelling();
|
||||
UpdateOwnedItems();
|
||||
RefreshBuying(updateOwned: false);
|
||||
RefreshSelling(updateOwned: false);
|
||||
needsRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshBuying()
|
||||
private void RefreshBuying(bool updateOwned = true)
|
||||
{
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshShoppingCrateBuyList();
|
||||
//RefreshStoreDealsList();
|
||||
RefreshStoreBuyList();
|
||||
@@ -98,15 +106,18 @@ namespace Barotrauma
|
||||
//storeDealsList.Enabled = hasPermissions;
|
||||
storeBuyList.Enabled = hasPermissions;
|
||||
shoppingCrateBuyList.Enabled = hasPermissions;
|
||||
needsBuyingRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshSelling()
|
||||
private void RefreshSelling(bool updateOwned = true)
|
||||
{
|
||||
if (updateOwned) { UpdateOwnedItems(); }
|
||||
RefreshShoppingCrateSellList();
|
||||
RefreshStoreSellList();
|
||||
var hasPermissions = HasPermissions;
|
||||
storeSellList.Enabled = hasPermissions;
|
||||
shoppingCrateSellList.Enabled = hasPermissions;
|
||||
needsSellingRefresh = false;
|
||||
}
|
||||
|
||||
private void CreateUI()
|
||||
@@ -400,6 +411,7 @@ namespace Barotrauma
|
||||
SetConfirmButtonBehavior();
|
||||
clearAllButton = new GUIButton(new RectTransform(new Vector2(0.35f, 1.0f), buttonContainer.RectTransform), TextManager.Get("campaignstore.clearall"))
|
||||
{
|
||||
ClickSound = GUISoundType.DecreaseQuantity,
|
||||
Enabled = HasPermissions,
|
||||
ForceUpperCase = true,
|
||||
OnClicked = (button, userData) =>
|
||||
@@ -422,7 +434,7 @@ namespace Barotrauma
|
||||
|
||||
if (prevLocation?.Reputation != null)
|
||||
{
|
||||
prevLocation.Reputation.OnReputationValueChanged -= Refresh;
|
||||
prevLocation.Reputation.OnReputationValueChanged = null;
|
||||
}
|
||||
|
||||
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
|
||||
@@ -432,7 +444,7 @@ namespace Barotrauma
|
||||
ChangeStoreTab(StoreTab.Buy);
|
||||
if (newLocation?.Reputation != null)
|
||||
{
|
||||
newLocation.Reputation.OnReputationValueChanged += Refresh;
|
||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -535,6 +547,7 @@ namespace Barotrauma
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
|
||||
SetQuantityLabelText(StoreTab.Buy, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions && quantity > 0);
|
||||
}
|
||||
existingItemFrames.Add(itemFrame);
|
||||
@@ -575,6 +588,7 @@ namespace Barotrauma
|
||||
{
|
||||
(itemFrame.UserData as PurchasedItem).Quantity = quantity;
|
||||
SetQuantityLabelText(StoreTab.Sell, itemFrame);
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions);
|
||||
}
|
||||
if (quantity < 1) { itemFrame.Visible = false; }
|
||||
@@ -617,6 +631,7 @@ namespace Barotrauma
|
||||
CargoManager.ModifyItemQuantityInSellCrate(crateItem.ItemPrefab, playerItemQuantity - crateItem.Quantity);
|
||||
}
|
||||
}
|
||||
needsItemsToSellRefresh = false;
|
||||
}
|
||||
|
||||
private void RefreshShoppingCrateList(List<PurchasedItem> items, GUIListBox listBox)
|
||||
@@ -645,6 +660,7 @@ namespace Barotrauma
|
||||
numInput.UserData = item;
|
||||
numInput.Enabled = hasPermissions;
|
||||
}
|
||||
SetOwnedLabelText(itemFrame);
|
||||
SetItemFrameStatus(itemFrame, hasPermissions);
|
||||
}
|
||||
existingItemFrames.Add(itemFrame);
|
||||
@@ -740,7 +756,7 @@ namespace Barotrauma
|
||||
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")
|
||||
GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.yScale * 80)), parent: listBox.Content.RectTransform), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = tooltip,
|
||||
UserData = pi
|
||||
@@ -775,7 +791,7 @@ namespace Barotrauma
|
||||
CanBeFocused = false,
|
||||
Stretch = true
|
||||
};
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndQuantityGroup.RectTransform),
|
||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
|
||||
pi.ItemPrefab.Name, font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
@@ -783,11 +799,12 @@ namespace Barotrauma
|
||||
TextScale = 0.85f,
|
||||
UserData = "name"
|
||||
};
|
||||
GUILayoutGroup shoppingCrateAmountGroup = null;
|
||||
GUINumberInput amountInput = null;
|
||||
if (listBox == storeBuyList || listBox == storeSellList)
|
||||
{
|
||||
var block = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), nameAndQuantityGroup.RectTransform),
|
||||
CreateQuantityLabelText(listBox == storeSellList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.TopLeft)
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.3f), nameAndQuantityGroup.RectTransform),
|
||||
CreateQuantityLabelText(listBox == storeSellList ? StoreTab.Sell : StoreTab.Buy, pi.Quantity), font: GUI.Font, textAlignment: Alignment.BottomLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
@@ -797,7 +814,13 @@ namespace Barotrauma
|
||||
}
|
||||
else if (listBox == shoppingCrateBuyList || listBox == shoppingCrateSellList)
|
||||
{
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.5f), nameAndQuantityGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
var relativePadding = nameBlock.Padding.X / nameBlock.Rect.Width;
|
||||
shoppingCrateAmountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativePadding, 0.6f), nameAndQuantityGroup.RectTransform) { RelativeOffset = new Vector2(relativePadding, 0) },
|
||||
isHorizontal: true)
|
||||
{
|
||||
RelativeSpacing = 0.02f
|
||||
};
|
||||
amountInput = new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), shoppingCrateAmountGroup.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = GetMaxAvailable(pi.ItemPrefab, listBox == shoppingCrateBuyList ? StoreTab.Buy : StoreTab.Sell),
|
||||
@@ -818,9 +841,25 @@ namespace Barotrauma
|
||||
}
|
||||
AddToShoppingCrate(purchasedItem, quantity: numberInput.IntValue - purchasedItem.Quantity);
|
||||
};
|
||||
amountInput.PlusButton.ClickSound = GUISoundType.IncreaseQuantity;
|
||||
amountInput.MinusButton.ClickSound = GUISoundType.DecreaseQuantity;
|
||||
frame.HoverColor = frame.SelectedColor = Color.Transparent;
|
||||
}
|
||||
|
||||
// Amount in players' inventories and on the sub
|
||||
var rectTransform = shoppingCrateAmountGroup == null ?
|
||||
new RectTransform(new Vector2(1.0f, 0.3f), nameAndQuantityGroup.RectTransform) :
|
||||
new RectTransform(new Vector2(0.6f, 1.0f), shoppingCrateAmountGroup.RectTransform);
|
||||
new GUITextBlock(rectTransform, CreateOwnedLabelText(OwnedItems.GetValueOrDefault(pi.ItemPrefab, 0)), font: GUI.Font,
|
||||
textAlignment: shoppingCrateAmountGroup == null ? Alignment.TopLeft : Alignment.CenterLeft)
|
||||
{
|
||||
CanBeFocused = false,
|
||||
TextColor = Color.White * (forceDisable ? 0.5f : 1.0f),
|
||||
TextScale = 0.85f,
|
||||
UserData = "owned"
|
||||
};
|
||||
shoppingCrateAmountGroup?.Recalculate();
|
||||
|
||||
var buttonRelativeWidth = (0.9f * mainGroup.Rect.Height) / mainGroup.Rect.Width;
|
||||
|
||||
var priceBlock = new GUITextBlock(new RectTransform(new Vector2(priceAndButtonRelativeWidth - buttonRelativeWidth, 1.0f), mainGroup.RectTransform), "", font: GUI.SubHeadingFont, textAlignment: Alignment.Right)
|
||||
@@ -842,6 +881,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreAddToCrateButton")
|
||||
{
|
||||
ClickSound = GUISoundType.IncreaseQuantity,
|
||||
Enabled = !forceDisable && pi.Quantity > 0,
|
||||
ForceUpperCase = true,
|
||||
UserData = "addbutton",
|
||||
@@ -852,6 +892,7 @@ namespace Barotrauma
|
||||
{
|
||||
new GUIButton(new RectTransform(new Vector2(buttonRelativeWidth, 0.9f), mainGroup.RectTransform), style: "StoreRemoveFromCrateButton")
|
||||
{
|
||||
ClickSound = GUISoundType.DecreaseQuantity,
|
||||
Enabled = !forceDisable,
|
||||
ForceUpperCase = true,
|
||||
UserData = "removebutton",
|
||||
@@ -869,6 +910,39 @@ namespace Barotrauma
|
||||
return frame;
|
||||
}
|
||||
|
||||
private void UpdateOwnedItems()
|
||||
{
|
||||
OwnedItems.Clear();
|
||||
|
||||
// Add items on the sub(s)
|
||||
Submarine.MainSub?.GetItems(true)
|
||||
.Where(i => i.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached) &&
|
||||
i.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null)))
|
||||
.ForEach(i => AddToOwnedItems(i.Prefab));
|
||||
|
||||
// Add items in character inventories
|
||||
foreach (Character c in GameMain.GameSession.CrewManager.GetCharacters())
|
||||
{
|
||||
Item.ItemList.Where(i => i != null && i.GetRootInventoryOwner() == c)
|
||||
.ForEach(i => AddToOwnedItems(i.Prefab));
|
||||
}
|
||||
|
||||
// Add items already purchased
|
||||
CargoManager?.PurchasedItems?.ForEach(pi => AddToOwnedItems(pi.ItemPrefab, amount: pi.Quantity));
|
||||
|
||||
void AddToOwnedItems(ItemPrefab itemPrefab, int amount = 1)
|
||||
{
|
||||
if (OwnedItems.ContainsKey(itemPrefab))
|
||||
{
|
||||
OwnedItems[itemPrefab] += amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
OwnedItems.Add(itemPrefab, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetItemFrameStatus(GUIComponent itemFrame, bool enabled)
|
||||
{
|
||||
if (itemFrame == null || !(itemFrame.UserData is PurchasedItem pi)) { return; }
|
||||
@@ -901,6 +975,11 @@ namespace Barotrauma
|
||||
numberInput.Enabled = enabled;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("owned", recursive: true) is GUITextBlock owned)
|
||||
{
|
||||
owned.TextColor = color;
|
||||
}
|
||||
|
||||
if (itemFrame.FindChild("price", recursive: true) is GUITextBlock price)
|
||||
{
|
||||
price.TextColor = color;
|
||||
@@ -918,7 +997,8 @@ namespace Barotrauma
|
||||
|
||||
private void SetQuantityLabelText(StoreTab mode, GUIComponent itemFrame)
|
||||
{
|
||||
if (itemFrame?.FindChild("quantitylabel", recursive: true) is GUITextBlock label)
|
||||
if (itemFrame == null) { return; }
|
||||
if (itemFrame.FindChild("quantitylabel", recursive: true) is GUITextBlock label)
|
||||
{
|
||||
label.Text = CreateQuantityLabelText(mode, (itemFrame.UserData as PurchasedItem).Quantity);
|
||||
}
|
||||
@@ -928,6 +1008,23 @@ namespace Barotrauma
|
||||
TextManager.GetWithVariable("campaignstore.quantity", "[amount]", quantity.ToString()) :
|
||||
TextManager.GetWithVariable("campaignstore.instock", "[amount]", quantity.ToString());
|
||||
|
||||
private void SetOwnedLabelText(GUIComponent itemComponent)
|
||||
{
|
||||
if (itemComponent == null) { return; }
|
||||
var itemCount = 0;
|
||||
if (itemComponent.UserData is PurchasedItem pi)
|
||||
{
|
||||
itemCount = OwnedItems.GetValueOrDefault(pi.ItemPrefab, itemCount);
|
||||
}
|
||||
if (itemComponent.FindChild("owned", recursive: true) is GUITextBlock label)
|
||||
{
|
||||
label.Text = CreateOwnedLabelText(itemCount);
|
||||
}
|
||||
}
|
||||
|
||||
private string CreateOwnedLabelText(int itemCount) => itemCount > 0 ?
|
||||
TextManager.GetWithVariable("campaignstore.owned", "[amount]", itemCount.ToString()) : "";
|
||||
|
||||
private int GetMaxAvailable(ItemPrefab itemPrefab, StoreTab mode)
|
||||
{
|
||||
var list = mode == StoreTab.Sell ? itemsToSell : CurrentLocation.StoreStock;
|
||||
@@ -1103,11 +1200,12 @@ namespace Barotrauma
|
||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||
{
|
||||
CreateUI();
|
||||
needsRefresh = false;
|
||||
}
|
||||
else if (hadPermissions != HasPermissions)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
if (needsRefresh || hadPermissions != HasPermissions) { Refresh(); }
|
||||
if (needsBuyingRefresh) { RefreshBuying(); }
|
||||
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
|
||||
if (needsSellingRefresh) { RefreshSelling(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUI.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
||||
new GUITextBlock(rectT(1, 0, textLayout), FormatCurrency(price));
|
||||
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { Enabled = Campaign.Money >= price && !isDisabled, OnClicked = onPressed };
|
||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = Campaign.Money >= price && !isDisabled, OnClicked = onPressed };
|
||||
contentLayout.Recalculate();
|
||||
buyButtonLayout.Recalculate();
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace Barotrauma
|
||||
if (gameSession == value) { return; }
|
||||
if (value == null && Screen.Selected == GameScreen && gameSession.GameMode is CampaignMode)
|
||||
{
|
||||
DebugConsole.AddWarning("GameSession set to null while in the game screen\n" + Environment.StackTrace);
|
||||
DebugConsole.AddWarning("GameSession set to null while in the game screen\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
if (gameSession?.GameMode != null && gameSession.GameMode != value?.GameMode)
|
||||
{
|
||||
@@ -669,7 +669,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect invitation command ({connectCommand})", e);
|
||||
#else
|
||||
DebugConsole.Log($"Failed to parse a Steam friend's connect invitation command ({connectCommand})\n" + e.StackTrace);
|
||||
DebugConsole.Log($"Failed to parse a Steam friend's connect invitation command ({connectCommand})\n" + e.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
ConnectName = null;
|
||||
ConnectEndpoint = null;
|
||||
|
||||
@@ -52,11 +52,11 @@ namespace Barotrauma
|
||||
i.GetRootInventoryOwner() == character &&
|
||||
!i.SpawnedInOutpost &&
|
||||
(i.ContainedItems == null || i.ContainedItems.None() || i.ContainedItems.All(ci => soldEntities.Any(se => se.Item == ci))) &&
|
||||
i.Condition >= 0.9f * i.MaxCondition && soldEntities.None(se => se.Item == i));
|
||||
(i.Condition >= 0.9f * i.MaxCondition || i.Prefab.AllowSellingWhenBroken) && soldEntities.None(se => se.Item == i));
|
||||
|
||||
// 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 equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
|
||||
foreach (InvSlotType slot in equipmentSlots)
|
||||
{
|
||||
var index = character.Inventory.FindLimbSlot(slot);
|
||||
if (character.Inventory.Items[index] is Item item)
|
||||
@@ -69,18 +69,27 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// Prevent selling items contained inside equipped items
|
||||
foreach (InvSlotType slot in equipmentSlots)
|
||||
{
|
||||
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)
|
||||
RemoveContainedFromSellables(item);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveContainedFromSellables(Item item)
|
||||
{
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
if (containedItem == null) { continue; }
|
||||
if (containedItem.ContainedItems != null)
|
||||
{
|
||||
sellables.Remove(containedItem);
|
||||
RemoveContainedFromSellables(containedItem);
|
||||
}
|
||||
sellables.Remove(containedItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Barotrauma
|
||||
private GUIListBox crewList;
|
||||
private GUIButton commandButton, toggleCrewButton;
|
||||
private float crewListOpenState;
|
||||
private bool toggleCrewListOpen = true;
|
||||
private bool _isCrewMenuOpen = true;
|
||||
private Point crewListEntrySize;
|
||||
|
||||
private GUIFrame contextMenu;
|
||||
@@ -42,16 +42,26 @@ namespace Barotrauma
|
||||
|
||||
public bool AllowCharacterSwitch = true;
|
||||
|
||||
public bool ToggleCrewListOpen
|
||||
/// <summary>
|
||||
/// This property stores the preference in settings. Don't use for automatic logic.
|
||||
/// Use AutoShowCrewList(), AutoHideCrewList(), and ResetCrewList().
|
||||
/// </summary>
|
||||
public bool IsCrewMenuOpen
|
||||
{
|
||||
get { return toggleCrewListOpen; }
|
||||
get { return _isCrewMenuOpen; }
|
||||
set
|
||||
{
|
||||
if (toggleCrewListOpen == value) { return; }
|
||||
toggleCrewListOpen = GameMain.Config.CrewMenuOpen = value;
|
||||
if (_isCrewMenuOpen == value) { return; }
|
||||
_isCrewMenuOpen = GameMain.Config.CrewMenuOpen = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AutoShowCrewList() => _isCrewMenuOpen = true;
|
||||
|
||||
public void AutoHideCrewList() => _isCrewMenuOpen = false;
|
||||
|
||||
public void ResetCrewList() => _isCrewMenuOpen = GameMain.Config.CrewMenuOpen;
|
||||
|
||||
const float CommandNodeAnimDuration = 0.2f;
|
||||
|
||||
public List<GUIButton> OrderOptionButtons = new List<GUIButton>();
|
||||
@@ -139,7 +149,7 @@ namespace Barotrauma
|
||||
{
|
||||
OnClicked = (GUIButton btn, object userdata) =>
|
||||
{
|
||||
ToggleCrewListOpen = !ToggleCrewListOpen;
|
||||
IsCrewMenuOpen = !IsCrewMenuOpen;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -251,12 +261,7 @@ namespace Barotrauma
|
||||
var sub = Character.Controlled.Submarine;
|
||||
if (sub == null || sub.TeamID != Character.Controlled.TeamID || sub.Info.IsWreck) { return false; }
|
||||
SetCharacterOrder(null, order, null, Character.Controlled);
|
||||
var visibleHulls = new List<Hull>(Character.Controlled.GetVisibleHulls());
|
||||
foreach (var hull in visibleHulls)
|
||||
{
|
||||
HumanAIController.PropagateHullSafety(Character.Controlled, hull);
|
||||
HumanAIController.RefreshTargets(Character.Controlled, order, hull);
|
||||
}
|
||||
if (IsSinglePlayer) { HumanAIController.ReportProblem(Character.Controlled, order); }
|
||||
return true;
|
||||
},
|
||||
UserData = order,
|
||||
@@ -286,7 +291,7 @@ namespace Barotrauma
|
||||
|
||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
prevUIScale = GUI.Scale;
|
||||
ToggleCrewListOpen = GameMain.Config.CrewMenuOpen;
|
||||
_isCrewMenuOpen = GameMain.Config.CrewMenuOpen;
|
||||
dismissedOrderPrefab ??= Order.GetPrefab("dismissed");
|
||||
}
|
||||
|
||||
@@ -318,7 +323,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (character == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Tried to remove a null character from CrewManager.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
characters.Remove(character);
|
||||
@@ -567,7 +572,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!IsSinglePlayer)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(text)) { return; }
|
||||
@@ -583,7 +588,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (!IsSinglePlayer)
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Cannot add messages to single player chat box in multiplayer mode!\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
if (string.IsNullOrEmpty(message.Text)) { return; }
|
||||
@@ -675,8 +680,7 @@ namespace Barotrauma
|
||||
AddOrder(new Order(order.Prefab ?? order, hull, null, orderGiver), order.FadeOutTime);
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
orderGiver.Speak(
|
||||
order.GetChatMessage("", hull.DisplayName, givingOrderToSelf: character == orderGiver), ChatMessageType.Order);
|
||||
orderGiver.Speak(order.GetChatMessage("", hull.DisplayName, givingOrderToSelf: character == orderGiver), ChatMessageType.Order);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -692,12 +696,11 @@ namespace Barotrauma
|
||||
if (IsSinglePlayer)
|
||||
{
|
||||
character.SetOrder(order, option, orderGiver, speak: orderGiver != character);
|
||||
orderGiver?.Speak(
|
||||
order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
|
||||
orderGiver?.Speak(order.GetChatMessage(character.Name, orderGiver.CurrentHull?.DisplayName, givingOrderToSelf: character == orderGiver, orderOption: option), null);
|
||||
}
|
||||
else if (orderGiver != null)
|
||||
{
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, order?.TargetEntity ?? order?.TargetItemComponent?.Item, character, orderGiver);
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item as ISpatialEntity, character, orderGiver);
|
||||
GameMain.Client?.SendChatMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -1290,7 +1293,7 @@ namespace Barotrauma
|
||||
{
|
||||
CreateCommandUI(HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) ? Character.Controlled : GUI.MouseOn?.UserData as Character);
|
||||
}
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
clicklessSelectionActive = isOpeningClick = true;
|
||||
}
|
||||
|
||||
@@ -1524,14 +1527,15 @@ namespace Barotrauma
|
||||
new Vector2(-crewArea.Rect.Width - HUDLayoutSettings.Padding, 0.0f),
|
||||
Vector2.Zero,
|
||||
crewListOpenState).ToPoint();
|
||||
crewListOpenState = ToggleCrewListOpen ?
|
||||
|
||||
crewListOpenState = IsCrewMenuOpen ?
|
||||
Math.Min(crewListOpenState + deltaTime * 2.0f, 1.0f) :
|
||||
Math.Max(crewListOpenState - deltaTime * 2.0f, 0.0f);
|
||||
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null && PlayerInput.KeyHit(InputType.CrewOrders))
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PopupMenu);
|
||||
ToggleCrewListOpen = !ToggleCrewListOpen;
|
||||
SoundPlayer.PlayUISound(GUISoundType.PopupMenu);
|
||||
IsCrewMenuOpen = !IsCrewMenuOpen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1589,8 +1593,8 @@ namespace Barotrauma
|
||||
private Hull hullContext;
|
||||
private bool isContextual;
|
||||
private readonly List<Order> contextualOrders = new List<Order>();
|
||||
private Point shortcutCenterNodeOffset;
|
||||
private const int maxShortcutNodeCount = 4;
|
||||
private Point shorcutCenterNodeOffset;
|
||||
private const int maxShortCutNodeCount = 4;
|
||||
|
||||
private bool WasCommandInterfaceDisabledThisUpdate { get; set; }
|
||||
private bool CanIssueOrders
|
||||
@@ -1773,7 +1777,7 @@ namespace Barotrauma
|
||||
returnNodeMargin = returnNodeSize.X * 0.5f;
|
||||
|
||||
nodeDistance = (int)(150 * GUI.Scale);
|
||||
shortcutCenterNodeOffset = new Point(0, (int)(1.25f * nodeDistance));
|
||||
shorcutCenterNodeOffset = new Point(0, (int)(1.25f * nodeDistance));
|
||||
}
|
||||
|
||||
private List<OrderCategory> GetAvailableCategories()
|
||||
@@ -2057,7 +2061,7 @@ namespace Barotrauma
|
||||
|
||||
shortcutNodes.Clear();
|
||||
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && 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
|
||||
@@ -2075,7 +2079,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 < maxShortcutNodeCount && (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)
|
||||
{
|
||||
@@ -2085,7 +2089,7 @@ namespace Barotrauma
|
||||
|
||||
// If player is not a security officer AND invaders are reported
|
||||
// --> Create shorcut node for Fight Intruders order
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && (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(
|
||||
@@ -2094,7 +2098,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 < maxShortcutNodeCount && (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(
|
||||
@@ -2103,7 +2107,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 < maxShortcutNodeCount && (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(
|
||||
@@ -2112,13 +2116,13 @@ namespace Barotrauma
|
||||
|
||||
// If fire is reported
|
||||
// --> Create shortcut node for Extinguish Fires order
|
||||
if (shortcutNodes.Count < maxShortcutNodeCount && 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 < maxShortcutNodeCount && 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)
|
||||
{
|
||||
@@ -2131,11 +2135,17 @@ namespace Barotrauma
|
||||
{
|
||||
shortcutNodes.Add(CreateOrderNode(shortcutNodeSize, null, Point.Zero, orderPrefab, -1));
|
||||
}
|
||||
if (shortcutNodes.Count >= maxShortcutNodeCount) { break; }
|
||||
if (shortcutNodes.Count >= maxShortCutNodeCount) { break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shortcutNodes.Count < maxShortCutNodeCount && characterContext != null && !characterContext.IsDismissed)
|
||||
{
|
||||
shortcutNodes.Add(
|
||||
CreateOrderNode(shortcutNodeSize, null, Point.Zero, dismissedOrderPrefab, -1));
|
||||
}
|
||||
|
||||
if (shortcutNodes.Count < 1) { return; }
|
||||
|
||||
shortcutCenterNode = new GUIButton(
|
||||
@@ -2148,7 +2158,7 @@ namespace Barotrauma
|
||||
c.PressedColor = c.Color;
|
||||
c.SelectedColor = c.Color;
|
||||
}
|
||||
shortcutCenterNode.RectTransform.MoveOverTime(shortcutCenterNodeOffset, CommandNodeAnimDuration);
|
||||
shortcutCenterNode.RectTransform.MoveOverTime(shorcutCenterNodeOffset, CommandNodeAnimDuration);
|
||||
|
||||
var nodeCountForCalculations = shortcutNodes.Count * 2 + 2;
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, 0.75f * nodeDistance, nodeCountForCalculations);
|
||||
@@ -2156,7 +2166,7 @@ namespace Barotrauma
|
||||
for (int i = 0; i < shortcutNodes.Count; i++)
|
||||
{
|
||||
shortcutNodes[i].RectTransform.Parent = commandFrame.RectTransform;
|
||||
shortcutNodes[i].RectTransform.MoveOverTime(shortcutCenterNodeOffset + offsets[firstOffsetIndex - i].ToPoint(), CommandNodeAnimDuration);
|
||||
shortcutNodes[i].RectTransform.MoveOverTime(shorcutCenterNodeOffset + offsets[firstOffsetIndex - i].ToPoint(), CommandNodeAnimDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2171,7 +2181,7 @@ namespace Barotrauma
|
||||
{
|
||||
order = orders[i];
|
||||
disableNode = !CanSomeoneHearCharacter() ||
|
||||
(order.MustSetTarget && (order.ItemComponentType != null || order.ItemIdentifiers.Length > 0) && order.GetMatchingItems(true).None());
|
||||
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) && order.GetMatchingItems(true).None());
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(
|
||||
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), order, (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
|
||||
!disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
|
||||
@@ -2190,13 +2200,14 @@ namespace Barotrauma
|
||||
// Check if targeting an item or a hull
|
||||
if (itemContext != null && !itemContext.NonInteractable)
|
||||
{
|
||||
ItemComponent targetComponent;
|
||||
foreach (Order p in Order.PrefabList)
|
||||
{
|
||||
if ((p.ItemIdentifiers.Length > 0 && (p.ItemIdentifiers.Contains(itemContext.Prefab.Identifier) || itemContext.HasTag(p.ItemIdentifiers))) ||
|
||||
(p.ItemComponentType != null && itemContext.Components.Any(c => c?.GetType() == p.ItemComponentType)))
|
||||
targetComponent = null;
|
||||
if ((p.TargetItems.Length > 0 && (p.TargetItems.Contains(itemContext.Prefab.Identifier) || itemContext.HasTag(p.TargetItems))) ||
|
||||
p.TryGetTargetItemComponent(itemContext, out targetComponent))
|
||||
{
|
||||
contextualOrders.Add(p.HasOptions ? p :
|
||||
new Order(p, itemContext, itemContext.Components.FirstOrDefault(c => c?.GetType() == p.ItemComponentType), Character.Controlled));
|
||||
contextualOrders.Add(p.HasOptions ? p : new Order(p, itemContext, targetComponent, Character.Controlled));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2205,8 +2216,8 @@ namespace Barotrauma
|
||||
var operateWeaponsPrefab = Order.GetPrefab(orderIdentifier);
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
|
||||
{
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => operateWeaponsPrefab.ItemIdentifiers.Contains(c.Item.Prefab.Identifier)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => operateWeaponsPrefab.ItemIdentifiers.Contains(c.Item.Prefab.Identifier));
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems));
|
||||
if (turret != null) { contextualOrders.Add(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled)); }
|
||||
}
|
||||
|
||||
@@ -2214,14 +2225,17 @@ namespace Barotrauma
|
||||
orderIdentifier = "repairsystems";
|
||||
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"))))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairelectrical"), itemContext, null, Character.Controlled));
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairelectrical"), itemContext, targetItem: null, Character.Controlled));
|
||||
}
|
||||
else if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical"))))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairmechanical"), itemContext, null, Character.Controlled));
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairmechanical"), itemContext, targetItem: null, Character.Controlled));
|
||||
}
|
||||
else
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2235,23 +2249,29 @@ namespace Barotrauma
|
||||
|
||||
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))
|
||||
orderIdentifier = "cleanupitems";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, null, Character.Controlled));
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(hullContext != null)
|
||||
else if (hullContext != null)
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("fixleaks"), hullContext, null, Character.Controlled));
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("fixleaks"), hullContext, targetItem: null, Character.Controlled));
|
||||
}
|
||||
|
||||
if (characters.Any(c => c != Character.Controlled))
|
||||
if (contextualOrders.None(o => o.Category != OrderCategory.Movement))
|
||||
{
|
||||
// Show 'follow' order only when there are no orders of other categories available
|
||||
if (contextualOrders.None(o => o.Category != OrderCategory.Movement))
|
||||
orderIdentifier = "wait";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
Vector2 position = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
Hull hull = Hull.FindHull(position, guess: Character.Controlled?.CurrentHull);
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), new OrderTarget(position, hull), Character.Controlled));
|
||||
}
|
||||
|
||||
if (characters.Any(c => c != Character.Controlled))
|
||||
{
|
||||
orderIdentifier = "follow";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
@@ -2259,14 +2279,14 @@ namespace Barotrauma
|
||||
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)) &&
|
||||
characters.Any(c => c.CurrentOrder != null && !c.CurrentOrder.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
}
|
||||
}
|
||||
|
||||
// Show 'dismiss' order only when there are crew members with active orders
|
||||
orderIdentifier = "dismissed";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) &&
|
||||
characters.Any(c => c.CurrentOrder != null && !c.CurrentOrder.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2280,17 +2300,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: there's duplicate logic here and above -> would be better to refactor so that the conditions are only defined in one place
|
||||
public static bool DoesItemHaveContextualOrders(Item item)
|
||||
{
|
||||
if (Order.PrefabList.Any(o => o.ItemIdentifiers.Length > 0 && o.ItemIdentifiers.Contains(item.Prefab.Identifier))) { return true; }
|
||||
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 (Order.PrefabList.Any(o => o.TargetItems.Length > 0 && o.TargetItems.Contains(item.Prefab.Identifier))) { return true; }
|
||||
if (Order.PrefabList.Any(o => item.HasTag(o.TargetItems))) { return true; }
|
||||
if (Order.PrefabList.Any(o => o.TryGetTargetItemComponent(item, out _))) { return true; }
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(item, Character.Controlled)) { 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)) ||
|
||||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => operateWeaponsPrefab.ItemIdentifiers.Contains(c.Item.Prefab.Identifier)));
|
||||
(item.GetConnectedComponents<Turret>().Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ||
|
||||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)));
|
||||
}
|
||||
|
||||
private GUIButton CreateOrderNode(Point size, RectTransform parent, Point offset, Order order, int hotkey, bool disableNode = false, bool checkIfOrderCanBeHeard = true)
|
||||
@@ -2462,7 +2484,7 @@ namespace Barotrauma
|
||||
style: "GUITextBox")
|
||||
{
|
||||
UserData = new Tuple<Order, string>(
|
||||
item == null ? order : new Order(order, item, item.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType)),
|
||||
item == null ? order : new Order(order, item, order.GetTargetItemComponent(item)),
|
||||
order.Options[i]),
|
||||
Font = GUI.SmallFont,
|
||||
OnClicked = (_, userData) =>
|
||||
@@ -2479,7 +2501,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var userData = new Tuple<Order, string>(item == null ? order : new Order(order, item, item.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType)), "");
|
||||
var userData = new Tuple<Order, string>(item == null ? order : new Order(order, item, order.GetTargetItemComponent(item)), "");
|
||||
optionElement = new GUIButton(
|
||||
new RectTransform(
|
||||
new Point((int)(50 * GUI.Scale)),
|
||||
@@ -2528,7 +2550,7 @@ namespace Barotrauma
|
||||
var item = itemContext != null ?
|
||||
(order.UseController ? itemContext.GetConnectedComponents<Turret>().FirstOrDefault()?.Item ?? itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault()?.Item : itemContext) :
|
||||
(matchingItems.Count > 0 ? matchingItems[0] : null);
|
||||
var o = item == null || !order.IsPrefab ? order : new Order(order, item, item.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType));
|
||||
var o = item == null || !order.IsPrefab ? order : new Order(order, item, order.GetTargetItemComponent(item));
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance,
|
||||
GetCircumferencePointCount(order.Options.Length),
|
||||
GetFirstNodeAngle(order.Options.Length));
|
||||
@@ -2754,7 +2776,7 @@ namespace Barotrauma
|
||||
|
||||
// Order icon
|
||||
GUIImage orderIcon;
|
||||
if (character.CurrentOrder != null && !character.CurrentOrder.Identifier.Equals("dismissed"))
|
||||
if (!character.IsDismissed)
|
||||
{
|
||||
orderIcon = new GUIImage(new RectTransform(new Vector2(1.2f), node.RectTransform, anchor: Anchor.Center), character.CurrentOrder.SymbolSprite, scaleToFit: true);
|
||||
var tooltip = character.CurrentOrder.Name;
|
||||
@@ -2910,7 +2932,7 @@ namespace Barotrauma
|
||||
{
|
||||
bearing = GetBearing(
|
||||
centerNode.RectTransform.AnimTargetPos.ToVector2(),
|
||||
shortcutCenterNodeOffset.ToVector2());
|
||||
shorcutCenterNodeOffset.ToVector2());
|
||||
}
|
||||
return nodeCount % 2 > 0 ?
|
||||
MathHelper.ToRadians(bearing + 360.0f / nodeCount / 2) :
|
||||
@@ -2997,8 +3019,7 @@ namespace Barotrauma
|
||||
#endif
|
||||
if (order.Identifier == dismissedOrderPrefab.Identifier)
|
||||
{
|
||||
return characters.FindAll(c => c.CurrentOrder != null && c.CurrentOrder.Identifier != dismissedOrderPrefab.Identifier)
|
||||
.OrderBy(c => c.Info.DisplayName).ToList();
|
||||
return characters.FindAll(c => !c.IsDismissed).OrderBy(c => c.Info.DisplayName).ToList();
|
||||
}
|
||||
return GetCharactersSortedForOrder(order, order.Identifier != "follow").ToList();
|
||||
}
|
||||
@@ -3006,16 +3027,16 @@ namespace Barotrauma
|
||||
private IEnumerable<Character> GetCharactersSortedForOrder(Order order, bool includeSelf)
|
||||
{
|
||||
return characters.FindAll(c => Character.Controlled == null || ((includeSelf || c != Character.Controlled) && c.TeamID == Character.Controlled.TeamID))
|
||||
// 1. Prioritize those who are already ordered to operate the item target of the new 'operate' order
|
||||
.OrderByDescending(c => c.CurrentOrder != null && order.Category == OrderCategory.Operate && c.CurrentOrder.Identifier == order.Identifier && c.CurrentOrder.TargetEntity == order.TargetEntity)
|
||||
// 2. Prioritize those who are currently dismissed
|
||||
.ThenByDescending(c => c.CurrentOrder == null || c.CurrentOrder.Identifier == dismissedOrderPrefab.Identifier)
|
||||
// 3. Prioritize those who are not currently assigned with the same type of order (for example, when giving a 'Fix Leak' order, prioritize those who have a different order)
|
||||
.ThenBy(c => c.CurrentOrder != null && c.CurrentOrder.Identifier == order.Identifier && c.CurrentOrder.TargetEntity == order.TargetEntity)
|
||||
// 4. Prioritize those with the appropriate job for the order
|
||||
// 1. Prioritize those who are on the same submarine than the controlled character
|
||||
.OrderByDescending(c => Character.Controlled == null || c.Submarine == Character.Controlled.Submarine)
|
||||
// 2. Prioritize those who are already ordered to operate the item target of the new 'operate' order, or given the same maintenance order as now issued
|
||||
.ThenByDescending(c => c.CurrentOrder != null && c.CurrentOrder.Identifier == order.Identifier && (order.Category == OrderCategory.Maintenance || (order.Category == OrderCategory.Operate && c.CurrentOrder.TargetSpatialEntity == order.TargetSpatialEntity)))
|
||||
// 3. Prioritize those with the appropriate job for the order
|
||||
.ThenByDescending(c => order.HasAppropriateJob(c))
|
||||
// 5. Prioritize those with the lowest "weight" of the current order
|
||||
.ThenBy(c => c.CurrentOrder?.Weight)
|
||||
// 4. Prioritize bots over player controlled characters
|
||||
.ThenByDescending(c => c.IsBot)
|
||||
// 5. Use the priority value of the current objective
|
||||
.ThenBy(c => c.AIController?.ObjectiveManager.CurrentObjective?.Priority)
|
||||
// 6. Prioritize those with the best skill for the order
|
||||
.ThenByDescending(c => c.GetSkillLevel(order.AppropriateSkill));
|
||||
}
|
||||
|
||||
@@ -98,6 +98,9 @@ namespace Barotrauma
|
||||
case "pendingupgrades":
|
||||
UpgradeManager = new UpgradeManager(this, subElement, isSingleplayer: true);
|
||||
break;
|
||||
case "pets":
|
||||
petsElement = subElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,6 +216,10 @@ namespace Barotrauma
|
||||
crewDead = false;
|
||||
endTimer = 5.0f;
|
||||
CrewManager.InitSinglePlayerRound();
|
||||
if (petsElement != null)
|
||||
{
|
||||
PetBehavior.LoadPets(petsElement);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadInitialLevel()
|
||||
@@ -413,8 +420,6 @@ namespace Barotrauma
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
bool save = false;
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
||||
@@ -707,6 +712,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
modeElement.Add(petsElement);
|
||||
|
||||
CrewManager.Save(modeElement);
|
||||
CampaignMetadata.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
|
||||
@@ -161,7 +161,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!captain_medicObjectiveSensor.MotionDetected);
|
||||
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(captain_medic.Info.DisplayName, TextManager.Get("Captain.Radio.Medic"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
GameMain.GameSession.CrewManager.ToggleCrewListOpen = true;
|
||||
GameMain.GameSession.CrewManager.AutoShowCrewList();
|
||||
GameMain.GameSession.CrewManager.AddCharacter(captain_medic);
|
||||
TriggerTutorialSegment(0, GameMain.Config.KeyBindText(InputType.Command));
|
||||
do
|
||||
@@ -186,8 +186,7 @@ namespace Barotrauma.Tutorials
|
||||
// TODO: Rework order highlighting for new command UI
|
||||
// GameMain.GameSession.CrewManager.HighlightOrderButton(captain_mechanic, "repairsystems", highlightColor, new Vector2(5, 5));
|
||||
//HighlightOrderOption("jobspecific");
|
||||
}
|
||||
while (!HasOrder(captain_mechanic, "repairsystems"));
|
||||
} while (!HasOrder(captain_mechanic, "repairsystems") && !HasOrder(captain_mechanic, "repairmechanical") && !HasOrder(captain_mechanic, "repairelectrical"));
|
||||
RemoveCompletedObjective(segments[1]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Command));
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Barotrauma.Tutorials
|
||||
GameMain.GameSession.CrewManager.AllowCharacterSwitch = false;
|
||||
GameMain.GameSession.CrewManager.AddCharacter(doctor);
|
||||
GameMain.GameSession.CrewManager.AddCharacter(patient1);
|
||||
GameMain.GameSession.CrewManager.ToggleCrewListOpen = true;
|
||||
GameMain.GameSession.CrewManager.AutoShowCrewList();
|
||||
patient1.CharacterHealth.UseHealthWindow = false;
|
||||
|
||||
yield return new WaitForSeconds(3.0f, false);
|
||||
|
||||
@@ -87,9 +87,9 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
engineer = Character.Controlled;
|
||||
|
||||
var toolbox = FindOrGiveItem(engineer, "toolbox");
|
||||
toolbox.Unequip(engineer);
|
||||
engineer.Inventory.RemoveItem(toolbox);
|
||||
var toolbelt = FindOrGiveItem(engineer, "toolbelt");
|
||||
toolbelt.Unequip(engineer);
|
||||
engineer.Inventory.RemoveItem(toolbelt);
|
||||
|
||||
var repairOrder = Order.GetPrefab("repairsystems");
|
||||
engineer_repairIcon = repairOrder.SymbolSprite;
|
||||
@@ -123,7 +123,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
// Room 3
|
||||
engineer_reactorObjectiveSensor = Item.ItemList.Find(i => i.HasTag("engineer_reactorobjectivesensor")).GetComponent<MotionSensor>();
|
||||
tutorial_oxygenGenerator = Item.ItemList.Find(i => i.HasTag("tutorial_oxygengenerator")).GetComponent<Powered>();
|
||||
tutorial_oxygenGenerator = Item.ItemList.Find(i => i.HasTag("tutorial_oxygengenerator")).GetComponent<OxygenGenerator>();
|
||||
engineer_reactor = Item.ItemList.Find(i => i.HasTag("engineer_reactor")).GetComponent<Reactor>();
|
||||
engineer_reactor.FireDelay = engineer_reactor.MeltdownDelay = float.PositiveInfinity;
|
||||
engineer_reactor.FuelConsumptionRate = 0.0f;
|
||||
@@ -311,6 +311,8 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
yield return null;
|
||||
} while (engineer_reactor.AvailableFuel == 0);
|
||||
RemoveCompletedObjective(segments[1]);
|
||||
TriggerTutorialSegment(2);
|
||||
CoroutineManager.StartCoroutine(ReactorOperatedProperly());
|
||||
do
|
||||
{
|
||||
@@ -352,7 +354,7 @@ namespace Barotrauma.Tutorials
|
||||
} while (wait > 0.0f);
|
||||
engineer.SelectedConstruction = null;
|
||||
engineer_reactor.CanBeSelected = false;
|
||||
RemoveCompletedObjective(segments[1]);
|
||||
RemoveCompletedObjective(segments[2]);
|
||||
SetHighlight(engineer_reactor.Item, false);
|
||||
SetHighlight(engineer_brokenJunctionBox, true);
|
||||
SetDoorAccess(engineer_secondDoor, engineer_secondDoorLight, true);
|
||||
@@ -361,7 +363,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!engineer_secondDoor.IsOpen);
|
||||
yield return new WaitForSeconds(1f, false);
|
||||
Repairable repairableJunctionBoxComponent = engineer_brokenJunctionBox.GetComponent<Repairable>();
|
||||
TriggerTutorialSegment(2, GameMain.Config.KeyBindText(InputType.Select)); // Repair the junction box
|
||||
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Select)); // Repair the junction box
|
||||
do
|
||||
{
|
||||
if (!engineer.HasEquippedItem("screwdriver"))
|
||||
@@ -378,7 +380,7 @@ namespace Barotrauma.Tutorials
|
||||
yield return null;
|
||||
} while (engineer_brokenJunctionBox.Condition < repairableJunctionBoxComponent.RepairThreshold); // Wait until repaired
|
||||
SetHighlight(engineer_brokenJunctionBox, false);
|
||||
RemoveCompletedObjective(segments[2]);
|
||||
RemoveCompletedObjective(segments[3]);
|
||||
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, true);
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
@@ -389,14 +391,14 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!engineer_thirdDoor.IsOpen);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.FaultyWiring"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(3, GameMain.Config.KeyBindText(InputType.Use), GameMain.Config.KeyBindText(InputType.Deselect)); // Connect the junction boxes
|
||||
TriggerTutorialSegment(4, GameMain.Config.KeyBindText(InputType.Use), GameMain.Config.KeyBindText(InputType.Deselect)); // Connect the junction boxes
|
||||
do { CheckGhostWires(); HandleJunctionBoxWiringHighlights(); yield return null; } while (engineer_workingPump.Voltage < engineer_workingPump.MinVoltage); // Wait until connected all the way to the pump
|
||||
CheckGhostWires();
|
||||
for (int i = 0; i < engineer_disconnectedJunctionBoxes.Length; i++)
|
||||
{
|
||||
SetHighlight(engineer_disconnectedJunctionBoxes[i].Item, false);
|
||||
}
|
||||
RemoveCompletedObjective(segments[3]);
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
do { yield return null; } while (engineer_workingPump.Item.CurrentHull.WaterPercentage > waterVolumeBeforeOpening); // Wait until drained
|
||||
wiringActive = false;
|
||||
SetDoorAccess(engineer_fourthDoor, engineer_fourthDoorLight, true);
|
||||
@@ -406,7 +408,7 @@ namespace Barotrauma.Tutorials
|
||||
do { yield return null; } while (!tutorial_enteredSubmarineSensor.MotionDetected);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Submarine"), ChatMessageType.Radio, null);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
TriggerTutorialSegment(4); // Repair junction box
|
||||
TriggerTutorialSegment(5); // Repair junction box
|
||||
while (ContentRunning) yield return null;
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_1, engineer_repairIcon, engineer_repairIconColor);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineJunctionBox_2, engineer_repairIcon, engineer_repairIconColor);
|
||||
@@ -422,16 +424,16 @@ namespace Barotrauma.Tutorials
|
||||
// Remove highlights when each individual machine is repaired
|
||||
do { CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3); yield return null; } while (engineer_submarineJunctionBox_1.Condition < repairableJunctionBoxComponent1.RepairThreshold || engineer_submarineJunctionBox_2.Condition < repairableJunctionBoxComponent2.RepairThreshold || engineer_submarineJunctionBox_3.Condition < repairableJunctionBoxComponent3.RepairThreshold);
|
||||
CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3);
|
||||
RemoveCompletedObjective(segments[4]);
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
yield return new WaitForSeconds(2f, false);
|
||||
|
||||
TriggerTutorialSegment(5); // Powerup reactor
|
||||
TriggerTutorialSegment(6); // Powerup reactor
|
||||
SetHighlight(engineer_submarineReactor.Item, true);
|
||||
engineer.AddActiveObjectiveEntity(engineer_submarineReactor.Item, engineer_reactorIcon, engineer_reactorIconColor);
|
||||
do { yield return null; } while (!IsReactorPoweredUp(engineer_submarineReactor)); // Wait until ~matches load
|
||||
engineer.RemoveActiveObjectiveEntity(engineer_submarineReactor.Item);
|
||||
SetHighlight(engineer_submarineReactor.Item, false);
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
RemoveCompletedObjective(segments[6]);
|
||||
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Complete"), ChatMessageType.Radio, null);
|
||||
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
|
||||
@@ -87,9 +87,9 @@ namespace Barotrauma.Tutorials
|
||||
radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker");
|
||||
mechanic = Character.Controlled;
|
||||
|
||||
var toolbox = FindOrGiveItem(mechanic, "toolbox");
|
||||
toolbox.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(toolbox);
|
||||
var toolbelt = FindOrGiveItem(mechanic, "toolbelt");
|
||||
toolbelt.Unequip(mechanic);
|
||||
mechanic.Inventory.RemoveItem(toolbelt);
|
||||
|
||||
var crowbar = FindOrGiveItem(mechanic, "crowbar");
|
||||
crowbar.Unequip(mechanic);
|
||||
@@ -141,7 +141,7 @@ namespace Barotrauma.Tutorials
|
||||
mechanic_brokenWall_1.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_1.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_1.AddDamage(i, 165);
|
||||
mechanic_brokenWall_1.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_1 = mechanic_brokenWall_1.Sections[0].gap.FlowTargetHull;
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace Barotrauma.Tutorials
|
||||
mechanic_brokenWall_2.SpriteColor = Color.White;
|
||||
for (int i = 0; i < mechanic_brokenWall_2.SectionCount; i++)
|
||||
{
|
||||
mechanic_brokenWall_2.AddDamage(i, 165);
|
||||
mechanic_brokenWall_2.AddDamage(i, 85);
|
||||
}
|
||||
mechanic_brokenhull_2 = mechanic_brokenWall_2.Sections[0].gap.FlowTargetHull;
|
||||
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, false);
|
||||
|
||||
@@ -362,10 +362,10 @@ namespace Barotrauma.Tutorials
|
||||
SetHighlight(officer_rangedWeaponHolder.Item, false);
|
||||
do
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
yield return null;
|
||||
} while (!officer.HasEquippedItem("harpoongun")); // Wait until equipped
|
||||
ItemContainer harpoonGunChamber = officer.Inventory.FindItemByIdentifier("harpoongun").GetComponent<ItemContainer>();
|
||||
} while (!officer.HasEquippedItem("shotgun")); // Wait until equipped
|
||||
ItemContainer shotGunChamber = officer.Inventory.FindItemByIdentifier("shotgun").GetComponent<ItemContainer>();
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, true);
|
||||
do
|
||||
{
|
||||
@@ -376,7 +376,7 @@ namespace Barotrauma.Tutorials
|
||||
for (int i = 0; i < officer_rangedWeaponCabinet.Inventory.Items.Length; i++)
|
||||
{
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i] == null) continue;
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "spear")
|
||||
if (officer_rangedWeaponCabinet.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer_rangedWeaponCabinet.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
@@ -387,18 +387,18 @@ namespace Barotrauma.Tutorials
|
||||
for (int i = 0; i < officer.Inventory.Items.Length; i++)
|
||||
{
|
||||
if (officer.Inventory.Items[i] == null) continue;
|
||||
if (officer.Inventory.Items[i].Prefab.Identifier == "spear")
|
||||
if (officer.Inventory.Items[i].Prefab.Identifier == "shotgunshell")
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, i, highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (officer.Inventory.FindItemByIdentifier("spear") != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("spear") != null))
|
||||
if (officer.Inventory.FindItemByIdentifier("shotgunshell") != null || (IsSelectedItem(officer_rangedWeaponCabinet.Item) && officer_rangedWeaponCabinet.Inventory.FindItemByIdentifier("shotgunshell") != null))
|
||||
{
|
||||
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
HighlightInventorySlot(officer.Inventory, "shotgun", highlightColor, 0.5f, 0.5f, 0f);
|
||||
}
|
||||
yield return null;
|
||||
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
|
||||
} while (!shotGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
SetHighlight(officer_rangedWeaponCabinet.Item, false);
|
||||
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);
|
||||
|
||||
@@ -584,8 +584,8 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
|
||||
infoBlock.RectTransform.NonScaledSize = new Point(infoBlock.Rect.Width, (int)(infoContent.Children.Sum(c => c.Rect.Height + infoContent.AbsoluteSpacing) / infoContent.RectTransform.RelativeSize.Y));
|
||||
|
||||
GUI.PlayUISound(GUISoundType.UIMessage);
|
||||
|
||||
SoundPlayer.PlayUISound(GUISoundType.UIMessage);
|
||||
|
||||
return background;
|
||||
}
|
||||
|
||||
@@ -1149,7 +1149,7 @@ namespace Barotrauma
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set voice capture mode.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
VoiceSetting = VoiceMode.Disabled;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,12 +51,13 @@ namespace Barotrauma
|
||||
limbSlotIcons.Add(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
|
||||
limbSlotIcons.Add(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
|
||||
limbSlotIcons.Add(InvSlotType.Bag, new Sprite("Content/UI/CommandUIAtlas.png", new Rectangle(639, 926, 128,80)));
|
||||
}
|
||||
return limbSlotIcons;
|
||||
}
|
||||
}
|
||||
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Bag | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
@@ -143,17 +144,13 @@ namespace Barotrauma
|
||||
protected override ItemInventory GetActiveEquippedSubInventory(int slotIndex)
|
||||
{
|
||||
var item = Items[slotIndex];
|
||||
if (item == null) return null;
|
||||
if (item == null) { return null; }
|
||||
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
if (container == null ||
|
||||
!character.CanAccessInventory(container.Inventory) ||
|
||||
!container.KeepOpenWhenEquipped ||
|
||||
!character.HasEquippedItem(container.Item))
|
||||
if (container == null || !container.KeepOpenWhenEquippedBy(character))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return container.Inventory;
|
||||
}
|
||||
|
||||
@@ -625,7 +622,7 @@ namespace Barotrauma
|
||||
{
|
||||
var itemContainer = item.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null &&
|
||||
itemContainer.KeepOpenWhenEquipped &&
|
||||
itemContainer.KeepOpenWhenEquippedBy(character) &&
|
||||
character.CanAccessInventory(itemContainer.Inventory) &&
|
||||
!highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory))
|
||||
{
|
||||
@@ -729,6 +726,7 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < indicators.Length; i++)
|
||||
{
|
||||
if (indicatorIndexes[i] < 0) { continue; }
|
||||
Item item = Items[indicatorIndexes[i]];
|
||||
if (item != null)
|
||||
{
|
||||
@@ -922,12 +920,14 @@ namespace Barotrauma
|
||||
if (slotItem == item)
|
||||
{
|
||||
slot.ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.4f);
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity> { item }, true));
|
||||
|
||||
item.Remove();
|
||||
return;
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
draggingItem = null;
|
||||
GUI.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
}
|
||||
|
||||
public void DrawOwn(SpriteBatch spriteBatch)
|
||||
|
||||
@@ -261,7 +261,23 @@ namespace Barotrauma.Items.Components
|
||||
if (!isNetworkMessage || open != PredictedState)
|
||||
{
|
||||
StopPicking(null);
|
||||
PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse);
|
||||
ActionType actionType = ActionType.OnUse;
|
||||
if (forcedOpen)
|
||||
{
|
||||
actionType = ActionType.OnPicked;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (open && HasSoundsOfType[(int)ActionType.OnOpen])
|
||||
{
|
||||
actionType = ActionType.OnOpen;
|
||||
}
|
||||
else if (!open && HasSoundsOfType[(int)ActionType.OnClose])
|
||||
{
|
||||
actionType = ActionType.OnClose;
|
||||
}
|
||||
}
|
||||
PlaySound(actionType);
|
||||
if (isOpen) { stuck = MathHelper.Clamp(stuck - StuckReductionOnOpen, 0.0f, 100.0f); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
for (int i = 0; i < targetSections.Count; i++)
|
||||
{
|
||||
targetHull.SetSectionColorOrStrength(targetSections[i], color, sizeAdjustedSprayStrength * deltaTime, true, false);
|
||||
targetHull.IncreaseSectionColorOrStrength(targetSections[i], color, sizeAdjustedSprayStrength * deltaTime, true, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace Barotrauma.Items.Components
|
||||
get { return sounds.Count > 0; }
|
||||
}
|
||||
|
||||
public bool[] HasSoundsOfType { get { return hasSoundsOfType; } }
|
||||
|
||||
private readonly bool[] hasSoundsOfType;
|
||||
private readonly Dictionary<ActionType, List<ItemSound>> sounds;
|
||||
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
|
||||
@@ -191,6 +193,12 @@ namespace Barotrauma.Items.Components
|
||||
private ItemSound loopingSound;
|
||||
private SoundChannel loopingSoundChannel;
|
||||
private List<SoundChannel> playingOneshotSoundChannels = new List<SoundChannel>();
|
||||
public ItemComponent ReplacedBy;
|
||||
|
||||
public ItemComponent GetReplacementOrThis()
|
||||
{
|
||||
return ReplacedBy?.GetReplacementOrThis() ?? this;
|
||||
}
|
||||
|
||||
public void UpdateSounds()
|
||||
{
|
||||
|
||||
@@ -70,6 +70,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
[Serialize(false, false, description: "Should the inventory of this item be kept open when the item is equipped by a character.")]
|
||||
public bool KeepOpenWhenEquipped { get; set; }
|
||||
|
||||
[Serialize(false, false, description: "Can the inventory of this item be moved around on the screen by the player.")]
|
||||
public bool MovableFrame { get; set; }
|
||||
|
||||
@@ -162,6 +163,30 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public bool KeepOpenWhenEquippedBy(Character character)
|
||||
{
|
||||
if (!character.CanAccessInventory(Inventory) ||
|
||||
!KeepOpenWhenEquipped ||
|
||||
!character.HasEquippedItem(Item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//if holding 2 different "always open" items in different hands, don't force them to stay open
|
||||
if (character.SelectedItems[0] != null &&
|
||||
character.SelectedItems[1] != null &&
|
||||
character.SelectedItems[0] != character.SelectedItems[1])
|
||||
{
|
||||
if ((character.SelectedItems[0].GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false) &&
|
||||
(character.SelectedItems[1].GetComponent<ItemContainer>()?.KeepOpenWhenEquipped ?? false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||
{
|
||||
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
|
||||
|
||||
@@ -26,29 +26,17 @@ namespace Barotrauma.Items.Components
|
||||
if (isHUDsHidden == value) { return; }
|
||||
if (value == true)
|
||||
{
|
||||
ToggleCrewArea(false, storeOriginalState: true);
|
||||
GameMain.GameSession?.CrewManager?.AutoHideCrewList();
|
||||
ToggleChatBox(false, storeOriginalState: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ToggleCrewArea(crewAreaOriginalState, storeOriginalState: false);
|
||||
GameMain.GameSession?.CrewManager?.ResetCrewList();
|
||||
ToggleChatBox(chatBoxOriginalState, storeOriginalState: false);
|
||||
}
|
||||
isHUDsHidden = value;
|
||||
}
|
||||
|
||||
private void ToggleCrewArea(bool value, bool storeOriginalState)
|
||||
{
|
||||
var crewManager = GameMain.GameSession?.CrewManager;
|
||||
if (crewManager == null) { return; }
|
||||
|
||||
if (storeOriginalState)
|
||||
{
|
||||
crewAreaOriginalState = crewManager.ToggleCrewListOpen;
|
||||
}
|
||||
crewManager.ToggleCrewListOpen = value;
|
||||
}
|
||||
|
||||
private void ToggleChatBox(bool value, bool storeOriginalState)
|
||||
{
|
||||
var crewManager = GameMain.GameSession?.CrewManager;
|
||||
|
||||
@@ -17,7 +17,16 @@ namespace Barotrauma.Items.Components
|
||||
private GUITickBox autoControlIndicator;
|
||||
|
||||
private List<Pair<Vector2, ParticleEmitter>> pumpOutEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||
private List<Pair<Vector2, ParticleEmitter>> pumpInEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||
private List<Pair<Vector2, ParticleEmitter>> pumpInEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||
|
||||
public float CurrentBrokenVolume
|
||||
{
|
||||
get
|
||||
{
|
||||
if (item.ConditionPercentage > 10.0f || !IsActive) { return 0.0f; }
|
||||
return (1.0f - item.ConditionPercentage / 10.0f) * 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
{
|
||||
|
||||
@@ -284,6 +284,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Enabled = false,
|
||||
Selected = AutoTemp,
|
||||
ClickSound = GUISoundType.UISwitch,
|
||||
OnClicked = (button, data) =>
|
||||
{
|
||||
AutoTemp = !AutoTemp;
|
||||
|
||||
@@ -181,6 +181,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Selected = false,
|
||||
Enabled = true,
|
||||
ClickSound = GUISoundType.UISwitch,
|
||||
OnClicked = (button, data) =>
|
||||
{
|
||||
button.Selected = !button.Selected;
|
||||
|
||||
@@ -123,6 +123,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
Selected = autoPilot,
|
||||
Enabled = true,
|
||||
ClickSound = GUISoundType.UISwitch,
|
||||
OnClicked = (button, data) =>
|
||||
{
|
||||
button.Selected = !button.Selected;
|
||||
|
||||
@@ -342,7 +342,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X || PlayerInput.IsShiftDown())
|
||||
if ((highlightedNodeIndex.HasValue && Vector2.DistanceSquared(nodeWorldPos, draggingWire.nodes[(int)highlightedNodeIndex]) > Submarine.GridSize.X * Submarine.GridSize.X) ||
|
||||
PlayerInput.IsShiftDown())
|
||||
{
|
||||
selectedNodeIndex = highlightedNodeIndex;
|
||||
}
|
||||
@@ -535,6 +536,9 @@ namespace Barotrauma.Items.Components
|
||||
nodes = nodePositions.ToList();
|
||||
UpdateSections();
|
||||
Drawable = nodes.Any();
|
||||
IsActive =
|
||||
(connections[0] == null ^ connections[1] == null) &&
|
||||
(item.ParentInventory is CharacterInventory characterInventory && ((characterInventory.Owner as Character)?.HasEquippedItem(item) ?? false));
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Barotrauma.Items.Components
|
||||
private RoundSound startMoveSound, endMoveSound, moveSound;
|
||||
|
||||
private SoundChannel moveSoundChannel;
|
||||
private Vector2 oldRotation = Vector2.Zero;
|
||||
|
||||
private Vector2 crosshairPos, crosshairPointerPos;
|
||||
|
||||
@@ -285,7 +286,7 @@ namespace Barotrauma.Items.Components
|
||||
rotation + MathHelper.PiOver2, item.Scale,
|
||||
SpriteEffects.None, item.SpriteDepth + (barrelSprite.Depth - item.Sprite.Depth));
|
||||
|
||||
if (!editing || GUI.DisableHUD) { return; }
|
||||
if (!editing || GUI.DisableHUD || !item.IsSelected) { return; }
|
||||
|
||||
float widgetRadius = 60.0f;
|
||||
|
||||
@@ -304,10 +305,12 @@ namespace Barotrauma.Items.Components
|
||||
drawPos + new Vector2((float)Math.Cos((maxRotation + minRotation) / 2), (float)Math.Sin((maxRotation + minRotation) / 2)) * widgetRadius,
|
||||
Color.LightGreen);
|
||||
|
||||
if (!item.IsSelected) { return; }
|
||||
|
||||
Widget minRotationWidget = GetWidget("minrotation", spriteBatch, size: 10, initMethod: (widget) =>
|
||||
{
|
||||
{
|
||||
widget.Selected += () =>
|
||||
{
|
||||
oldRotation = RotationLimits;
|
||||
};
|
||||
widget.MouseDown += () =>
|
||||
{
|
||||
widget.color = GUI.Style.Green;
|
||||
@@ -317,6 +320,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
widget.color = Color.Yellow;
|
||||
item.CreateEditingHUD();
|
||||
if (SubEditorScreen.IsSubEditor())
|
||||
{
|
||||
SubEditorScreen.StoreCommand(new PropertyCommand(this, "RotationLimits", RotationLimits, oldRotation));
|
||||
}
|
||||
};
|
||||
widget.MouseHeld += (deltaTime) =>
|
||||
{
|
||||
@@ -345,10 +352,14 @@ namespace Barotrauma.Items.Components
|
||||
widget.DrawPos = GetDrawPos() + new Vector2((float)Math.Cos(minRotation), (float)Math.Sin(minRotation)) * widgetRadius;
|
||||
widget.Update(deltaTime);
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
Widget maxRotationWidget = GetWidget("maxrotation", spriteBatch, size: 10, initMethod: (widget) =>
|
||||
{
|
||||
widget.Selected += () =>
|
||||
{
|
||||
oldRotation = RotationLimits;
|
||||
};
|
||||
widget.MouseDown += () =>
|
||||
{
|
||||
widget.color = GUI.Style.Green;
|
||||
@@ -358,6 +369,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
widget.color = Color.Yellow;
|
||||
item.CreateEditingHUD();
|
||||
if (SubEditorScreen.IsSubEditor())
|
||||
{
|
||||
SubEditorScreen.StoreCommand(new PropertyCommand(this, "RotationLimits", RotationLimits, oldRotation));
|
||||
}
|
||||
};
|
||||
widget.MouseHeld += (deltaTime) =>
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -163,6 +162,8 @@ namespace Barotrauma
|
||||
|
||||
public static Inventory DraggingInventory;
|
||||
|
||||
public Inventory ReplacedBy;
|
||||
|
||||
public Rectangle BackgroundFrame { get; protected set; }
|
||||
|
||||
private ushort[] receivedItemIDs;
|
||||
@@ -317,6 +318,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Inventory GetReplacementOrThiS()
|
||||
{
|
||||
return ReplacedBy?.GetReplacementOrThiS() ?? this;
|
||||
}
|
||||
|
||||
public virtual void CreateSlots()
|
||||
{
|
||||
slots = new InventorySlot[capacity];
|
||||
@@ -398,8 +404,8 @@ namespace Barotrauma
|
||||
container = (this as ItemInventory).Container;
|
||||
}
|
||||
|
||||
if (container == null) return false;
|
||||
return owner.SelectedCharacter != null || !container.KeepOpenWhenEquipped || (!(owner is Character)) || !owner.HasEquippedItem(container.Item);
|
||||
if (container == null) { return false; }
|
||||
return owner.SelectedCharacter != null|| (!(owner is Character character)) || !container.KeepOpenWhenEquippedBy(character) || !owner.HasEquippedItem(container.Item);
|
||||
}
|
||||
|
||||
protected virtual bool HideSlot(int i)
|
||||
@@ -465,12 +471,15 @@ namespace Barotrauma
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
if (mouseDrag) { item.OwnInventory?.DeleteAllItems(); }
|
||||
slot.ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.4f);
|
||||
if (!mouseDrag)
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
|
||||
SubEditorScreen.BulkItemBufferInUse = true;
|
||||
SubEditorScreen.BulkItemBuffer.Add(new AddOrDeleteCommand(new List<MapEntity> { item }, true));
|
||||
item.OwnInventory?.DeleteAllItems();
|
||||
item.Remove();
|
||||
}
|
||||
}
|
||||
@@ -993,13 +1002,23 @@ namespace Barotrauma
|
||||
{
|
||||
if (DraggingItemToWorld &&
|
||||
Character.Controlled.FocusedItem?.OwnInventory != null &&
|
||||
(Character.Controlled.FocusedItem.GetComponent<ItemContainer>()?.HasRequiredItems(Character.Controlled, addMessage: false) ?? false) &&
|
||||
Character.Controlled.FocusedItem.OwnInventory.CanBePut(draggingItem) &&
|
||||
Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled))
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Screen.Selected is SubEditorScreen)
|
||||
{
|
||||
if (draggingItem?.ParentInventory != null)
|
||||
{
|
||||
SubEditorScreen.StoreCommand(new InventoryPlaceCommand(draggingItem.ParentInventory, new List<Item> { draggingItem }, true));
|
||||
}
|
||||
}
|
||||
|
||||
SoundPlayer.PlayUISound(GUISoundType.DropItem);
|
||||
bool removed = false;
|
||||
if (Screen.Selected is SubEditorScreen editor)
|
||||
{
|
||||
@@ -1025,14 +1044,16 @@ namespace Barotrauma
|
||||
{
|
||||
draggingItem.Drop(Character.Controlled);
|
||||
}
|
||||
|
||||
GUI.PlayUISound(removed ? GUISoundType.PickItem : GUISoundType.DropItem);
|
||||
|
||||
SoundPlayer.PlayUISound(removed ? GUISoundType.PickItem : GUISoundType.DropItem);
|
||||
}
|
||||
}
|
||||
else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem)
|
||||
{
|
||||
Inventory oldInventory = draggingItem.ParentInventory;
|
||||
Inventory selectedInventory = selectedSlot.ParentInventory;
|
||||
int slotIndex = selectedSlot.SlotIndex;
|
||||
int oldSlot = oldInventory == null ? 0 : Array.IndexOf(oldInventory.Items, draggingItem);
|
||||
|
||||
//if attempting to drop into an invalid slot in the same inventory, try to move to the correct slot
|
||||
if (selectedInventory.Items[slotIndex] == null &&
|
||||
@@ -1051,17 +1072,21 @@ namespace Barotrauma
|
||||
}
|
||||
selectedInventory.slots[slotIndex].ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.9f);
|
||||
}
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
else if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
|
||||
{
|
||||
if (SubEditorScreen.IsSubEditor())
|
||||
{
|
||||
SubEditorScreen.StoreCommand(new InventoryMoveCommand(oldInventory, selectedInventory, draggingItem, oldSlot, slotIndex));
|
||||
}
|
||||
if (selectedInventory.slots != null) { selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f); }
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selectedInventory.slots != null){ selectedInventory.slots[slotIndex].ShowBorderHighlight(GUI.Style.Red, 0.1f, 0.9f); }
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
}
|
||||
selectedInventory.HideTimer = 2.0f;
|
||||
if (selectedSlot.ParentInventory?.Owner is Item parentItem && parentItem.ParentInventory != null)
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public override bool DrawBelowWater => (!(Screen.Selected is SubEditorScreen editor) || !editor.WiringMode || !isWire) && base.DrawBelowWater;
|
||||
public override bool DrawBelowWater => (!(Screen.Selected is SubEditorScreen editor) || !editor.WiringMode || !isWire) && (base.DrawBelowWater || ParentInventory is CharacterInventory);
|
||||
|
||||
public override bool DrawOverWater => base.DrawOverWater || (IsSelected || Screen.Selected is SubEditorScreen editor && editor.WiringMode) && isWire;
|
||||
|
||||
@@ -332,6 +332,7 @@ namespace Barotrauma
|
||||
var holdable = GetComponent<Holdable>();
|
||||
if (holdable != null && holdable.Picker?.AnimController != null)
|
||||
{
|
||||
if (!back) { return; }
|
||||
float depthStep = 0.000001f;
|
||||
if (holdable.Picker.SelectedItems[0] == this)
|
||||
{
|
||||
@@ -542,7 +543,7 @@ namespace Barotrauma
|
||||
Spacing = (int)(25 * GUI.Scale)
|
||||
};
|
||||
|
||||
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont);
|
||||
var itemEditor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont) { UserData = this };
|
||||
itemEditor.Children.First().Color = Color.Black * 0.7f;
|
||||
if (!inGame)
|
||||
{
|
||||
@@ -663,7 +664,7 @@ namespace Barotrauma
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), listBox.Content.RectTransform), style: "HorizontalLine");
|
||||
|
||||
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, titleFont: GUI.SubHeadingFont);
|
||||
var componentEditor = new SerializableEntityEditor(listBox.Content.RectTransform, ic, inGame, showName: !inGame, titleFont: GUI.SubHeadingFont) { UserData = ic };
|
||||
componentEditor.Children.First().Color = Color.Black * 0.7f;
|
||||
|
||||
if (inGame)
|
||||
@@ -855,7 +856,7 @@ namespace Barotrauma
|
||||
public void UpdateHUD(Camera cam, Character character, float deltaTime)
|
||||
{
|
||||
bool editingHUDCreated = false;
|
||||
if ((HasInGameEditableProperties && character.SelectedConstruction == this) ||
|
||||
if ((HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped)) ||
|
||||
Screen.Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
GUIComponent prevEditingHUD = editingHUD;
|
||||
@@ -956,7 +957,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawHUD(SpriteBatch spriteBatch, Camera cam, Character character)
|
||||
{
|
||||
if (HasInGameEditableProperties)
|
||||
if (HasInGameEditableProperties && (character.SelectedConstruction == this || EditableWhenEquipped))
|
||||
{
|
||||
DrawEditing(spriteBatch, cam);
|
||||
}
|
||||
@@ -1028,13 +1029,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HasInGameEditableProperties)
|
||||
if (HasInGameEditableProperties && Character.Controlled != null && (Character.Controlled.SelectedConstruction == this || EditableWhenEquipped))
|
||||
{
|
||||
if (editingHUD != null && editingHUD.UserData == this) { editingHUD.AddToGUIUpdateList(); }
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled != null && Character.Controlled?.SelectedConstruction != this) { return; }
|
||||
if (Character.Controlled != null && Character.Controlled.SelectedConstruction != this) { return; }
|
||||
|
||||
bool needsLayoutUpdate = false;
|
||||
foreach (ItemComponent ic in activeHUDs)
|
||||
|
||||
@@ -97,10 +97,12 @@ namespace Barotrauma
|
||||
{
|
||||
if (potentialContainer?.OwnInventory?.TryPutItem(item, Character.Controlled) ?? false)
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
}
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity> {item}, false));
|
||||
|
||||
placePosition = Vector2.Zero;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,5 +110,7 @@ namespace Barotrauma
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
static partial void PlayTinnitusProjSpecific(float volume) => SoundPlayer.PlaySound("tinnitus", volume: volume);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,18 @@ namespace Barotrauma
|
||||
|
||||
partial void UpdateProjSpecific(float growModifier)
|
||||
{
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, OnChangeHull);
|
||||
if (this is DummyFireSource)
|
||||
{
|
||||
EmitParticles(size, WorldPosition, hull, growModifier, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
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 (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; }
|
||||
}
|
||||
|
||||
public static void EmitParticles(Vector2 size, Vector2 worldPosition, Hull hull, float growModifier, Particle.OnChangeHullHandler onChangeHull = null)
|
||||
@@ -32,6 +39,8 @@ namespace Barotrauma
|
||||
(particlePos.X - (worldPosition.X + size.X / 2.0f)),
|
||||
(float)Math.Sqrt(size.X) * Rand.Range(0.0f, 15.0f) * growModifier);
|
||||
|
||||
particleVel.X = MathHelper.Clamp(particleVel.X, -200.0f, 200.0f);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle("flame",
|
||||
particlePos, particleVel, 0.0f, hull);
|
||||
|
||||
|
||||
@@ -10,11 +10,30 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Hull : MapEntity, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private class RemoteDecal
|
||||
{
|
||||
public readonly UInt32 DecalId;
|
||||
public readonly int SpriteIndex;
|
||||
public Vector2 NormalizedPos;
|
||||
public readonly float Scale;
|
||||
|
||||
public RemoteDecal(UInt32 decalId, int spriteIndex, Vector2 normalizedPos, float scale)
|
||||
{
|
||||
DecalId = decalId;
|
||||
SpriteIndex = spriteIndex;
|
||||
NormalizedPos = normalizedPos;
|
||||
Scale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
private float serverUpdateDelay;
|
||||
private float remoteWaterVolume, remoteOxygenPercentage;
|
||||
private List<Vector3> remoteFireSources;
|
||||
private readonly List<BackgroundSection> remoteBackgroundSections = new List<BackgroundSection>();
|
||||
private readonly List<RemoteDecal> remoteDecals = new List<RemoteDecal>();
|
||||
|
||||
private readonly HashSet<Decal> pendingDecalUpdates = new HashSet<Decal>();
|
||||
|
||||
private double lastAmbientLightEditTime;
|
||||
|
||||
public override bool SelectableInEditor
|
||||
@@ -94,20 +113,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) { continue; }
|
||||
if (!entity.IsMouseOn(position)) { continue; }
|
||||
if (entity.linkedTo != null && entity.linkedTo.Contains(this))
|
||||
if (entity.linkedTo == null || !entity.Linkable) { continue; }
|
||||
if (entity.linkedTo.Contains(this) || linkedTo.Contains(entity) || rClick)
|
||||
{
|
||||
if (entity == this || !entity.IsHighlighted) continue;
|
||||
if (!entity.IsMouseOn(position)) continue;
|
||||
if (entity.Linkable && entity.linkedTo != null && !entity.linkedTo.Contains(this))
|
||||
if (entity == this || !entity.IsHighlighted) { continue; }
|
||||
if (!entity.IsMouseOn(position)) { continue; }
|
||||
if (entity.linkedTo.Contains(this))
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
entity.linkedTo.Remove(this);
|
||||
linkedTo.Remove(entity);
|
||||
}
|
||||
}
|
||||
else if (entity.Linkable && entity.linkedTo != null)
|
||||
else
|
||||
{
|
||||
entity.linkedTo.Add(this);
|
||||
linkedTo.Add(entity);
|
||||
if (!entity.linkedTo.Contains(this)) { entity.linkedTo.Add(this); }
|
||||
if (!linkedTo.Contains(this)) { linkedTo.Add(entity); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,10 +145,14 @@ namespace Barotrauma
|
||||
networkUpdateTimer += deltaTime;
|
||||
if (networkUpdateTimer > 0.2f)
|
||||
{
|
||||
if (!pendingSectionUpdates.Any())
|
||||
if (!pendingSectionUpdates.Any() && !pendingDecalUpdates.Any())
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this);
|
||||
}
|
||||
foreach (Decal decal in pendingDecalUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { decal });
|
||||
}
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember?.CreateEntityEvent(this, new object[] { pendingSectionUpdate });
|
||||
@@ -261,6 +285,13 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(fireSourceRect.X - (int)fs.DamageRange, fireSourceRect.Y, fireSourceRect.Width + (int)fs.DamageRange * 2, fireSourceRect.Height), GUI.Style.Orange, false, 0, 5);
|
||||
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
|
||||
}
|
||||
foreach (FireSource fs in FakeFireSources)
|
||||
{
|
||||
Rectangle fireSourceRect = new Rectangle((int)fs.WorldPosition.X, -(int)fs.WorldPosition.Y, (int)fs.Size.X, (int)fs.Size.Y);
|
||||
GUI.DrawRectangle(spriteBatch, fireSourceRect, GUI.Style.Red, false, 0, 5);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(fireSourceRect.X - (int)fs.DamageRange, fireSourceRect.Y, fireSourceRect.Width + (int)fs.DamageRange * 2, fireSourceRect.Height), GUI.Style.Orange, false, 0, 5);
|
||||
//GUI.DrawRectangle(spriteBatch, new Rectangle((int)fs.LastExtinguishPos.X, (int)-fs.LastExtinguishPos.Y, 5,5), Color.Yellow, true);
|
||||
}
|
||||
|
||||
|
||||
/*GUI.DrawLine(spriteBatch, new Vector2(drawRect.X, -WorldSurface), new Vector2(drawRect.Right, -WorldSurface), Color.Cyan * 0.5f);
|
||||
@@ -530,9 +561,9 @@ namespace Barotrauma
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write(extraData != null);
|
||||
if (extraData == null)
|
||||
{
|
||||
msg.WriteRangedInteger(0, 0, 2);
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
|
||||
|
||||
msg.Write(FireSources.Count > 0);
|
||||
@@ -552,8 +583,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (extraData[0] is Decal decal)
|
||||
{
|
||||
msg.WriteRangedInteger(1, 0, 2);
|
||||
int decalIndex = decals.IndexOf(decal);
|
||||
msg.Write((byte)(decalIndex < 0 ? 255 : decalIndex));
|
||||
msg.WriteRangedSingle(decal.BaseAlpha, 0.0f, 1.0f, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.WriteRangedInteger(2, 0, 2);
|
||||
int sectorToUpdate = (int)extraData[0];
|
||||
int start = sectorToUpdate * BackgroundSectionsPerNetworkEvent;
|
||||
int end = Math.Min((sectorToUpdate + 1) * BackgroundSectionsPerNetworkEvent, BackgroundSections.Count - 1);
|
||||
@@ -598,11 +637,6 @@ namespace Barotrauma
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -619,16 +653,16 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
int decalCount = message.ReadRangedInteger(0, MaxDecalsPerHull);
|
||||
decals.Clear();
|
||||
if (decalCount == 0) { decals.Clear(); }
|
||||
remoteDecals.Clear();
|
||||
for (int i = 0; i < decalCount; i++)
|
||||
{
|
||||
UInt32 decalId = message.ReadUInt32();
|
||||
int spriteIndex = message.ReadByte();
|
||||
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);
|
||||
remoteDecals.Add(new RemoteDecal(decalId, spriteIndex, new Vector2(normalizedXPos, normalizedYPos), decalScale));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -642,11 +676,30 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (BackgroundSection remoteBackgroundSection in remoteBackgroundSections)
|
||||
{
|
||||
float prevColorStrength = BackgroundSections[remoteBackgroundSection.Index].ColorStrength;
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColor(remoteBackgroundSection.Color);
|
||||
BackgroundSections[remoteBackgroundSection.Index].SetColorStrength(remoteBackgroundSection.ColorStrength);
|
||||
paintAmount = Math.Max(0, paintAmount + (BackgroundSections[remoteBackgroundSection.Index].ColorStrength - prevColorStrength) / BackgroundSections.Count);
|
||||
}
|
||||
remoteBackgroundSections.Clear();
|
||||
|
||||
if (remoteDecals.Any())
|
||||
{
|
||||
decals.Clear();
|
||||
foreach (RemoteDecal remoteDecal in remoteDecals)
|
||||
{
|
||||
float decalPosX = MathHelper.Lerp(rect.X, rect.Right, remoteDecal.NormalizedPos.X);
|
||||
float decalPosY = MathHelper.Lerp(rect.Y - rect.Height, rect.Y, remoteDecal.NormalizedPos.Y);
|
||||
if (Submarine != null)
|
||||
{
|
||||
decalPosX += Submarine.Position.X;
|
||||
decalPosY += Submarine.Position.Y;
|
||||
}
|
||||
AddDecal(remoteDecal.DecalId, new Vector2(decalPosX, decalPosY), remoteDecal.Scale, isNetworkEvent: true, spriteIndex: remoteDecal.SpriteIndex);
|
||||
}
|
||||
remoteDecals.Clear();
|
||||
}
|
||||
|
||||
if (remoteFireSources == null) { return; }
|
||||
|
||||
WaterVolume = remoteWaterVolume;
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
if (!light.IsBackground) { continue; }
|
||||
light.DrawSprite(spriteBatch, cam);
|
||||
if (light.Color.A > 0 && light.Range > 0.0f) { light.DrawLightVolume(spriteBatch, lightEffect, transform); }
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
}
|
||||
GameMain.ParticleManager.Draw(spriteBatch, true, null, Particles.ParticleBlendState.Additive);
|
||||
spriteBatch.End();
|
||||
@@ -328,7 +328,7 @@ namespace Barotrauma.Lights
|
||||
foreach (LightSource light in activeLights)
|
||||
{
|
||||
if (light.IsBackground) { continue; }
|
||||
if (light.Color.A > 0 && light.Range > 0.0f) { light.DrawLightVolume(spriteBatch, lightEffect, transform); }
|
||||
light.DrawLightVolume(spriteBatch, lightEffect, transform);
|
||||
}
|
||||
|
||||
lightEffect.World = transform;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -6,6 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
|
||||
namespace Barotrauma.Lights
|
||||
{
|
||||
class LightSourceParams : ISerializableEntity
|
||||
@@ -42,6 +44,12 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(1f, true), Editable(minValue: 0.01f, maxValue: 100f, ValueStep = 0.1f, DecimalCount = 2)]
|
||||
public float Scale { get; set; }
|
||||
|
||||
[Serialize("0, 0", true), Editable(ValueStep = 1, DecimalCount = 1, MinValueFloat = -1000f, MaxValueFloat = 1000f)]
|
||||
public Vector2 Offset { get; set; }
|
||||
|
||||
public float TextureRange
|
||||
{
|
||||
get;
|
||||
@@ -239,11 +247,13 @@ namespace Barotrauma.Lights
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 _spriteScale = Vector2.One;
|
||||
|
||||
public Vector2 SpriteScale
|
||||
{
|
||||
get;
|
||||
set;
|
||||
} = Vector2.One;
|
||||
get { return _spriteScale * lightSourceParams.Scale; }
|
||||
set { _spriteScale = value; }
|
||||
}
|
||||
|
||||
public float? OverrideLightSpriteAlpha
|
||||
{
|
||||
@@ -278,7 +288,9 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
get { return lightSourceParams.LightSprite; }
|
||||
}
|
||||
|
||||
|
||||
private Vector2 OverrideLightTextureOrigin => OverrideLightTexture.Origin + LightSourceParams.Offset;
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get { return lightSourceParams.Color; }
|
||||
@@ -331,16 +343,42 @@ namespace Barotrauma.Lights
|
||||
|
||||
public bool Enabled = true;
|
||||
|
||||
public LightSource (XElement element)
|
||||
private ISerializableEntity conditionalTarget;
|
||||
private readonly PropertyConditional.Comparison comparison;
|
||||
private readonly List<PropertyConditional> conditionals = new List<PropertyConditional>();
|
||||
|
||||
public LightSource (XElement element, ISerializableEntity conditionalTarget = null)
|
||||
: this(Vector2.Zero, 100.0f, Color.White, null)
|
||||
{
|
||||
lightSourceParams = new LightSourceParams(element);
|
||||
CastShadows = element.GetAttributeBool("castshadows", true);
|
||||
string comparison = element.GetAttributeString("comparison", null);
|
||||
if (comparison != null)
|
||||
{
|
||||
Enum.TryParse(comparison, ignoreCase: true, out this.comparison);
|
||||
}
|
||||
|
||||
if (lightSourceParams.DeformableLightSpriteElement != null)
|
||||
{
|
||||
DeformableLightSprite = new DeformableSprite(lightSourceParams.DeformableLightSpriteElement, invert: true);
|
||||
}
|
||||
|
||||
this.conditionalTarget = conditionalTarget;
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "conditional":
|
||||
foreach (XAttribute attribute in subElement.Attributes())
|
||||
{
|
||||
if (PropertyConditional.IsValid(attribute))
|
||||
{
|
||||
conditionals.Add(new PropertyConditional(attribute));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LightSource(LightSourceParams lightSourceParams)
|
||||
@@ -363,7 +401,8 @@ namespace Barotrauma.Lights
|
||||
CastShadows = true;
|
||||
texture = LightTexture;
|
||||
diffToSub = new Dictionary<Submarine, Vector2>();
|
||||
if (addLight) GameMain.LightManager.AddLight(this);
|
||||
if (addLight) { GameMain.LightManager.AddLight(this); }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -493,7 +532,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (Range < 1.0f || Color.A < 0.01f) return null;
|
||||
if (Range < 1.0f || Color.A < 1) { return null; }
|
||||
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null) drawPos += ParentSub.DrawPosition;
|
||||
@@ -535,7 +574,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTexture.Origin;
|
||||
Vector2 origin = OverrideLightTextureOrigin;
|
||||
|
||||
origin /= Math.Max(overrideTextureDims.X, overrideTextureDims.Y);
|
||||
origin -= Vector2.One * 0.5f;
|
||||
@@ -844,7 +883,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTexture.Origin;
|
||||
Vector2 origin = OverrideLightTextureOrigin;
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally) { origin.X = OverrideLightTexture.SourceRect.Width - origin.X; }
|
||||
if (LightSpriteEffect == SpriteEffects.FlipVertically) { origin.Y = OverrideLightTexture.SourceRect.Height - origin.Y; }
|
||||
uvOffset = (origin / overrideTextureDims) - new Vector2(0.5f, 0.5f);
|
||||
@@ -1031,7 +1070,7 @@ namespace Barotrauma.Lights
|
||||
{
|
||||
var overrideTextureDims = new Vector2(OverrideLightTexture.SourceRect.Width, OverrideLightTexture.SourceRect.Height);
|
||||
|
||||
Vector2 origin = OverrideLightTexture.Origin;
|
||||
Vector2 origin = OverrideLightTextureOrigin;
|
||||
|
||||
origin /= Math.Max(overrideTextureDims.X, overrideTextureDims.Y);
|
||||
origin *= TextureRange;
|
||||
@@ -1059,13 +1098,12 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (DeformableLightSprite != null)
|
||||
{
|
||||
Vector2 origin = DeformableLightSprite.Origin;
|
||||
Vector2 origin = DeformableLightSprite.Origin + LightSourceParams.Offset;
|
||||
Vector2 drawPos = position;
|
||||
if (ParentSub != null)
|
||||
{
|
||||
drawPos += ParentSub.DrawPosition;
|
||||
}
|
||||
|
||||
if (LightSpriteEffect == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
origin.X = DeformableLightSprite.Sprite.SourceRect.Width - origin.X;
|
||||
@@ -1084,7 +1122,7 @@ namespace Barotrauma.Lights
|
||||
|
||||
if (LightSprite != null)
|
||||
{
|
||||
Vector2 origin = LightSprite.Origin;
|
||||
Vector2 origin = LightSprite.Origin + LightSourceParams.Offset;
|
||||
if ((LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally)
|
||||
{
|
||||
origin.X = LightSprite.SourceRect.Width - origin.X;
|
||||
@@ -1128,12 +1166,27 @@ namespace Barotrauma.Lights
|
||||
GUI.DrawLine(spriteBatch, drawPos - Vector2.One * Range, drawPos + Vector2.One * Range, Color);
|
||||
GUI.DrawLine(spriteBatch, drawPos - new Vector2(1.0f, -1.0f) * Range, drawPos + new Vector2(1.0f, -1.0f) * Range, Color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckConditionals()
|
||||
{
|
||||
if (conditionals.None()) { return; }
|
||||
if (conditionalTarget == null) { return; }
|
||||
if (comparison == PropertyConditional.Comparison.And)
|
||||
{
|
||||
Enabled = conditionals.All(c => c.Matches(conditionalTarget));
|
||||
}
|
||||
else
|
||||
{
|
||||
Enabled = conditionals.Any(c => c.Matches(conditionalTarget));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void DrawLightVolume(SpriteBatch spriteBatch, BasicEffect lightEffect, Matrix transform)
|
||||
{
|
||||
if (Range < 1.0f || Color.A < 1) { return; }
|
||||
|
||||
if (CastShadows)
|
||||
{
|
||||
CheckHullsInRange();
|
||||
@@ -1158,7 +1211,6 @@ namespace Barotrauma.Lights
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (NeedsRecalculation)
|
||||
{
|
||||
var verts = FindRaycastHits();
|
||||
@@ -1168,7 +1220,6 @@ namespace Barotrauma.Lights
|
||||
NeedsRecalculation = false;
|
||||
}
|
||||
|
||||
|
||||
Vector2 offset = ParentSub == null ? Vector2.Zero : ParentSub.DrawPosition;
|
||||
lightEffect.World =
|
||||
Matrix.CreateTranslation(-new Vector3(position, 0.0f)) *
|
||||
|
||||
@@ -27,6 +27,9 @@ namespace Barotrauma
|
||||
|
||||
private static bool resizing;
|
||||
private int resizeDirX, resizeDirY;
|
||||
private Rectangle? prevRect;
|
||||
|
||||
public static bool SelectionChanged;
|
||||
|
||||
//which entities have been selected for editing
|
||||
private static List<MapEntity> selectedList = new List<MapEntity>();
|
||||
@@ -105,6 +108,11 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for undo/redo to determine what this item has been replaced with
|
||||
/// </summary>
|
||||
public MapEntity ReplacedBy;
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) { }
|
||||
|
||||
/// <summary>
|
||||
@@ -147,13 +155,13 @@ namespace Barotrauma
|
||||
}
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
if (PlayerInput.KeyDown(Keys.Delete))
|
||||
if (PlayerInput.KeyHit(Keys.Delete))
|
||||
{
|
||||
selectedList.ForEach(e =>
|
||||
if (selectedList.Any())
|
||||
{
|
||||
//orphaned wires may already have been removed
|
||||
if (!e.Removed) { e.Remove(); }
|
||||
});
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(selectedList, true));
|
||||
}
|
||||
selectedList.ForEach(e => { if (!e.Removed) { e.Remove(); } });
|
||||
selectedList.Clear();
|
||||
}
|
||||
|
||||
@@ -217,30 +225,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.Z))
|
||||
{
|
||||
SetPreviousRects(e => e.rectMemento.Undo());
|
||||
}
|
||||
else if (PlayerInput.KeyHit(Keys.R))
|
||||
{
|
||||
SetPreviousRects(e => e.rectMemento.Redo());
|
||||
}
|
||||
|
||||
void SetPreviousRects(Func<MapEntity, Rectangle> memoryMethod)
|
||||
{
|
||||
foreach (var e in SelectedList)
|
||||
{
|
||||
if (e.rectMemento != null)
|
||||
{
|
||||
Point diff = memoryMethod(e).Location - e.Rect.Location;
|
||||
// We have to call the move method, because there's a lot more than just storing the rect (in some cases)
|
||||
// We also have to reassign the rect, because the move method does not set the width and height. They might have changed too.
|
||||
// The Rect property is virtual and it's overridden for structs. Setting the rect via the property should automatically recreate the sections for resizable structures.
|
||||
e.Move(diff.ToVector2());
|
||||
e.Rect = e.rectMemento.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,35 +327,38 @@ namespace Barotrauma
|
||||
//clone
|
||||
if (PlayerInput.IsCtrlDown())
|
||||
{
|
||||
var clones = Clone(selectedList);
|
||||
var clones = Clone(selectedList).Where(c => c != null).ToList();
|
||||
selectedList = clones;
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false));
|
||||
selectedList.ForEach(c => c.Move(moveAmount));
|
||||
}
|
||||
else // move
|
||||
{
|
||||
var oldRects = selectedList.Select(e => e.Rect).ToList();
|
||||
List<MapEntity> deposited = new List<MapEntity>();
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
if (e.rectMemento == null)
|
||||
{
|
||||
e.rectMemento = new Memento<Rectangle>();
|
||||
e.rectMemento.Store(e.Rect);
|
||||
}
|
||||
e.Move(moveAmount);
|
||||
|
||||
if (isShiftDown && e is Item item && targetContainer != null)
|
||||
{
|
||||
if (targetContainer.OwnInventory.TryPutItem(item, Character.Controlled))
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.DropItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.DropItem);
|
||||
deposited.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
}
|
||||
}
|
||||
e.rectMemento.Store(e.Rect);
|
||||
}
|
||||
|
||||
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity>(selectedList),selectedList.Select(entity => entity.Rect).ToList(), oldRects, false));
|
||||
if (deposited.Any() && deposited.Any(entity => entity is Item))
|
||||
{
|
||||
var depositedItems = deposited.Where(entity => entity is Item).Cast<Item>().ToList();
|
||||
SubEditorScreen.StoreCommand(new InventoryPlaceCommand(targetContainer.OwnInventory, depositedItems, false));
|
||||
}
|
||||
|
||||
deposited.ForEach(entity => { selectedList.Remove(entity); });
|
||||
@@ -492,6 +479,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public MapEntity GetReplacementOrThis()
|
||||
{
|
||||
return ReplacedBy?.GetReplacementOrThis() ?? this;
|
||||
}
|
||||
|
||||
public static Item GetPotentialContainer(Vector2 position, List<MapEntity> entities = null)
|
||||
{
|
||||
Item targetContainer = null;
|
||||
@@ -904,13 +896,12 @@ namespace Barotrauma
|
||||
public static void Cut(List<MapEntity> entities)
|
||||
{
|
||||
if (entities.Count == 0) { return; }
|
||||
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity>(entities), true));
|
||||
|
||||
CopyEntities(entities);
|
||||
|
||||
entities.ForEach(e =>
|
||||
{
|
||||
e.Remove();
|
||||
});
|
||||
|
||||
entities.ForEach(e => { if (!e.Removed) { e.Remove(); } });
|
||||
entities.Clear();
|
||||
}
|
||||
|
||||
@@ -922,6 +913,7 @@ namespace Barotrauma
|
||||
Clone(copiedList);
|
||||
|
||||
var clones = mapEntityList.Except(prevEntities).ToList();
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(clones, false));
|
||||
var nonWireClones = clones.Where(c => !(c is Item item) || item.GetComponent<Wire>() == null);
|
||||
if (!nonWireClones.Any()) { nonWireClones = clones; }
|
||||
|
||||
@@ -1031,12 +1023,11 @@ namespace Barotrauma
|
||||
|
||||
if (resizing)
|
||||
{
|
||||
if (rectMemento == null)
|
||||
if (prevRect == null)
|
||||
{
|
||||
rectMemento = new Memento<Rectangle>();
|
||||
rectMemento.Store(Rect);
|
||||
prevRect = new Rectangle(Rect.Location, Rect.Size);
|
||||
}
|
||||
|
||||
|
||||
Vector2 placePosition = new Vector2(rect.X, rect.Y);
|
||||
Vector2 placeSize = new Vector2(rect.Width, rect.Height);
|
||||
|
||||
@@ -1079,9 +1070,15 @@ namespace Barotrauma
|
||||
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
rectMemento.Store(Rect);
|
||||
resizing = false;
|
||||
Resized?.Invoke(rect);
|
||||
if (prevRect != null)
|
||||
{
|
||||
var newData = new List<Rectangle> { Rect };
|
||||
var oldData = new List<Rectangle> { prevRect.Value };
|
||||
SubEditorScreen.StoreCommand(new TransformCommand(new List<MapEntity> { this }, newData, oldData, true));
|
||||
}
|
||||
prevRect = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace Barotrauma
|
||||
int heightScaled = (int)(20 * GUI.Scale);
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) { UserData = this };
|
||||
GUIListBox listBox = new GUIListBox(new RectTransform(new Vector2(0.95f, 0.8f), editingHUD.RectTransform, Anchor.Center), style: null);
|
||||
var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont);
|
||||
var editor = new SerializableEntityEditor(listBox.Content.RectTransform, this, inGame, showName: true, titleFont: GUI.LargeFont) { UserData = this };
|
||||
|
||||
if (Submarine.MainSub?.Info?.Type == SubmarineType.OutpostModule)
|
||||
{
|
||||
|
||||
@@ -56,11 +56,12 @@ namespace Barotrauma
|
||||
if (PlayerInput.PrimaryMouseButtonReleased())
|
||||
{
|
||||
newRect.Location -= MathUtils.ToPoint(Submarine.MainSub.Position);
|
||||
new Structure(newRect, this, Submarine.MainSub)
|
||||
var structure = new Structure(newRect, this, Submarine.MainSub)
|
||||
{
|
||||
Submarine = Submarine.MainSub
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity> { structure }, false));
|
||||
selected = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
existingSound = roundSounds.Find(s => s.Filename == filename && s.Stream == stream)?.Sound;
|
||||
existingSound = roundSounds.Find(s => s.Filename == filename && s.Stream == stream && !s.Sound.Disposed)?.Sound;
|
||||
}
|
||||
|
||||
if (existingSound == null)
|
||||
@@ -121,7 +121,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\".";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,26 @@ namespace Barotrauma
|
||||
return newSound;
|
||||
}
|
||||
|
||||
public static void ReloadRoundSound(RoundSound roundSound)
|
||||
{
|
||||
Sound existingSound = roundSounds?.Find(s => s.Filename == roundSound.Filename && s.Stream == roundSound.Stream && !s.Sound.Disposed)?.Sound;
|
||||
if (existingSound == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
existingSound = GameMain.SoundManager.LoadSound(roundSound.Filename, roundSound.Stream);
|
||||
}
|
||||
catch (System.IO.FileNotFoundException e)
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + roundSound.Filename + "\".";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + roundSound.Filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
}
|
||||
roundSound.Sound = existingSound;
|
||||
}
|
||||
|
||||
private static void RemoveRoundSound(RoundSound roundSound)
|
||||
{
|
||||
roundSound.Sound?.Dispose();
|
||||
@@ -438,10 +458,15 @@ namespace Barotrauma
|
||||
public void CheckForErrors()
|
||||
{
|
||||
List<string> errorMsgs = new List<string>();
|
||||
List<SubEditorScreen.WarningType> warnings = new List<SubEditorScreen.WarningType>();
|
||||
|
||||
if (!Hull.hullList.Any())
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHullsWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NoWaypoints))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHullsWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NoHulls);
|
||||
}
|
||||
}
|
||||
|
||||
if (Info.Type != SubmarineType.OutpostModule ||
|
||||
@@ -449,7 +474,11 @@ namespace Barotrauma
|
||||
{
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NoWaypoints))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NoWaypoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,22 +489,38 @@ namespace Barotrauma
|
||||
if (item.GetComponent<Items.Components.Vent>() == null) { continue; }
|
||||
if (!item.linkedTo.Any())
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("DisconnectedVentsWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.DisconnectedVents))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("DisconnectedVentsWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.DisconnectedVents);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NoHumanSpawnpoints))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NoHumanSpawnpoints);
|
||||
}
|
||||
}
|
||||
if (WayPoint.WayPointList.Find(wp => wp.SpawnType == SpawnType.Cargo) == null)
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoCargoSpawnpointWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NoCargoSpawnpoints))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoCargoSpawnpointWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NoCargoSpawnpoints);
|
||||
}
|
||||
}
|
||||
if (!Item.ItemList.Any(it => it.GetComponent<Items.Components.Pump>() != null && it.HasTag("ballast")))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoBallastTagsWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NoBallastTag))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NoBallastTagsWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NoBallastTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Info.Type == SubmarineType.OutpostModule)
|
||||
@@ -503,7 +548,11 @@ namespace Barotrauma
|
||||
|
||||
if (Gap.GapList.Any(g => g.linkedTo.Count == 0))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NonLinkedGapsWarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.NonLinkedGaps))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("NonLinkedGapsWarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.NonLinkedGaps);
|
||||
}
|
||||
}
|
||||
|
||||
int disabledItemLightCount = 0;
|
||||
@@ -515,12 +564,35 @@ namespace Barotrauma
|
||||
int count = GameMain.LightManager.Lights.Count(l => l.CastShadows) - disabledItemLightCount;
|
||||
if (count > 45)
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("subeditor.shadowcastinglightswarning"));
|
||||
if (!IsWarningSuppressed(SubEditorScreen.WarningType.TooManyLights))
|
||||
{
|
||||
errorMsgs.Add(TextManager.Get("subeditor.shadowcastinglightswarning"));
|
||||
warnings.Add(SubEditorScreen.WarningType.TooManyLights);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorMsgs.Any())
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("Warning"), string.Join("\n\n", errorMsgs), new Vector2(0.25f, 0.0f), new Point(400, 200));
|
||||
GUIMessageBox msgBox = new GUIMessageBox(TextManager.Get("Warning"), string.Join("\n\n", errorMsgs), new Vector2(0.25f, 0.0f), new Point(400, 200));
|
||||
if (warnings.Any())
|
||||
{
|
||||
Point size = msgBox.RectTransform.NonScaledSize;
|
||||
GUITickBox suppress = new GUITickBox(new RectTransform(new Vector2(1f, 0.33f), msgBox.Content.RectTransform), TextManager.Get("editor.suppresswarnings"));
|
||||
msgBox.RectTransform.NonScaledSize = new Point(size.X, size.Y + suppress.RectTransform.NonScaledSize.Y);
|
||||
|
||||
msgBox.Buttons[0].OnClicked += (button, obj) =>
|
||||
{
|
||||
if (suppress.Selected)
|
||||
{
|
||||
foreach (SubEditorScreen.WarningType warning in warnings.Where(warning => !SubEditorScreen.SuppressedWarnings.Contains(warning)))
|
||||
{
|
||||
SubEditorScreen.SuppressedWarnings.Add(warning);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntity e in MapEntity.mapEntityList)
|
||||
@@ -556,6 +628,11 @@ namespace Barotrauma
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool IsWarningSuppressed(SubEditorScreen.WarningType type)
|
||||
{
|
||||
return SubEditorScreen.SuppressedWarnings.Contains(type);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -49,45 +49,53 @@ namespace Barotrauma.Networking
|
||||
Character targetCharacter = Entity.FindEntityByID(targetCharacterID) as Character;
|
||||
Entity targetEntity = Entity.FindEntityByID(msg.ReadUInt16());
|
||||
int optionIndex = msg.ReadByte();
|
||||
OrderTarget orderTargetPosition = null;
|
||||
if (msg.ReadBoolean())
|
||||
{
|
||||
var x = msg.ReadSingle();
|
||||
var y = msg.ReadSingle();
|
||||
var hull = Entity.FindEntityByID(msg.ReadUInt16()) as Hull;
|
||||
orderTargetPosition = new OrderTarget(new Vector2(x, y), hull, creatingFromExistingData: true);
|
||||
}
|
||||
|
||||
Order order = null;
|
||||
Order orderPrefab;
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid order message - order index out of bounds.");
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID)) LastID = ID;
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID)) { LastID = ID; }
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = Order.PrefabList[orderIndex];
|
||||
orderPrefab = Order.PrefabList[orderIndex];
|
||||
}
|
||||
string orderOption = "";
|
||||
if (optionIndex >= 0 && optionIndex < order.Options.Length)
|
||||
if (optionIndex >= 0 && optionIndex < orderPrefab.Options.Length)
|
||||
{
|
||||
orderOption = order.Options[optionIndex];
|
||||
orderOption = orderPrefab.Options[optionIndex];
|
||||
}
|
||||
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
||||
txt = orderPrefab.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
||||
|
||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
var order = orderTargetPosition == null ?
|
||||
new Order(orderPrefab, targetEntity, orderPrefab.GetTargetItemComponent(targetEntity as Item), orderGiver: senderCharacter) :
|
||||
new Order(orderPrefab, orderTargetPosition, orderGiver: senderCharacter);
|
||||
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
order.Prefab.FadeOutTime);
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(order, orderPrefab.FadeOutTime);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.SetOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
orderOption, senderCharacter);
|
||||
targetCharacter.SetOrder(order, orderOption, senderCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID))
|
||||
{
|
||||
GameMain.Client.AddChatMessage(
|
||||
new OrderChatMessage(order, orderOption, txt, targetEntity, targetCharacter, senderCharacter));
|
||||
new OrderChatMessage(orderPrefab, orderOption, txt, orderTargetPosition ?? targetEntity as ISpatialEntity, targetCharacter, senderCharacter));
|
||||
LastID = ID;
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -608,10 +608,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
string errorMsg = "Error while reading a message from server. {" + e + "}. ";
|
||||
if (GameMain.Client == null) { errorMsg += "Client disposed."; }
|
||||
errorMsg += "\n" + e.StackTrace;
|
||||
errorMsg += "\n" + e.StackTrace.CleanupStackTrace();
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace.CleanupStackTrace();
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
DebugConsole.ThrowError("Error while reading a message from server.", e);
|
||||
@@ -738,10 +738,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Error while reading an ingame update message from server. {" + e + "}\n" + e.StackTrace;
|
||||
string errorMsg = "Error while reading an ingame update message from server. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace.CleanupStackTrace();
|
||||
}
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Error while reading an ingame update message from server.", e);
|
||||
@@ -755,7 +755,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
string errorMsg = "Failed to read a voice packet from the server (VoipClient == null). ";
|
||||
if (GameMain.Client == null) { errorMsg += "Client disposed. "; }
|
||||
errorMsg += "\n" + Environment.StackTrace;
|
||||
errorMsg += "\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.ReadDataMessage:VoipClientNull",
|
||||
GameMain.Client == null ? GameAnalyticsSDK.Net.EGAErrorSeverity.Error : GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
@@ -1023,7 +1023,10 @@ namespace Barotrauma.Networking
|
||||
if (Enum.TryParse(splitMsg[0], out disconnectReason)) { disconnectReasonIncluded = true; }
|
||||
}
|
||||
|
||||
if (disconnectMsg == Lidgren.Network.NetConnection.NoResponseMessage)
|
||||
if (disconnectMsg == Lidgren.Network.NetConnection.NoResponseMessage ||
|
||||
disconnectReason == DisconnectReason.Banned ||
|
||||
disconnectReason == DisconnectReason.Kicked ||
|
||||
disconnectReason == DisconnectReason.TooManyFailedLogins)
|
||||
{
|
||||
allowReconnect = false;
|
||||
}
|
||||
@@ -1124,7 +1127,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
DebugConsole.NewMessage("Not attempting to reconnect (DisconnectReason doesn't allow reconnection).");
|
||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString()) + " ";
|
||||
|
||||
for (int i = 1; i < splitMsg.Length; i++)
|
||||
{
|
||||
@@ -1966,7 +1969,12 @@ namespace Barotrauma.Networking
|
||||
string selectShuttleName = inc.ReadString();
|
||||
string selectShuttleHash = inc.ReadString();
|
||||
|
||||
string campaignSubmarineIndexes = inc.ReadString();
|
||||
UInt16 campaignSubmarineIndexCount = inc.ReadUInt16();
|
||||
List<int> campaignSubIndices = new List<int>();
|
||||
for (int i = 0; i< campaignSubmarineIndexCount; i++)
|
||||
{
|
||||
campaignSubIndices.Add(inc.ReadUInt16());
|
||||
}
|
||||
|
||||
bool allowSubVoting = inc.ReadBoolean();
|
||||
bool allowModeVoting = inc.ReadBoolean();
|
||||
@@ -2022,22 +2030,16 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.Client.IsServerOwner) RequestSelectMode(modeIndex);
|
||||
}
|
||||
|
||||
if (campaignSubmarineIndexes != null)
|
||||
if (campaignSubIndices != null)
|
||||
{
|
||||
string[] activeIndexes = campaignSubmarineIndexes.Split(';');
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines = new List<SubmarineInfo>();
|
||||
for (int i = 0; i < activeIndexes.Length; i++)
|
||||
foreach (UInt16 campaignSubIndex in campaignSubIndices)
|
||||
{
|
||||
int index;
|
||||
if (int.TryParse(activeIndexes[i], out index))
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[campaignSubIndex];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "campaign"))
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "campaign"))
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(sub);
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasPermission(ClientPermissions.ManageCampaign) && !gameStarted && GameMain.NetLobbyScreen?.CampaignSetupUI != null)
|
||||
@@ -2139,6 +2141,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
entities.Add(entity);
|
||||
if (entity != null && (entity is Item || entity is Character || entity is Submarine))
|
||||
{
|
||||
entity.ClientRead(objHeader.Value, inc, sendingTime);
|
||||
@@ -2186,10 +2189,11 @@ namespace Barotrauma.Networking
|
||||
"Previous object was " + (prevBitLength) + " bits long (" + (prevByteLength) + " bytes)",
|
||||
" "
|
||||
};
|
||||
errorLines.Add(ex.StackTrace);
|
||||
errorLines.Add(ex.StackTrace.CleanupStackTrace());
|
||||
errorLines.Add(" ");
|
||||
if (prevObjHeader == ServerNetObject.ENTITY_EVENT || prevObjHeader == ServerNetObject.ENTITY_EVENT_INITIAL ||
|
||||
objHeader == ServerNetObject.ENTITY_EVENT || objHeader == ServerNetObject.ENTITY_EVENT_INITIAL)
|
||||
objHeader == ServerNetObject.ENTITY_EVENT || objHeader == ServerNetObject.ENTITY_EVENT_INITIAL ||
|
||||
objHeader == ServerNetObject.ENTITY_POSITION || prevObjHeader == ServerNetObject.ENTITY_POSITION)
|
||||
{
|
||||
foreach (IServerSerializable ent in entities)
|
||||
{
|
||||
@@ -2721,7 +2725,7 @@ namespace Barotrauma.Networking
|
||||
MultiPlayerCampaign campaign = GameMain.GameSession.GameMode as MultiPlayerCampaign;
|
||||
if (campaign == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed send campaign state to the server (no campaign active).\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Failed send campaign state to the server (no campaign active).\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2738,7 +2742,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command))
|
||||
{
|
||||
DebugConsole.ThrowError("Cannot send an empty console command to the server!\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Cannot send an empty console command to the server!\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2778,7 +2782,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (subIndex < 0 || subIndex >= subList.Content.CountChildren)
|
||||
{
|
||||
DebugConsole.ThrowError("Submarine index out of bounds (" + subIndex + ")\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Submarine index out of bounds (" + subIndex + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2818,7 +2822,7 @@ namespace Barotrauma.Networking
|
||||
if (!HasPermission(ClientPermissions.SelectMode)) return;
|
||||
if (modeIndex < 0 || modeIndex >= GameMain.NetLobbyScreen.ModeList.Content.CountChildren)
|
||||
{
|
||||
DebugConsole.ThrowError("Gamemode index out of bounds (" + modeIndex + ")\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Gamemode index out of bounds (" + modeIndex + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,12 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (((Entity)entity).Removed)
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the entity has been removed.\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the entity has been removed.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
if (((Entity)entity).IdFreed)
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the ID of the entity has been freed.\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the ID of the entity has been freed.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Failed to read event for entity \"" + entity.ToString() + "\" (" + e.Message + ")! (MidRoundSyncing: " + thisClient.MidRoundSyncing + ")\n" + e.StackTrace;
|
||||
string errorMsg = "Failed to read event for entity \"" + entity.ToString() + "\" (" + e.Message + ")! (MidRoundSyncing: " + thisClient.MidRoundSyncing + ")\n" + e.StackTrace.CleanupStackTrace();
|
||||
errorMsg += "\nPrevious entities:";
|
||||
for (int j = entities.Count - 2; j >= 0; j--)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -11,10 +10,20 @@ namespace Barotrauma.Networking
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)ChatMessageType.Order);
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(Order.Prefab));
|
||||
|
||||
msg.Write(TargetCharacter == null ? (UInt16)0 : TargetCharacter.ID);
|
||||
msg.Write(TargetEntity == null ? (UInt16)0 : TargetEntity.ID);
|
||||
msg.Write(TargetEntity is Entity ? (TargetEntity as Entity).ID : (UInt16)0);
|
||||
msg.Write((byte)Array.IndexOf(Order.Prefab.Options, OrderOption));
|
||||
if (TargetEntity is OrderTarget orderTarget)
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write(orderTarget.Position.X);
|
||||
msg.Write(orderTarget.Position.Y);
|
||||
msg.Write(orderTarget.Hull == null ? (UInt16)0 : orderTarget.Hull.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@ namespace Barotrauma.Networking
|
||||
disconnectMsg = $"DisconnectMessage.MissingContentPackages~[missingcontentpackages]={string.Join(", ", packageStrs)}";
|
||||
}
|
||||
Close(disconnectMsg, disableReconnect: true);
|
||||
OnDisconnectMessageReceived?.Invoke(DisconnectReason.MissingContentPackage + "/" + disconnectMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -373,7 +373,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
info.GameMode = element.GetAttributeString("GameMode", "");
|
||||
info.GameVersion = element.GetAttributeString("GameVersion", "");
|
||||
info.MaxPlayers = element.GetAttributeInt("MaxPlayers", 0);
|
||||
|
||||
int maxPlayersElement = element.GetAttributeInt("MaxPlayers", 0);
|
||||
|
||||
if (maxPlayersElement > NetConfig.MaxPlayers)
|
||||
{
|
||||
DebugConsole.IsOpen = true;
|
||||
DebugConsole.NewMessage($"Setting the maximum amount of players to {maxPlayersElement} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", Color.Red);
|
||||
maxPlayersElement = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
info.MaxPlayers = maxPlayersElement;
|
||||
|
||||
if (Enum.TryParse(element.GetAttributeString("PlayStyle", ""), out PlayStyle playStyleTemp)) { info.PlayStyle = playStyleTemp; }
|
||||
if (bool.TryParse(element.GetAttributeString("UsingWhiteList", ""), out bool whitelistTemp)) { info.UsingWhiteList = whitelistTemp; }
|
||||
|
||||
@@ -478,11 +478,14 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
if (rules.ContainsKey("gamestarted")) serverInfo.GameStarted = rules["gamestarted"] == "True";
|
||||
|
||||
if (rules.ContainsKey("gamemode"))
|
||||
{
|
||||
serverInfo.GameMode = rules["gamemode"];
|
||||
}
|
||||
if (rules.ContainsKey("playstyle") && Enum.TryParse(rules["playstyle"], out PlayStyle playStyle))
|
||||
{
|
||||
serverInfo.PlayStyle = playStyle;
|
||||
}
|
||||
|
||||
if (serverInfo.ContentPackageNames.Count != serverInfo.ContentPackageHashes.Count ||
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopIds.Count)
|
||||
@@ -1297,7 +1300,7 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message + "\n" + e.StackTrace;
|
||||
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace();
|
||||
if (!noLog)
|
||||
{
|
||||
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
|
||||
@@ -1492,7 +1495,7 @@ namespace Barotrauma.Steam
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace);
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
class Decal
|
||||
{
|
||||
public readonly DecalPrefab Prefab;
|
||||
private Vector2 position;
|
||||
|
||||
public readonly Sprite Sprite;
|
||||
|
||||
private float fadeTimer;
|
||||
|
||||
public float FadeTimer
|
||||
{
|
||||
get { return fadeTimer; }
|
||||
set { fadeTimer = MathHelper.Clamp(value, 0.0f, LifeTime); }
|
||||
}
|
||||
|
||||
public float FadeInTime
|
||||
{
|
||||
get { return Prefab.FadeInTime; }
|
||||
}
|
||||
|
||||
public float FadeOutTime
|
||||
{
|
||||
get { return Prefab.FadeOutTime; }
|
||||
}
|
||||
|
||||
public float LifeTime
|
||||
{
|
||||
get { return Prefab.LifeTime; }
|
||||
}
|
||||
|
||||
public Color Color
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Vector2 WorldPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector2 worldPos = position
|
||||
+ clippedSourceRect.Size.ToVector2() / 2 * scale
|
||||
+ hull.Rect.Location.ToVector2();
|
||||
if (hull.Submarine != null) { worldPos += hull.Submarine.DrawPosition; }
|
||||
return worldPos;
|
||||
}
|
||||
}
|
||||
|
||||
private Hull hull;
|
||||
|
||||
private float scale;
|
||||
|
||||
private Rectangle clippedSourceRect;
|
||||
|
||||
public Decal(DecalPrefab prefab, float scale, Vector2 worldPosition, Hull hull)
|
||||
{
|
||||
Prefab = prefab;
|
||||
|
||||
this.hull = hull;
|
||||
|
||||
//transform to hull-relative coordinates so we don't have to worry about the hull moving
|
||||
position = worldPosition - hull.WorldRect.Location.ToVector2();
|
||||
|
||||
Vector2 drawPos = position + hull.Rect.Location.ToVector2();
|
||||
|
||||
Sprite = prefab.Sprites[Rand.Range(0, prefab.Sprites.Count, Rand.RandSync.Unsynced)];
|
||||
Color = prefab.Color;
|
||||
|
||||
Rectangle drawRect = new Rectangle(
|
||||
(int)(drawPos.X - Sprite.size.X / 2 * scale),
|
||||
(int)(drawPos.Y + Sprite.size.Y / 2 * scale),
|
||||
(int)(Sprite.size.X * scale),
|
||||
(int)(Sprite.size.Y * scale));
|
||||
|
||||
Rectangle overFlowAmount = new Rectangle(
|
||||
(int)Math.Max(hull.Rect.X - drawRect.X, 0.0f),
|
||||
(int)Math.Max(drawRect.Y - hull.Rect.Y, 0.0f),
|
||||
(int)Math.Max(drawRect.Right - hull.Rect.Right, 0.0f),
|
||||
(int)Math.Max((hull.Rect.Y - hull.Rect.Height) - (drawRect.Y - drawRect.Height), 0.0f));
|
||||
|
||||
clippedSourceRect = new Rectangle(
|
||||
Sprite.SourceRect.X + (int)(overFlowAmount.X / scale),
|
||||
Sprite.SourceRect.Y + (int)(overFlowAmount.Y / scale),
|
||||
Sprite.SourceRect.Width - (int)((overFlowAmount.X + overFlowAmount.Width) / scale),
|
||||
Sprite.SourceRect.Height - (int)((overFlowAmount.Y + overFlowAmount.Height) / scale));
|
||||
|
||||
position -= new Vector2(Sprite.size.X / 2 * scale - overFlowAmount.X, -Sprite.size.Y / 2 * scale + overFlowAmount.Y);
|
||||
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
fadeTimer += deltaTime;
|
||||
}
|
||||
|
||||
public void StopFadeIn()
|
||||
{
|
||||
Color *= GetAlpha();
|
||||
fadeTimer = Prefab.FadeInTime;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private float GetAlpha()
|
||||
{
|
||||
if (fadeTimer < Prefab.FadeInTime)
|
||||
{
|
||||
return fadeTimer / Prefab.FadeInTime;
|
||||
}
|
||||
else if (fadeTimer > Prefab.LifeTime - Prefab.FadeOutTime)
|
||||
{
|
||||
return (Prefab.LifeTime - fadeTimer) / Prefab.FadeOutTime;
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
class DecalManager
|
||||
{
|
||||
public PrefabCollection<DecalPrefab> Prefabs { get; private set; }
|
||||
|
||||
public DecalManager()
|
||||
{
|
||||
Prefabs = new PrefabCollection<DecalPrefab>();
|
||||
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.Decals))
|
||||
{
|
||||
LoadFromFile(configFile);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadFromFile(ContentFile configFile)
|
||||
{
|
||||
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
||||
if (doc == null) { return; }
|
||||
|
||||
bool allowOverriding = false;
|
||||
var mainElement = doc.Root;
|
||||
if (doc.Root.IsOverride())
|
||||
{
|
||||
mainElement = doc.Root.FirstElement();
|
||||
allowOverriding = true;
|
||||
}
|
||||
|
||||
foreach (XElement sourceElement in mainElement.Elements())
|
||||
{
|
||||
var element = sourceElement.IsOverride() ? sourceElement.FirstElement() : sourceElement;
|
||||
string name = element.Name.ToString().ToLowerInvariant();
|
||||
if (Prefabs.ContainsKey(name))
|
||||
{
|
||||
if (allowOverriding || sourceElement.IsOverride())
|
||||
{
|
||||
DebugConsole.NewMessage($"Overriding the existing decal prefab '{name}' using the file '{configFile.Path}'", Color.Yellow);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in '{configFile.Path}': Duplicate decal prefab '{name}' found in '{configFile.Path}'! Each decal prefab must have a unique name. " +
|
||||
"Use <override></override> tags to override prefabs.");
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Prefabs.Add(new DecalPrefab(element, configFile), allowOverriding || sourceElement.IsOverride());
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveByFile(string filePath)
|
||||
{
|
||||
Prefabs.RemoveByFile(filePath);
|
||||
}
|
||||
|
||||
public Decal CreateDecal(string decalName, float scale, Vector2 worldPosition, Hull hull)
|
||||
{
|
||||
if (!Prefabs.ContainsKey(decalName.ToLowerInvariant()))
|
||||
{
|
||||
DebugConsole.ThrowError("Decal prefab " + decalName + " not found!");
|
||||
return null;
|
||||
}
|
||||
|
||||
DecalPrefab prefab = Prefabs[decalName];
|
||||
|
||||
return new Decal(prefab, scale, worldPosition, hull);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Particles
|
||||
{
|
||||
class DecalPrefab : IPrefab, IDisposable
|
||||
{
|
||||
public readonly string Name;
|
||||
|
||||
public string OriginalName { get { return Name; } }
|
||||
|
||||
private string _identifier;
|
||||
public string Identifier
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_identifier == null)
|
||||
{
|
||||
_identifier = Name.ToLowerInvariant();
|
||||
}
|
||||
return _identifier;
|
||||
}
|
||||
}
|
||||
|
||||
public string FilePath { get; private set; }
|
||||
|
||||
public ContentPackage ContentPackage { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (Sprite spr in Sprites)
|
||||
{
|
||||
spr.Remove();
|
||||
}
|
||||
Sprites.Clear();
|
||||
}
|
||||
|
||||
public readonly List<Sprite> Sprites;
|
||||
|
||||
public readonly Color Color;
|
||||
|
||||
public readonly float LifeTime;
|
||||
public readonly float FadeOutTime;
|
||||
public readonly float FadeInTime;
|
||||
|
||||
public DecalPrefab(XElement element, ContentFile file)
|
||||
{
|
||||
Name = element.Name.ToString();
|
||||
|
||||
FilePath = file.Path;
|
||||
|
||||
ContentPackage = file.ContentPackage;
|
||||
|
||||
Sprites = new List<Sprite>();
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().Equals("sprite", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Sprites.Add(new Sprite(subElement));
|
||||
}
|
||||
}
|
||||
|
||||
Color = new Color(element.GetAttributeVector4("color", Vector4.One));
|
||||
|
||||
LifeTime = element.GetAttributeFloat("lifetime", 10.0f);
|
||||
FadeOutTime = Math.Min(LifeTime, element.GetAttributeFloat("fadeouttime", 1.0f));
|
||||
FadeInTime = Math.Min(LifeTime - FadeOutTime, element.GetAttributeFloat("fadeintime", 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,7 +483,7 @@ namespace Barotrauma.Particles
|
||||
|
||||
if (prefab.GrowTime > 0.0f && totalLifeTime - lifeTime < prefab.GrowTime)
|
||||
{
|
||||
drawSize *= ((totalLifeTime - lifeTime) / prefab.GrowTime);
|
||||
drawSize *= MathUtils.SmoothStep((totalLifeTime - lifeTime) / prefab.GrowTime);
|
||||
}
|
||||
|
||||
Color currColor = new Color(color.ToVector4() * ColorMultiplier);
|
||||
|
||||
@@ -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, Color? colorMultiplier = null)
|
||||
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, ParticlePrefab overrideParticle = 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, colorMultiplier);
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle);
|
||||
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, colorMultiplier);
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle);
|
||||
}
|
||||
}
|
||||
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null)
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null)
|
||||
{
|
||||
angle += Rand.Range(Prefab.AngleMin, Prefab.AngleMax);
|
||||
|
||||
@@ -55,13 +55,20 @@ namespace Barotrauma.Particles
|
||||
Vector2 velocity = dir * Rand.Range(Prefab.VelocityMin, Prefab.VelocityMax) * velocityMultiplier;
|
||||
position += dir * Rand.Range(Prefab.DistanceMin, Prefab.DistanceMax);
|
||||
|
||||
var particle = GameMain.ParticleManager.CreateParticle(Prefab.ParticlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop);
|
||||
var particle = GameMain.ParticleManager.CreateParticle(overrideParticle ?? Prefab.ParticlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop);
|
||||
|
||||
if (particle != null)
|
||||
{
|
||||
particle.Size *= Rand.Range(Prefab.ScaleMin, Prefab.ScaleMax) * sizeMultiplier;
|
||||
particle.HighQualityCollisionDetection = Prefab.HighQualityCollisionDetection;
|
||||
if (colorMultiplier.HasValue) { particle.ColorMultiplier = colorMultiplier.Value.ToVector4(); }
|
||||
if (colorMultiplier.HasValue)
|
||||
{
|
||||
particle.ColorMultiplier = colorMultiplier.Value.ToVector4();
|
||||
}
|
||||
else if (Prefab.ColorMultiplier != Color.White)
|
||||
{
|
||||
particle.ColorMultiplier = Prefab.ColorMultiplier.ToVector4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +145,8 @@ namespace Barotrauma.Particles
|
||||
|
||||
public readonly bool CopyEntityAngle;
|
||||
|
||||
public readonly Color ColorMultiplier;
|
||||
|
||||
public bool DrawOnTop => forceDrawOnTop || ParticlePrefab.DrawOnTop;
|
||||
private readonly bool forceDrawOnTop;
|
||||
|
||||
@@ -204,11 +213,12 @@ namespace Barotrauma.Particles
|
||||
}
|
||||
|
||||
EmitInterval = element.GetAttributeFloat("emitinterval", 0.0f);
|
||||
ParticlesPerSecond = element.GetAttributeInt("particlespersecond", 0);
|
||||
ParticlesPerSecond = element.GetAttributeFloat("particlespersecond", 0);
|
||||
ParticleAmount = element.GetAttributeInt("particleamount", 0);
|
||||
HighQualityCollisionDetection = element.GetAttributeBool("highqualitycollisiondetection", false);
|
||||
CopyEntityAngle = element.GetAttributeBool("copyentityangle", false);
|
||||
forceDrawOnTop = element.GetAttributeBool("drawontop", false);
|
||||
forceDrawOnTop = element.GetAttributeBool("drawontop", false);
|
||||
ColorMultiplier = element.GetAttributeColor("colormultiplier", Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Barotrauma
|
||||
}
|
||||
sb.AppendLine("\n");
|
||||
sb.AppendLine("Game version " + GameMain.Version +
|
||||
" (" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")");
|
||||
" (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")");
|
||||
if (GameMain.Config != null)
|
||||
{
|
||||
sb.AppendLine("Graphics mode: " + GameMain.Config.GraphicsWidth + "x" + GameMain.Config.GraphicsHeight + " (" + GameMain.Config.WindowMode.ToString() + ")");
|
||||
@@ -219,7 +219,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
sb.AppendLine("Stack trace: ");
|
||||
sb.AppendLine(exception.StackTrace);
|
||||
sb.AppendLine(exception.StackTrace.CleanupStackTrace());
|
||||
sb.AppendLine("\n");
|
||||
|
||||
if (exception.InnerException != null)
|
||||
@@ -230,7 +230,7 @@ namespace Barotrauma
|
||||
sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString());
|
||||
}
|
||||
sb.AppendLine("Stack trace: ");
|
||||
sb.AppendLine(exception.InnerException.StackTrace);
|
||||
sb.AppendLine(exception.InnerException.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
|
||||
sb.AppendLine("Last debug messages:");
|
||||
|
||||
@@ -374,6 +374,14 @@ namespace Barotrauma.CharacterEditor
|
||||
if (Wizard.instance != null) { return; }
|
||||
spriteSheetRect = CalculateSpritesheetRectangle();
|
||||
// Handle shortcut keys
|
||||
if (PlayerInput.KeyHit(Keys.F1))
|
||||
{
|
||||
SetToggle(paramsToggle, !paramsToggle.Selected);
|
||||
}
|
||||
if (PlayerInput.KeyHit(Keys.F5))
|
||||
{
|
||||
RecreateRagdoll();
|
||||
}
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.D1))
|
||||
@@ -445,10 +453,6 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
SetToggle(showCollidersToggle, !showCollidersToggle.Selected);
|
||||
}
|
||||
if (PlayerInput.KeyHit(Keys.Tab))
|
||||
{
|
||||
SetToggle(paramsToggle, !paramsToggle.Selected);
|
||||
}
|
||||
if (PlayerInput.KeyHit(Keys.L))
|
||||
{
|
||||
SetToggle(lightsToggle, !lightsToggle.Selected);
|
||||
@@ -469,10 +473,6 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
SetToggle(ikToggle, !ikToggle.Selected);
|
||||
}
|
||||
if (PlayerInput.KeyHit(Keys.F5))
|
||||
{
|
||||
RecreateRagdoll();
|
||||
}
|
||||
}
|
||||
if (PlayerInput.KeyDown(InputType.Left) || PlayerInput.KeyDown(InputType.Right) || PlayerInput.KeyDown(InputType.Up) || PlayerInput.KeyDown(InputType.Down))
|
||||
{
|
||||
@@ -809,7 +809,13 @@ namespace Barotrauma.CharacterEditor
|
||||
else if (showColliders)
|
||||
{
|
||||
character.AnimController.Collider.DebugDraw(spriteBatch, Color.White, forceColor: true);
|
||||
character.AnimController.Limbs.ForEach(l => l.body.DebugDraw(spriteBatch, GUI.Style.Green, forceColor: true));
|
||||
foreach (var limb in character.AnimController.Limbs)
|
||||
{
|
||||
if (!limb.Hide)
|
||||
{
|
||||
limb.body.DebugDraw(spriteBatch, GUI.Style.Green, forceColor: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
@@ -953,14 +959,14 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
UpdateOtherLimbs(lastLimb, l => TryUpdateSubParam(l.Params, "spriteorientation", angle));
|
||||
}
|
||||
}, circleRadius: 40, widgetSize: 15, rotationOffset: MathHelper.Pi, autoFreeze: false, rounding: 10);
|
||||
}, circleRadius: 40, widgetSize: 15, rotationOffset: 0, autoFreeze: false, rounding: 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
var topLeft = spriteSheetControls.RectTransform.TopLeft;
|
||||
GUI.DrawString(spriteBatch, new Vector2(topLeft.X + 350 * GUI.xScale, GameMain.GraphicsHeight - 95 * GUI.yScale), GetCharacterEditorTranslation("SpriteSheetOrientation") + ":", Color.White, Color.Gray * 0.5f, 10, GUI.Font);
|
||||
DrawRadialWidget(spriteBatch, new Vector2(topLeft.X + 610 * GUI.xScale, GameMain.GraphicsHeight - 75 * GUI.yScale), RagdollParams.SpritesheetOrientation, string.Empty, Color.White,
|
||||
angle => TryUpdateRagdollParam("spritesheetorientation", angle), circleRadius: 40, widgetSize: 15, rotationOffset: MathHelper.Pi, autoFreeze: false, rounding: 10);
|
||||
angle => TryUpdateRagdollParam("spritesheetorientation", angle), circleRadius: 40, widgetSize: 15, rotationOffset: 0, autoFreeze: false, rounding: 10);
|
||||
}
|
||||
}
|
||||
// Debug
|
||||
@@ -2780,9 +2786,7 @@ namespace Barotrauma.CharacterEditor
|
||||
};
|
||||
// Spacing
|
||||
new GUIFrame(new RectTransform(buttonSize / 2, layoutGroup.RectTransform), style: null) { CanBeFocused = false };
|
||||
Vector2 messageBoxRelSize = new Vector2(0.5f, 0.5f);
|
||||
int messageBoxWidth = GameMain.GraphicsWidth / 2;
|
||||
int messageBoxHeight = GameMain.GraphicsHeight / 2;
|
||||
Vector2 messageBoxRelSize = new Vector2(0.5f, 0.7f);
|
||||
var saveRagdollButton = new GUIButton(new RectTransform(buttonSize, layoutGroup.RectTransform), GetCharacterEditorTranslation("SaveRagdoll"));
|
||||
saveRagdollButton.OnClicked += (button, userData) =>
|
||||
{
|
||||
@@ -2902,12 +2906,12 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
var box = new GUIMessageBox(GetCharacterEditorTranslation("SaveAnimation"), string.Empty, new string[] { TextManager.Get("Cancel"), TextManager.Get("Save") }, messageBoxRelSize);
|
||||
var textArea = new GUIFrame(new RectTransform(new Vector2(1, 0.1f), box.Content.RectTransform) { MinSize = new Point(350, 30) }, style: null);
|
||||
var inputLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), textArea.RectTransform) { MinSize = new Point(250, 30) }, $"{GetCharacterEditorTranslation("ProvideFileName")}: ");
|
||||
var inputField = new GUITextBox(new RectTransform(new Vector2(0.5f, 1), textArea.RectTransform, Anchor.TopRight) { MinSize = new Point(100, 30) }, CurrentAnimation.Name);
|
||||
var inputLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1), textArea.RectTransform, Anchor.CenterLeft) { MinSize = new Point(250, 30) }, $"{GetCharacterEditorTranslation("ProvideFileName")}: ");
|
||||
var inputField = new GUITextBox(new RectTransform(new Vector2(0.45f, 1), textArea.RectTransform, Anchor.CenterRight) { MinSize = new Point(100, 30) }, CurrentAnimation.Name);
|
||||
// Type filtering
|
||||
var typeSelectionArea = new GUIFrame(new RectTransform(new Vector2(1f, 0.1f), box.Content.RectTransform) { MinSize = new Point(0, 30) }, style: null);
|
||||
var typeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), typeSelectionArea.RectTransform, Anchor.TopCenter, Pivot.TopRight), $"{GetCharacterEditorTranslation("SelectAnimationType")}: ");
|
||||
var typeDropdown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1), typeSelectionArea.RectTransform, Anchor.TopCenter, Pivot.TopLeft), elementCount: 4);
|
||||
var typeLabel = new GUITextBlock(new RectTransform(new Vector2(0.45f, 1), typeSelectionArea.RectTransform, Anchor.CenterLeft), $"{GetCharacterEditorTranslation("SelectAnimationType")}: ");
|
||||
var typeDropdown = new GUIDropDown(new RectTransform(new Vector2(0.45f, 1), typeSelectionArea.RectTransform, Anchor.CenterRight), elementCount: 4);
|
||||
foreach (object enumValue in Enum.GetValues(typeof(AnimationType)))
|
||||
{
|
||||
if (!(enumValue is AnimationType.NotDefined))
|
||||
@@ -2958,8 +2962,8 @@ namespace Barotrauma.CharacterEditor
|
||||
deleteButton.Enabled = false;
|
||||
// Type filtering
|
||||
var typeSelectionArea = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.1f), loadBox.Content.RectTransform) { MinSize = new Point(0, 30) }, style: null);
|
||||
var typeLabel = new GUITextBlock(new RectTransform(new Vector2(0.4f, 1), typeSelectionArea.RectTransform, Anchor.TopCenter, Pivot.TopRight), $"{GetCharacterEditorTranslation("SelectAnimationType")}: ");
|
||||
var typeDropdown = new GUIDropDown(new RectTransform(new Vector2(0.4f, 1), typeSelectionArea.RectTransform, Anchor.TopCenter, Pivot.TopLeft), elementCount: 4);
|
||||
var typeLabel = new GUITextBlock(new RectTransform(new Vector2(0.45f, 1), typeSelectionArea.RectTransform, Anchor.CenterLeft), $"{GetCharacterEditorTranslation("SelectAnimationType")}: ");
|
||||
var typeDropdown = new GUIDropDown(new RectTransform(new Vector2(0.45f, 1), typeSelectionArea.RectTransform, Anchor.CenterRight), elementCount: 4);
|
||||
foreach (object enumValue in Enum.GetValues(typeof(AnimationType)))
|
||||
{
|
||||
if (!(enumValue is AnimationType.NotDefined))
|
||||
@@ -3499,12 +3503,8 @@ namespace Barotrauma.CharacterEditor
|
||||
limbJoint.UpperLimit += MathHelper.TwoPi;
|
||||
}
|
||||
}
|
||||
|
||||
if (limbJoint.UpperLimit - limbJoint.LowerLimit > MathHelper.TwoPi)
|
||||
{
|
||||
limbJoint.LowerLimit = MathUtils.WrapAnglePi(limbJoint.LowerLimit);
|
||||
limbJoint.UpperLimit = MathUtils.WrapAnglePi(limbJoint.UpperLimit);
|
||||
}
|
||||
limbJoint.LowerLimit = MathUtils.WrapAnglePi(limbJoint.LowerLimit);
|
||||
limbJoint.UpperLimit = MathUtils.WrapAnglePi(limbJoint.UpperLimit);
|
||||
}
|
||||
|
||||
private Limb GetClosestLimbOnRagdoll(Vector2 targetPos, Func<Limb, bool> filter = null)
|
||||
@@ -4392,7 +4392,7 @@ namespace Barotrauma.CharacterEditor
|
||||
|
||||
if (!altDown && editJoints && selectedJoints.Any() && jointCreationMode == JointCreationMode.None)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2 - 180, 250), GetCharacterEditorTranslation("HoldLeftAltToManipulateJoint"), Color.White, Color.Black * 0.5f, 10, GUI.Font);
|
||||
GUI.DrawString(spriteBatch, new Vector2(GameMain.GraphicsWidth / 2 - 180, 100), GetCharacterEditorTranslation("HoldLeftAltToManipulateJoint"), Color.White, Color.Black * 0.5f, 10, GUI.Font);
|
||||
}
|
||||
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
@@ -4465,7 +4465,13 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
if (joint.LimitEnabled && jointCreationMode == JointCreationMode.None)
|
||||
{
|
||||
DrawJointLimitWidgets(spriteBatch, limb, joint, tformedJointPos, autoFreeze: true, allowPairEditing: true, rotationOffset: limb.Rotation, holdPosition: true);
|
||||
var otherBody = limb == joint.LimbA ? joint.LimbB : joint.LimbA;
|
||||
float rotation = -otherBody.Rotation + limb.Params.GetSpriteOrientation();
|
||||
if (character.AnimController.Dir < 0)
|
||||
{
|
||||
rotation -= MathHelper.Pi;
|
||||
}
|
||||
DrawJointLimitWidgets(spriteBatch, limb, joint, tformedJointPos, autoFreeze: true, allowPairEditing: true, rotationOffset: rotation, holdPosition: true);
|
||||
}
|
||||
// Is the direction inversed incorrectly?
|
||||
Vector2 to = tformedJointPos + VectorExtensions.ForwardFlipped(joint.LimbB.Rotation - joint.LimbB.Params.GetSpriteOrientation(), 20);
|
||||
@@ -4898,7 +4904,7 @@ namespace Barotrauma.CharacterEditor
|
||||
void RecalculateCollider(Limb l)
|
||||
{
|
||||
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
|
||||
float multiplier = 0.85f;
|
||||
float multiplier = 0.9f;
|
||||
l.body.SetSize(new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * l.Scale * RagdollParams.TextureScale * multiplier);
|
||||
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
|
||||
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
|
||||
@@ -5010,7 +5016,7 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
if (joint.LimitEnabled && jointCreationMode == JointCreationMode.None)
|
||||
{
|
||||
DrawJointLimitWidgets(spriteBatch, limb, joint, tformedJointPos, autoFreeze: false, allowPairEditing: true, holdPosition: false);
|
||||
DrawJointLimitWidgets(spriteBatch, limb, joint, tformedJointPos, autoFreeze: false, allowPairEditing: true, holdPosition: false, rotationOffset: joint.LimbB.Params.GetSpriteOrientation());
|
||||
}
|
||||
if (jointSelectionWidget.IsControlled)
|
||||
{
|
||||
@@ -5071,7 +5077,7 @@ namespace Barotrauma.CharacterEditor
|
||||
|
||||
private void DrawJointLimitWidgets(SpriteBatch spriteBatch, Limb limb, LimbJoint joint, Vector2 drawPos, bool autoFreeze, bool allowPairEditing, bool holdPosition, float rotationOffset = 0)
|
||||
{
|
||||
rotationOffset -= limb.Params.GetSpriteOrientation();
|
||||
bool clockWise = joint.Params.ClockWiseRotation;
|
||||
Color angleColor = joint.UpperLimit - joint.LowerLimit > 0 ? GUI.Style.Green * 0.5f : GUI.Style.Red;
|
||||
DrawRadialWidget(spriteBatch, drawPos, MathHelper.ToDegrees(joint.UpperLimit), $"{joint.Params.Name}: {GetCharacterEditorTranslation("UpperLimit")}", Color.Cyan, angle =>
|
||||
{
|
||||
@@ -5111,7 +5117,7 @@ namespace Barotrauma.CharacterEditor
|
||||
DrawAngle(20, angleColor, 4);
|
||||
DrawAngle(40, Color.Cyan);
|
||||
GUI.DrawString(spriteBatch, drawPos, angle.FormatZeroDecimal(), Color.Black, backgroundColor: Color.Cyan, font: GUI.SmallFont);
|
||||
}, circleRadius: 40, rotationOffset: rotationOffset, displayAngle: false, clockWise: false, holdPosition: holdPosition);
|
||||
}, circleRadius: 40, rotationOffset: rotationOffset, displayAngle: false, clockWise: clockWise, holdPosition: holdPosition);
|
||||
DrawRadialWidget(spriteBatch, drawPos, MathHelper.ToDegrees(joint.LowerLimit), $"{joint.Params.Name}: {GetCharacterEditorTranslation("LowerLimit")}", Color.Yellow, angle =>
|
||||
{
|
||||
joint.LowerLimit = MathHelper.ToRadians(angle);
|
||||
@@ -5150,12 +5156,12 @@ namespace Barotrauma.CharacterEditor
|
||||
DrawAngle(20, angleColor, 4);
|
||||
DrawAngle(25, Color.Yellow);
|
||||
GUI.DrawString(spriteBatch, drawPos, angle.FormatZeroDecimal(), Color.Black, backgroundColor: Color.Yellow, font: GUI.SmallFont);
|
||||
}, circleRadius: 25, rotationOffset: rotationOffset, displayAngle: false, clockWise: false, holdPosition: holdPosition);
|
||||
}, circleRadius: 25, rotationOffset: rotationOffset, displayAngle: false, clockWise: clockWise, holdPosition: holdPosition);
|
||||
void DrawAngle(float radius, Color color, float thickness = 5)
|
||||
{
|
||||
float angle = joint.UpperLimit - joint.LowerLimit;
|
||||
ShapeExtensions.DrawSector(spriteBatch, drawPos, radius, angle, 40, color,
|
||||
offset: -rotationOffset - joint.UpperLimit + MathHelper.PiOver2, thickness: thickness);
|
||||
float offset = clockWise ? rotationOffset + joint.LowerLimit - MathHelper.PiOver2 : rotationOffset - joint.UpperLimit - MathHelper.PiOver2;
|
||||
ShapeExtensions.DrawSector(spriteBatch, drawPos, radius, angle, 40, color, offset: offset, thickness: thickness);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5244,8 +5250,8 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
angle = 0;
|
||||
}
|
||||
float drawAngle = clockWise ? -angle : angle;
|
||||
var widgetDrawPos = drawPos + VectorExtensions.ForwardFlipped(MathHelper.ToRadians(drawAngle) + rotationOffset, circleRadius);
|
||||
float drawAngle = clockWise ? angle : -angle;
|
||||
var widgetDrawPos = drawPos + VectorExtensions.Forward(MathHelper.ToRadians(drawAngle) + rotationOffset - MathHelper.PiOver2, circleRadius);
|
||||
GUI.DrawLine(spriteBatch, drawPos, widgetDrawPos, color);
|
||||
DrawWidget(spriteBatch, widgetDrawPos, WidgetType.Rectangle, widgetSize, color, toolTip, () =>
|
||||
{
|
||||
@@ -5253,8 +5259,8 @@ namespace Barotrauma.CharacterEditor
|
||||
ShapeExtensions.DrawCircle(spriteBatch, drawPos, circleRadius, 40, color, thickness: 1);
|
||||
Vector2 d = PlayerInput.MousePosition - drawPos;
|
||||
float newAngle = clockWise
|
||||
? MathUtils.VectorToAngle(d) - MathHelper.PiOver2 + rotationOffset
|
||||
: -MathUtils.VectorToAngle(d) + MathHelper.PiOver2 - rotationOffset;
|
||||
? MathUtils.VectorToAngle(d) + MathHelper.PiOver2 - rotationOffset
|
||||
: -MathUtils.VectorToAngle(d) - MathHelper.PiOver2 + rotationOffset;
|
||||
angle = MathHelper.ToDegrees(wrapAnglePi ? MathUtils.WrapAnglePi(newAngle) : MathUtils.WrapAngleTwoPi(newAngle));
|
||||
angle = (float)Math.Round(angle / rounding) * rounding;
|
||||
if (angle >= 360 || angle <= -360) { angle = 0; }
|
||||
@@ -5263,7 +5269,7 @@ namespace Barotrauma.CharacterEditor
|
||||
GUI.DrawString(spriteBatch, drawPos, angle.FormatZeroDecimal(), Color.Black, backgroundColor: color, font: GUI.SmallFont);
|
||||
}
|
||||
onClick(angle);
|
||||
var zeroPos = drawPos + VectorExtensions.ForwardFlipped(rotationOffset, circleRadius);
|
||||
var zeroPos = drawPos + VectorExtensions.Forward(rotationOffset - MathHelper.PiOver2, circleRadius);
|
||||
GUI.DrawLine(spriteBatch, drawPos, zeroPos, GUI.Style.Red, width: 3);
|
||||
}, autoFreeze, holdPosition, onHovered: () =>
|
||||
{
|
||||
|
||||
@@ -75,6 +75,17 @@ namespace Barotrauma
|
||||
{
|
||||
Character.Controlled.SelectedConstruction.AddToGUIUpdateList();
|
||||
}
|
||||
if (Character.Controlled?.Inventory != null)
|
||||
{
|
||||
foreach (Item item in Character.Controlled.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
if (Character.Controlled.HasEquippedItem(item))
|
||||
{
|
||||
item.AddToGUIUpdateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null) GameMain.GameSession.AddToGUIUpdateList();
|
||||
|
||||
|
||||
@@ -335,6 +335,7 @@ namespace Barotrauma
|
||||
{
|
||||
base.Select();
|
||||
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
pointerLightSource = new LightSource(Vector2.Zero, 1000.0f, Color.White, submarine: null);
|
||||
GameMain.LightManager.AddLight(pointerLightSource);
|
||||
topPanel.ClearChildren();
|
||||
|
||||
@@ -424,6 +424,8 @@ namespace Barotrauma
|
||||
#region Selection
|
||||
public override void Select()
|
||||
{
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
|
||||
base.Select();
|
||||
|
||||
if (GameMain.Client != null)
|
||||
@@ -806,19 +808,6 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool JoinServerClicked(GUIButton button, object obj)
|
||||
{
|
||||
GameMain.ServerListScreen.Select();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool SteamWorkshopClicked(GUIButton button, object obj)
|
||||
{
|
||||
if (!Steam.SteamManager.IsInitialized) { return false; }
|
||||
GameMain.SteamWorkshopScreen.Select();
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ChangeMaxPlayers(GUIButton button, object obj)
|
||||
{
|
||||
int.TryParse(maxPlayersBox.Text, out int currMaxPlayers);
|
||||
@@ -829,33 +818,10 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HostServerClicked(GUIButton button, object obj)
|
||||
private void StartServer()
|
||||
{
|
||||
string name = serverNameBox.Text;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
serverNameBox.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*if (!int.TryParse(portBox.Text, out int port) || port < 0 || port > 65535)
|
||||
{
|
||||
portBox.Text = NetConfig.DefaultPort.ToString();
|
||||
portBox.Flash();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int queryPort = 0;
|
||||
#if USE_STEAM
|
||||
if (!int.TryParse(queryPortBox.Text, out queryPort) || queryPort < 0 || queryPort > 65535)
|
||||
{
|
||||
portBox.Text = NetConfig.DefaultQueryPort.ToString();
|
||||
portBox.Flash();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
GameMain.NetLobbyScreen?.Release();
|
||||
GameMain.NetLobbyScreen = new NetLobbyScreen();
|
||||
try
|
||||
@@ -913,14 +879,13 @@ namespace Barotrauma
|
||||
ChildServerRelay.Start(processInfo);
|
||||
Thread.Sleep(1000); //wait until the server is ready before connecting
|
||||
|
||||
GameMain.Client = new GameClient(name, System.Net.IPAddress.Loopback.ToString(), Steam.SteamManager.GetSteamID(), name, ownerKey, true);
|
||||
GameMain.Client = new GameClient(string.IsNullOrEmpty(GameMain.Config.PlayerName) ? name : GameMain.Config.PlayerName,
|
||||
System.Net.IPAddress.Loopback.ToString(), Steam.SteamManager.GetSteamID(), name, ownerKey, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to start server", e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool QuitClicked(GUIButton button, object obj)
|
||||
@@ -996,7 +961,7 @@ namespace Barotrauma
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
#if !UNSTABLE
|
||||
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")";
|
||||
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
|
||||
GUI.SmallFont.DrawString(spriteBatch, versionString, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.MeasureString(versionString).Y - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
|
||||
#endif
|
||||
if (selectedTab != Tab.Credits)
|
||||
@@ -1062,7 +1027,7 @@ namespace Barotrauma
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"MainMenuScreen.StartGame:IOException" + selectedSub.Name,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Copying the file \"" + selectedSub.FilePath + "\" failed.\n" + e.Message + "\n" + Environment.StackTrace);
|
||||
"Copying the file \"" + selectedSub.FilePath + "\" failed.\n" + e.Message + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1139,7 +1104,16 @@ namespace Barotrauma
|
||||
{
|
||||
port = settingsDoc.Root.GetAttributeInt("port", port);
|
||||
queryPort = settingsDoc.Root.GetAttributeInt("queryport", queryPort);
|
||||
maxPlayers = settingsDoc.Root.GetAttributeInt("maxplayers", maxPlayers);
|
||||
|
||||
int maxPlayersElement = settingsDoc.Root.GetAttributeInt("maxplayers", maxPlayers);
|
||||
if (maxPlayersElement > NetConfig.MaxPlayers)
|
||||
{
|
||||
DebugConsole.IsOpen = true;
|
||||
DebugConsole.NewMessage($"Setting the maximum amount of players to {maxPlayersElement} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", Color.Red);
|
||||
maxPlayersElement = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
maxPlayers = maxPlayersElement;
|
||||
karmaEnabled = settingsDoc.Root.GetAttributeBool("karmaenabled", true);
|
||||
selectedKarmaPreset = settingsDoc.Root.GetAttributeString("karmapreset", "default");
|
||||
string playStyleStr = settingsDoc.Root.GetAttributeString("playstyle", "Casual");
|
||||
@@ -1334,7 +1308,35 @@ namespace Barotrauma
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 0.07f), content.RectTransform), TextManager.Get("StartServerButton"), style: "GUIButtonLarge")
|
||||
{
|
||||
OnClicked = HostServerClicked
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
string name = serverNameBox.Text;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
serverNameBox.Flash();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ForbiddenWordFilter.IsForbidden(name, out string forbiddenWord))
|
||||
{
|
||||
var msgBox = new GUIMessageBox("",
|
||||
TextManager.GetWithVariables("forbiddenservernameverification", new string[] { "[forbiddenword]", "[servername]" }, new string[] { forbiddenWord, name }),
|
||||
new string[] { TextManager.Get("yes"), TextManager.Get("no") });
|
||||
msgBox.Buttons[0].OnClicked += (_, __) =>
|
||||
{
|
||||
StartServer();
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
}
|
||||
else
|
||||
{
|
||||
StartServer();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1169,7 +1169,7 @@ namespace Barotrauma
|
||||
|
||||
Character.Controlled = null;
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
CampaignCharacterDiscarded = false;
|
||||
|
||||
chatInput.Select();
|
||||
@@ -2799,7 +2799,7 @@ namespace Barotrauma
|
||||
var variantButton = CreateJobVariantButton(jobPrefab, variantIndex, images.Length, jobButton);
|
||||
variantButton.OnClicked = (btn, obj) =>
|
||||
{
|
||||
currSelected.Selected = false;
|
||||
if (currSelected != null) { currSelected.Selected = false; }
|
||||
int k = ((Pair<JobPrefab, int>)obj).Second;
|
||||
btn.Parent.UserData = obj;
|
||||
for (int j = 0; j < images.Length; j++)
|
||||
|
||||
@@ -153,6 +153,7 @@ namespace Barotrauma
|
||||
private GUITickBox filterVoip;
|
||||
private List<GUITickBox> playStyleTickBoxes;
|
||||
private List<GUITickBox> gameModeTickBoxes;
|
||||
private GUITickBox filterOffensive;
|
||||
|
||||
private string sortedBy;
|
||||
|
||||
@@ -325,7 +326,7 @@ namespace Barotrauma
|
||||
|
||||
filterSameVersion = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterSameVersion"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterSameVersion"),
|
||||
UserData = TextManager.Get("FilterSameVersion"),
|
||||
Selected = true,
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
@@ -333,39 +334,47 @@ namespace Barotrauma
|
||||
|
||||
filterPassword = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterPassword"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterPassword"),
|
||||
UserData = TextManager.Get("FilterPassword"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterPassword.TextBlock);
|
||||
|
||||
filterIncompatible = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterIncompatibleServers"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterIncompatibleServers"),
|
||||
UserData = TextManager.Get("FilterIncompatibleServers"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterIncompatible.TextBlock);
|
||||
|
||||
filterFull = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterFullServers"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterFullServers"),
|
||||
UserData = TextManager.Get("FilterFullServers"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterFull.TextBlock);
|
||||
|
||||
filterEmpty = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterEmptyServers"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterEmptyServers"),
|
||||
UserData = TextManager.Get("FilterEmptyServers"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterEmpty.TextBlock);
|
||||
|
||||
filterWhitelisted = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterWhitelistedServers"))
|
||||
{
|
||||
ToolTip = TextManager.Get("FilterWhitelistedServers"),
|
||||
UserData = TextManager.Get("FilterWhitelistedServers"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterWhitelisted.TextBlock);
|
||||
|
||||
filterOffensive = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("FilterOffensiveServers"))
|
||||
{
|
||||
UserData = TextManager.Get("FilterOffensiveServers"),
|
||||
ToolTip = TextManager.Get("FilterOffensiveServersToolTip"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterOffensive.TextBlock);
|
||||
|
||||
// Filter Tags
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), filters.Content.RectTransform), TextManager.Get("servertags"), font: GUI.SubHeadingFont)
|
||||
{
|
||||
@@ -374,35 +383,35 @@ namespace Barotrauma
|
||||
|
||||
filterKarma = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.karma.true"))
|
||||
{
|
||||
ToolTip = TextManager.Get("servertag.karma.true"),
|
||||
UserData = TextManager.Get("servertag.karma.true"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterKarma.TextBlock);
|
||||
|
||||
filterTraitor = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.traitors.true"))
|
||||
{
|
||||
ToolTip = TextManager.Get("servertag.traitors.true"),
|
||||
UserData = TextManager.Get("servertag.traitors.true"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterTraitor.TextBlock);
|
||||
|
||||
filterFriendlyFire = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.friendlyfire.false"))
|
||||
{
|
||||
ToolTip = TextManager.Get("servertag.friendlyfire.false"),
|
||||
UserData = TextManager.Get("servertag.friendlyfire.false"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterFriendlyFire.TextBlock);
|
||||
|
||||
filterVoip = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.voip.false"))
|
||||
{
|
||||
ToolTip = TextManager.Get("servertag.voip.false"),
|
||||
UserData = TextManager.Get("servertag.voip.false"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterVoip.TextBlock);
|
||||
|
||||
filterModded = new GUITickBox(new RectTransform(new Vector2(1.0f, elementHeight), filters.Content.RectTransform), TextManager.Get("servertag.modded.true"))
|
||||
{
|
||||
ToolTip = TextManager.Get("servertag.modded.true"),
|
||||
UserData = TextManager.Get("servertag.modded.true"),
|
||||
OnSelected = (tickBox) => { FilterServers(); return true; }
|
||||
};
|
||||
filterTextList.Add(filterModded.TextBlock);
|
||||
@@ -449,7 +458,9 @@ namespace Barotrauma
|
||||
filters.Content.RectTransform.SizeChanged += () =>
|
||||
{
|
||||
filters.Content.RectTransform.RecalculateChildren(true, true);
|
||||
filterTextList.ForEach(t => t.Text = t.ToolTip);
|
||||
filterTextList.ForEach(t => t.Text = t.Parent.Parent.UserData as string);
|
||||
gameModeTickBoxes.ForEach(tb => tb.Text = tb.ToolTip);
|
||||
playStyleTickBoxes.ForEach(tb => tb.Text = tb.ToolTip);
|
||||
GUITextBlock.AutoScaleAndNormalize(filterTextList, defaultScale: 1.0f);
|
||||
if (filterTextList[0].TextScale < 0.8f)
|
||||
{
|
||||
@@ -579,7 +590,7 @@ namespace Barotrauma
|
||||
{
|
||||
ClientNameBox.Flash();
|
||||
ClientNameBox.Select();
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
return false;
|
||||
}
|
||||
ShowDirectJoinPrompt();
|
||||
@@ -1050,6 +1061,7 @@ namespace Barotrauma
|
||||
(!filterFull.Selected || serverInfo.PlayerCount < serverInfo.MaxPlayers) &&
|
||||
(!filterEmpty.Selected || serverInfo.PlayerCount > 0) &&
|
||||
(!filterWhitelisted.Selected || serverInfo.UsingWhiteList == true) &&
|
||||
(filterOffensive.Selected || !ForbiddenWordFilter.IsForbidden(serverInfo.ServerName)) &&
|
||||
(!filterKarma.Selected || serverInfo.KarmaEnabled == true) &&
|
||||
(!filterFriendlyFire.Selected || serverInfo.FriendlyFireEnabled == false) &&
|
||||
(!filterTraitor.Selected || serverInfo.TraitorsEnabled == YesNoMaybe.Yes || serverInfo.TraitorsEnabled == YesNoMaybe.Maybe) &&
|
||||
@@ -1406,7 +1418,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect command ({connectCommand})", e);
|
||||
#else
|
||||
DebugConsole.Log($"Failed to parse a Steam friend's connect command ({connectCommand})\n" + e.StackTrace);
|
||||
DebugConsole.Log($"Failed to parse a Steam friend's connect command ({connectCommand})\n" + e.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
info.ConnectName = null;
|
||||
info.ConnectEndpoint = null;
|
||||
@@ -2109,7 +2121,7 @@ namespace Barotrauma
|
||||
{
|
||||
ClientNameBox.Flash();
|
||||
ClientNameBox.Select();
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1156,7 +1156,7 @@ namespace Barotrauma
|
||||
|
||||
if (itemContentPackage == null)
|
||||
{
|
||||
string errorMsg = "Failed to edit workshop item (content package null)\n" + Environment.StackTrace;
|
||||
string errorMsg = "Failed to edit workshop item (content package null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
@@ -33,6 +33,18 @@ namespace Barotrauma
|
||||
Default,
|
||||
Wiring
|
||||
}
|
||||
|
||||
public enum WarningType
|
||||
{
|
||||
NoWaypoints,
|
||||
NoHulls,
|
||||
DisconnectedVents,
|
||||
NoHumanSpawnpoints,
|
||||
NoCargoSpawnpoints,
|
||||
NoBallastTag,
|
||||
NonLinkedGaps,
|
||||
TooManyLights
|
||||
}
|
||||
|
||||
public static Vector2 MouseDragStart = Vector2.Zero;
|
||||
|
||||
@@ -85,11 +97,19 @@ namespace Barotrauma
|
||||
private GUIFrame previouslyUsedPanel;
|
||||
private GUIListBox previouslyUsedList;
|
||||
|
||||
private GUIFrame undoBufferPanel;
|
||||
private GUIListBox undoBufferList;
|
||||
|
||||
private GUIDropDown linkedSubBox;
|
||||
|
||||
private static GUIComponent autoSaveLabel;
|
||||
private static int maxAutoSaves = GameSettings.MaximumAutoSaves;
|
||||
|
||||
public static bool BulkItemBufferInUse;
|
||||
public static List<AddOrDeleteCommand> BulkItemBuffer = new List<AddOrDeleteCommand>();
|
||||
|
||||
public static List<WarningType> SuppressedWarnings = new List<WarningType>();
|
||||
|
||||
//a Character used for picking up and manipulating items
|
||||
private Character dummyCharacter;
|
||||
|
||||
@@ -109,12 +129,17 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private Vector2 oldItemPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Global undo/redo state for the sub editor and a selector index for it
|
||||
/// <see cref="Command"/>
|
||||
/// </summary>
|
||||
public static readonly List<Command> Commands = new List<Command>();
|
||||
private static int commandIndex;
|
||||
|
||||
private GUIFrame wiringToolPanel;
|
||||
|
||||
private DateTime editorSelectedTime;
|
||||
|
||||
private const string containerDeleteTag = "containerdelete";
|
||||
|
||||
private GUIImage previewImage;
|
||||
private GUILayoutGroup previewImageButtonHolder;
|
||||
|
||||
@@ -273,6 +298,7 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
previouslyUsedPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
showEntitiesPanel.Visible = !showEntitiesPanel.Visible;
|
||||
showEntitiesPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
@@ -285,12 +311,26 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
showEntitiesPanel.Visible = false;
|
||||
undoBufferPanel.Visible = false;
|
||||
previouslyUsedPanel.Visible = !previouslyUsedPanel.Visible;
|
||||
previouslyUsedPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var undoBufferButton = new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "UndoHistoryButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("Editor.UndoHistoryButton"),
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
showEntitiesPanel.Visible = false;
|
||||
previouslyUsedPanel.Visible = false;
|
||||
undoBufferPanel.Visible = !undoBufferPanel.Visible;
|
||||
undoBufferPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
|
||||
|
||||
subNameLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft),
|
||||
@@ -407,6 +447,45 @@ namespace Barotrauma
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
undoBufferPanel = new GUIFrame(new RectTransform(new Vector2(0.15f, 0.2f), GUI.Canvas) { MinSize = new Point(200, 200) })
|
||||
{
|
||||
Visible = false
|
||||
};
|
||||
undoBufferList = new GUIListBox(new RectTransform(new Vector2(0.925f, 0.9f), undoBufferPanel.RectTransform, Anchor.Center))
|
||||
{
|
||||
ScrollBarVisible = true,
|
||||
OnSelected = (_, userData) =>
|
||||
{
|
||||
int index;
|
||||
if (userData is Command command)
|
||||
{
|
||||
index = Commands.IndexOf(command);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
|
||||
int diff = index- commandIndex;
|
||||
int amount = Math.Abs(diff);
|
||||
|
||||
if (diff >= 0)
|
||||
{
|
||||
Redo(amount + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Undo(amount - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
UpdateUndoHistoryPanel();
|
||||
|
||||
//-----------------------------------------------
|
||||
|
||||
showEntitiesPanel = new GUIFrame(new RectTransform(new Vector2(0.08f, 0.5f), GUI.Canvas)
|
||||
{
|
||||
MinSize = new Point(170, 0)
|
||||
@@ -885,6 +964,7 @@ namespace Barotrauma
|
||||
{
|
||||
base.Select();
|
||||
|
||||
GUI.PreventPauseMenuToggle = false;
|
||||
if (!Directory.Exists(autoSavePath))
|
||||
{
|
||||
System.IO.DirectoryInfo e = Directory.CreateDirectory(autoSavePath);
|
||||
@@ -1043,6 +1123,7 @@ namespace Barotrauma
|
||||
|
||||
MapEntity.DeselectAll();
|
||||
MapEntity.SelectionGroups.Clear();
|
||||
ClearUndoBuffer();
|
||||
|
||||
SetMode(Mode.Default);
|
||||
|
||||
@@ -1062,147 +1143,15 @@ namespace Barotrauma
|
||||
GameMain.World.ProcessChanges();
|
||||
}
|
||||
|
||||
if (GUIMessageBox.MessageBoxes.Any(mbox => (mbox as GUIMessageBox)?.Tag == containerDeleteTag))
|
||||
{
|
||||
for (int i = 0; i < GUIMessageBox.MessageBoxes.Count; i++)
|
||||
{
|
||||
GUIMessageBox box = GUIMessageBox.MessageBoxes[i] as GUIMessageBox;
|
||||
if (box != null && box.Tag != containerDeleteTag) continue;
|
||||
box?.Close();
|
||||
i--; // Take into account the message boxes removing themselves from the list when closed
|
||||
}
|
||||
}
|
||||
ClearFilter();
|
||||
}
|
||||
|
||||
public void HandleContainerContentsDeletion(Item itemToDelete, Inventory itemInventory)
|
||||
{
|
||||
string itemNames = string.Empty;
|
||||
|
||||
foreach (Item item in itemInventory.Items)
|
||||
{
|
||||
if (item == null) continue;
|
||||
itemNames += item.Name + "\n";
|
||||
}
|
||||
|
||||
if (itemNames.Length > 0)
|
||||
{
|
||||
// Multiple prompts open
|
||||
if (GUIMessageBox.MessageBoxes.Any(mbox => (mbox as GUIMessageBox)?.Tag == containerDeleteTag))
|
||||
{
|
||||
var msgBox = new GUIMessageBox(itemToDelete.Name, TextManager.Get("DeletingContainerWithItems") + itemNames, new[] { TextManager.Get("Yes"), TextManager.Get("No"), TextManager.Get("YesToAll"), TextManager.Get("NoToAll") }, tag: containerDeleteTag);
|
||||
|
||||
// Yes
|
||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
itemInventory.DeleteAllItems();
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// No
|
||||
msgBox.Buttons[1].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
foreach (Item item in itemInventory.Items)
|
||||
{
|
||||
item?.Drop(null);
|
||||
}
|
||||
}
|
||||
else // If current screen is not subeditor, delete anyway to avoid lingering objects
|
||||
{
|
||||
itemInventory.DeleteAllItems();
|
||||
}
|
||||
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// Yes to All
|
||||
msgBox.Buttons[2].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
for (int i = 0; i < GUIMessageBox.MessageBoxes.Count; i++)
|
||||
{
|
||||
GUIMessageBox box = GUIMessageBox.MessageBoxes[i] as GUIMessageBox;
|
||||
if (box?.Tag != msgBox.Tag || box == msgBox) continue;
|
||||
GUIButton button = box?.Buttons[0];
|
||||
button?.OnClicked(button, button.UserData);
|
||||
i--; // Take into account the message boxes removing themselves from the list when closed
|
||||
}
|
||||
|
||||
itemInventory.DeleteAllItems();
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// No to all
|
||||
msgBox.Buttons[3].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
for (int i = 0; i < GUIMessageBox.MessageBoxes.Count; i++)
|
||||
{
|
||||
GUIMessageBox box = GUIMessageBox.MessageBoxes[i] as GUIMessageBox;
|
||||
if (box?.Tag != msgBox.Tag || box == msgBox) continue;
|
||||
GUIButton button = box?.Buttons[1];
|
||||
button?.OnClicked(button, button.UserData);
|
||||
i--; // Take into account the message boxes removing themselves from the list when closed
|
||||
}
|
||||
|
||||
if (Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
foreach (Item item in itemInventory.Items)
|
||||
{
|
||||
item?.Drop(null);
|
||||
}
|
||||
}
|
||||
else // If current screen is not subeditor, delete anyway to avoid lingering objects
|
||||
{
|
||||
itemInventory.DeleteAllItems();
|
||||
}
|
||||
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else // Single prompt
|
||||
{
|
||||
var msgBox = new GUIMessageBox(itemToDelete.Name, TextManager.Get("DeletingContainerWithItems") + itemNames, new[] { TextManager.Get("Yes"), TextManager.Get("No") }, tag: containerDeleteTag);
|
||||
|
||||
// Yes
|
||||
msgBox.Buttons[0].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
itemInventory.DeleteAllItems();
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
// No
|
||||
msgBox.Buttons[1].OnClicked = (btn, userdata) =>
|
||||
{
|
||||
if (Selected == GameMain.SubEditorScreen)
|
||||
{
|
||||
foreach (Item item in itemInventory.Items)
|
||||
{
|
||||
item?.Drop(null);
|
||||
}
|
||||
}
|
||||
else // If current screen is not subeditor, delete anyway to avoid lingering objects
|
||||
{
|
||||
itemInventory.DeleteAllItems();
|
||||
}
|
||||
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateDummyCharacter()
|
||||
{
|
||||
if (dummyCharacter != null) RemoveDummyCharacter();
|
||||
|
||||
dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", hasAi: false);
|
||||
dummyCharacter.Info.Name = "Galldren";
|
||||
|
||||
//make space for the entity menu
|
||||
for (int i = 0; i < dummyCharacter.Inventory.SlotPositions.Length; i++)
|
||||
@@ -2460,7 +2409,6 @@ namespace Barotrauma
|
||||
int min = Math.Min(6, AutoSaveInfo.Root.Elements().Count());
|
||||
var loadAutoSave = new GUIDropDown(new RectTransform(Vector2.One, deleteButtonHolder.RectTransform, Anchor.BottomCenter), TextManager.Get("LoadAutoSave"), elementCount: min)
|
||||
{
|
||||
Enabled = File.Exists(Path.Combine(SubmarineInfo.SavePath, ".AutoSaves", "AutoSave.sub")),
|
||||
ToolTip = TextManager.Get("LoadAutoSaveTooltip"),
|
||||
UserData = "loadautosave",
|
||||
OnSelected = (button, o) =>
|
||||
@@ -2609,7 +2557,7 @@ namespace Barotrauma
|
||||
var selectedSub = new Submarine(selectedSubInfo);
|
||||
Submarine.MainSub = selectedSub;
|
||||
Submarine.MainSub.UpdateTransform(interpolate: false);
|
||||
|
||||
ClearUndoBuffer();
|
||||
CreateDummyCharacter();
|
||||
|
||||
string name = Submarine.MainSub.Info.Name;
|
||||
@@ -2790,6 +2738,7 @@ namespace Barotrauma
|
||||
|
||||
MapEntity.DeselectAll();
|
||||
MapEntity.FilteredSelectedList.Clear();
|
||||
ClearUndoBuffer();
|
||||
|
||||
CreateDummyCharacter();
|
||||
if (newMode == Mode.Wiring)
|
||||
@@ -2922,7 +2871,7 @@ namespace Barotrauma
|
||||
CreateBackgroundColorPicker();
|
||||
break;
|
||||
case "selectsame":
|
||||
IEnumerable<MapEntity> matching = MapEntity.mapEntityList.Where(e => targets.Any(t => t.prefab.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e));
|
||||
IEnumerable<MapEntity> matching = MapEntity.mapEntityList.Where(e => e.prefab != null && targets.Any(t => t.prefab.Identifier == e.prefab.Identifier) && !MapEntity.SelectedList.Contains(e));
|
||||
MapEntity.SelectedList.AddRange(matching);
|
||||
break;
|
||||
case "copy":
|
||||
@@ -2935,7 +2884,8 @@ namespace Barotrauma
|
||||
MapEntity.Paste(cam.ScreenToWorld(contextMenu.Rect.Location.ToVector2()));
|
||||
break;
|
||||
case "delete":
|
||||
targets.ForEach(me => { me.Remove(); });
|
||||
StoreCommand(new AddOrDeleteCommand(targets, true));
|
||||
targets.ForEach(me => { if (!me.Removed) { me.Remove(); }});
|
||||
break;
|
||||
case "open" when target != null:
|
||||
OpenItem(target);
|
||||
@@ -3234,7 +3184,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
});
|
||||
GUI.PlayUISound(spawnedItem ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
|
||||
List<MapEntity> placedEntities = itemInstance.Where(it => !it.Removed).Cast<MapEntity>().ToList();
|
||||
if (placedEntities.Any())
|
||||
{
|
||||
StoreCommand(new AddOrDeleteCommand(placedEntities, false));
|
||||
}
|
||||
SoundPlayer.PlayUISound(spawnedItem ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
break;
|
||||
}
|
||||
case ItemPrefab itemPrefab when PlayerInput.IsShiftDown():
|
||||
@@ -3243,12 +3199,17 @@ namespace Barotrauma
|
||||
if (!inv.TryPutItem(item, dummyCharacter))
|
||||
{
|
||||
// We failed, remove the item so it doesn't stay at x:0,y:0
|
||||
GUI.PlayUISound(GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
|
||||
item.Remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
}
|
||||
|
||||
if (!item.Removed)
|
||||
{
|
||||
StoreCommand(new AddOrDeleteCommand(new List<MapEntity> { item }, false));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3257,7 +3218,7 @@ namespace Barotrauma
|
||||
{
|
||||
// Place the item into our hands
|
||||
DraggedItemPrefab = (MapEntityPrefab) obj;
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3265,7 +3226,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.PlayUISound(GUISoundType.PickItem);
|
||||
SoundPlayer.PlayUISound(GUISoundType.PickItem);
|
||||
MapEntityPrefab.SelectPrefab(obj);
|
||||
}
|
||||
|
||||
@@ -3611,6 +3572,7 @@ namespace Barotrauma
|
||||
EntityMenu.AddToGUIUpdateList();
|
||||
showEntitiesPanel.AddToGUIUpdateList();
|
||||
previouslyUsedPanel.AddToGUIUpdateList();
|
||||
undoBufferPanel.AddToGUIUpdateList();
|
||||
entityCountPanel.AddToGUIUpdateList();
|
||||
TopPanel.AddToGUIUpdateList();
|
||||
|
||||
@@ -3655,10 +3617,7 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private bool IsMouseOnEditorGUI()
|
||||
{
|
||||
if (GUI.MouseOn == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (GUI.MouseOn == null) { return false; }
|
||||
|
||||
return (EntityMenu?.MouseRect.Contains(PlayerInput.MousePosition) ?? false)
|
||||
|| (entityCountPanel?.MouseRect.Contains(PlayerInput.MousePosition) ?? false)
|
||||
@@ -3666,6 +3625,91 @@ namespace Barotrauma
|
||||
|| (TopPanel?.MouseRect.Contains(PlayerInput.MousePosition) ?? false);
|
||||
}
|
||||
|
||||
private static void Redo(int amount)
|
||||
{
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
if (commandIndex < Commands.Count)
|
||||
{
|
||||
Command command = Commands[commandIndex++];
|
||||
command.Execute();
|
||||
}
|
||||
}
|
||||
GameMain.SubEditorScreen.UpdateUndoHistoryPanel();
|
||||
}
|
||||
|
||||
private static void Undo(int amount)
|
||||
{
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
if (commandIndex > 0)
|
||||
{
|
||||
Command command = Commands[--commandIndex];
|
||||
command.UnExecute();
|
||||
}
|
||||
}
|
||||
GameMain.SubEditorScreen.UpdateUndoHistoryPanel();
|
||||
}
|
||||
|
||||
private static void ClearUndoBuffer()
|
||||
{
|
||||
SerializableEntityEditor.PropertyChangesActive = false;
|
||||
SerializableEntityEditor.CommandBuffer = null;
|
||||
Commands.ForEach(cmd => cmd.Cleanup());
|
||||
Commands.Clear();
|
||||
commandIndex = 0;
|
||||
GameMain.SubEditorScreen.UpdateUndoHistoryPanel();
|
||||
}
|
||||
|
||||
public static void StoreCommand(Command command)
|
||||
{
|
||||
if (commandIndex != Commands.Count)
|
||||
{
|
||||
Commands.RemoveRange(commandIndex, Commands.Count - commandIndex);
|
||||
}
|
||||
Commands.Add(command);
|
||||
commandIndex++;
|
||||
|
||||
// Start removing old commands
|
||||
if (Commands.Count > Math.Clamp(GameSettings.SubEditorMaxUndoBuffer, 1, 10240))
|
||||
{
|
||||
Commands.First()?.Cleanup();
|
||||
Commands.RemoveRange(0, 1);
|
||||
commandIndex = Commands.Count;
|
||||
}
|
||||
|
||||
GameMain.SubEditorScreen.UpdateUndoHistoryPanel();
|
||||
}
|
||||
|
||||
public void UpdateUndoHistoryPanel()
|
||||
{
|
||||
if (undoBufferPanel == null) { return; }
|
||||
|
||||
undoBufferList.Content.Children.ForEachMod(component =>
|
||||
{
|
||||
undoBufferList.Content.RemoveChild(component);
|
||||
});
|
||||
|
||||
for (int i = 0; i < Commands.Count; i++)
|
||||
{
|
||||
Command command = Commands[i];
|
||||
string description = command.GetDescription();
|
||||
CreateTextBlock(description, description, i + 1, command).RectTransform.SetAsFirstChild();
|
||||
}
|
||||
|
||||
CreateTextBlock(TextManager.Get("undo.beginning"), TextManager.Get("undo.beginningtooltip"), 0, null);
|
||||
|
||||
GUITextBlock CreateTextBlock(string name, string description, int index, Command command)
|
||||
{
|
||||
return new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), undoBufferList.Content.RectTransform) { MinSize = new Point(0, 15) },
|
||||
ToolBox.LimitString(name, GUI.SmallFont, undoBufferList.Content.Rect.Width), font: GUI.SmallFont, textColor: index == commandIndex ? GUI.Style.Green : (Color?) null)
|
||||
{
|
||||
UserData = command,
|
||||
ToolTip = description
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the game to run logic such as updating the world,
|
||||
/// checking for collisions, gathering input, and playing audio.
|
||||
@@ -3745,7 +3789,32 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (undoBufferPanel.Visible)
|
||||
{
|
||||
undoBufferList.Deselect();
|
||||
}
|
||||
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null
|
||||
|| MapEntity.EditingHUD != null
|
||||
&& GUI.KeyboardDispatcher.Subscriber is GUIComponent sub
|
||||
&& MapEntity.EditingHUD.Children.Contains(sub))
|
||||
{
|
||||
if (PlayerInput.IsCtrlDown() && !WiringMode)
|
||||
{
|
||||
if (PlayerInput.KeyHit(Keys.Z))
|
||||
{
|
||||
// Ctrl+Shift+Z redos while Ctrl+Z undos
|
||||
if (PlayerInput.IsShiftDown()) { Redo(1); } else { Undo(1); }
|
||||
}
|
||||
|
||||
// ctrl+Y redo
|
||||
if (PlayerInput.KeyHit(Keys.Y))
|
||||
{
|
||||
Redo(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
@@ -4019,9 +4088,15 @@ namespace Barotrauma
|
||||
newItem.Remove();
|
||||
}
|
||||
|
||||
if (!newItem.Removed)
|
||||
{
|
||||
BulkItemBufferInUse = true;
|
||||
BulkItemBuffer.Add(new AddOrDeleteCommand(new List<MapEntity> { newItem }, false));
|
||||
}
|
||||
|
||||
if (!dragginMouse)
|
||||
{
|
||||
GUI.PlayUISound(spawnedItem ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
SoundPlayer.PlayUISound(spawnedItem ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4083,14 +4158,41 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<MapEntity> placedEntities = itemInstance.Where(it => !it.Removed).Cast<MapEntity>().ToList();
|
||||
if (placedEntities.Any())
|
||||
{
|
||||
BulkItemBufferInUse = true;
|
||||
BulkItemBuffer.Add(new AddOrDeleteCommand(placedEntities, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
GUI.PlayUISound(spawnedItems ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
|
||||
SoundPlayer.PlayUISound(spawnedItems ? GUISoundType.PickItem : GUISoundType.PickItemFail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BulkItemBufferInUse && PlayerInput.PrimaryMouseButtonReleased() && BulkItemBuffer.Any())
|
||||
{
|
||||
AddOrDeleteCommand master = BulkItemBuffer[0];
|
||||
for (int i = 1; i < BulkItemBuffer.Count; i++)
|
||||
{
|
||||
AddOrDeleteCommand command = BulkItemBuffer[i];
|
||||
command.MergeInto(master);
|
||||
}
|
||||
|
||||
StoreCommand(master);
|
||||
BulkItemBuffer.Clear();
|
||||
BulkItemBufferInUse = false;
|
||||
}
|
||||
|
||||
if (SerializableEntityEditor.PropertyChangesActive && (SerializableEntityEditor.NextCommandPush < DateTime.Now || MapEntity.EditingHUD == null))
|
||||
{
|
||||
SerializableEntityEditor.CommitCommandBuffer();
|
||||
}
|
||||
|
||||
// Update our mouse dragging state so we can easily slide thru slots while holding the mouse button down to place lots of items
|
||||
if (PlayerInput.PrimaryMouseButtonHeld())
|
||||
{
|
||||
@@ -4273,9 +4375,18 @@ namespace Barotrauma
|
||||
Submarine.DrawFront(spriteBatch, editing: true, e => ShowThalamus || !(e.prefab?.Category.HasFlag(MapEntityCategory.Thalamus) ?? false));
|
||||
if (!WiringMode && !IsMouseOnEditorGUI())
|
||||
{
|
||||
MapEntityPrefab.Selected?.DrawPlacing(spriteBatch, cam);
|
||||
MapEntityPrefab.Selected?.DrawPlacing(spriteBatch, cam);
|
||||
MapEntity.DrawSelecting(spriteBatch, cam);
|
||||
}
|
||||
if (dummyCharacter != null && WiringMode)
|
||||
{
|
||||
for (int i = 0; i < dummyCharacter.SelectedItems.Length; i++)
|
||||
{
|
||||
if (dummyCharacter.SelectedItems[i] == null) { continue; }
|
||||
if (i > 0 && dummyCharacter.SelectedItems[0] == dummyCharacter.SelectedItems[i]) { continue; }
|
||||
dummyCharacter.SelectedItems[i].Draw(spriteBatch, editing: false, back: true);
|
||||
}
|
||||
}
|
||||
spriteBatch.End();
|
||||
|
||||
if (GameMain.LightManager.LightingEnabled && lightingEnabled)
|
||||
|
||||
@@ -18,6 +18,11 @@ namespace Barotrauma
|
||||
public static List<string> MissingLocalizations = new List<string>();
|
||||
#endif
|
||||
|
||||
public static bool LockEditing;
|
||||
public static bool PropertyChangesActive;
|
||||
public static DateTime NextCommandPush;
|
||||
public static Tuple<SerializableProperty, PropertyCommand> CommandBuffer;
|
||||
|
||||
public int ContentHeight
|
||||
{
|
||||
get
|
||||
@@ -1091,10 +1096,67 @@ namespace Barotrauma
|
||||
|
||||
private bool SetPropertyValue(SerializableProperty property, object entity, object value)
|
||||
{
|
||||
MultiSetProperties(property, entity, value);
|
||||
if (LockEditing) { return false; }
|
||||
|
||||
object oldData = property.GetValue(entity);
|
||||
// some properties have null as the default string value
|
||||
if (oldData == null && value is string) { oldData = ""; }
|
||||
if (entity is ISerializableEntity sEntity && Screen.Selected is SubEditorScreen && !Equals(oldData, value))
|
||||
{
|
||||
List<ISerializableEntity> entities = new List<ISerializableEntity> { sEntity };
|
||||
Dictionary<ISerializableEntity, object> affected = MultiSetProperties(property, entity, value);
|
||||
|
||||
Dictionary<object, List<ISerializableEntity>> oldValues = new Dictionary<object, List<ISerializableEntity>> {{ oldData, new List<ISerializableEntity> { sEntity }}};
|
||||
|
||||
affected.ForEach(aEntity =>
|
||||
{
|
||||
var (item, oldVal) = aEntity;
|
||||
entities.Add(item);
|
||||
|
||||
if (!oldValues.ContainsKey(oldVal))
|
||||
{
|
||||
oldValues.Add(oldVal, new List<ISerializableEntity> { item });
|
||||
}
|
||||
else
|
||||
{
|
||||
oldValues[oldVal].Add(item);
|
||||
}
|
||||
});
|
||||
|
||||
PropertyCommand cmd = new PropertyCommand(entities, property.Name, value, oldValues);
|
||||
if (CommandBuffer != null)
|
||||
{
|
||||
if (CommandBuffer.Item1 == property && CommandBuffer.Item2.PropertyCount == cmd.PropertyCount)
|
||||
{
|
||||
if (!CommandBuffer.Item2.MergeInto(cmd))
|
||||
{
|
||||
CommitCommandBuffer();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CommitCommandBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
NextCommandPush = DateTime.Now.AddSeconds(1);
|
||||
CommandBuffer = Tuple.Create(property, cmd);
|
||||
PropertyChangesActive = true;
|
||||
}
|
||||
|
||||
return property.TrySetValue(entity, value);
|
||||
}
|
||||
|
||||
public static void CommitCommandBuffer()
|
||||
{
|
||||
if (CommandBuffer != null)
|
||||
{
|
||||
SubEditorScreen.StoreCommand(CommandBuffer.Item2);
|
||||
}
|
||||
CommandBuffer = null;
|
||||
PropertyChangesActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets common shared properties to all selected map entities in sub editor.
|
||||
/// Only works client side while in the sub editor and when parentObject is ItemComponent, Item or Structure.
|
||||
@@ -1103,10 +1165,12 @@ namespace Barotrauma
|
||||
/// <param name="parentObject"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <remarks>The function has the same parameters as <see cref="SetValue"/></remarks>
|
||||
private void MultiSetProperties(SerializableProperty property, object parentObject, object value)
|
||||
private Dictionary<ISerializableEntity, object> MultiSetProperties(SerializableProperty property, object parentObject, object value)
|
||||
{
|
||||
if (!(Screen.Selected is SubEditorScreen) || MapEntity.SelectedList.Count <= 1) { return; }
|
||||
if (!(parentObject is ItemComponent || parentObject is Item || parentObject is Structure || parentObject is Hull)) { return; }
|
||||
Dictionary<ISerializableEntity, object> affected = new Dictionary<ISerializableEntity, object>();
|
||||
|
||||
if (!(Screen.Selected is SubEditorScreen) || MapEntity.SelectedList.Count <= 1) { return affected; }
|
||||
if (!(parentObject is ItemComponent || parentObject is Item || parentObject is Structure || parentObject is Hull)) { return affected; }
|
||||
|
||||
foreach (var entity in MapEntity.SelectedList.Where(entity => entity != parentObject))
|
||||
{
|
||||
@@ -1115,35 +1179,36 @@ namespace Barotrauma
|
||||
case Hull _:
|
||||
case Structure _:
|
||||
case Item _:
|
||||
{
|
||||
if (entity.GetType() == parentObject.GetType())
|
||||
{
|
||||
{
|
||||
affected.Add((ISerializableEntity) entity, property.GetValue(entity));
|
||||
property.PropertyInfo.SetValue(entity, value);
|
||||
}
|
||||
else if (entity is ISerializableEntity sEntity && sEntity.SerializableProperties != null)
|
||||
{
|
||||
var props = sEntity.SerializableProperties;
|
||||
|
||||
|
||||
if (props.TryGetValue(property.NameToLowerInvariant, out SerializableProperty foundProp))
|
||||
{
|
||||
affected.Add(sEntity, foundProp.GetValue(sEntity));
|
||||
foundProp.PropertyInfo.SetValue(entity, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ItemComponent _ when entity is Item item:
|
||||
{
|
||||
foreach (var component in item.Components)
|
||||
{
|
||||
if (component.GetType() == parentObject.GetType() && component != parentObject)
|
||||
{
|
||||
{
|
||||
affected.Add(component, property.GetValue(component));
|
||||
property.PropertyInfo.SetValue(component, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return affected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (value < 0.25f || value > 4.0f)
|
||||
{
|
||||
DebugConsole.ThrowError($"Frequency multiplier out of range: {value}" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError($"Frequency multiplier out of range: {value}" + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
frequencyMultiplier = Math.Clamp(value, 0.25f, 4.0f);
|
||||
|
||||
|
||||
@@ -730,6 +730,7 @@ namespace Barotrauma.Sounds
|
||||
else
|
||||
{
|
||||
playingChannels[i][j].Dispose();
|
||||
playingChannels[i][j] = null;
|
||||
}
|
||||
}
|
||||
else if (playingChannels[i][j].FadingOutAndDisposing)
|
||||
@@ -738,6 +739,7 @@ namespace Barotrauma.Sounds
|
||||
if (playingChannels[i][j].Gain <= 0.0f)
|
||||
{
|
||||
playingChannels[i][j].Dispose();
|
||||
playingChannels[i][j] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,18 @@ namespace Barotrauma
|
||||
|
||||
//ambience
|
||||
private static Sound waterAmbienceIn, waterAmbienceOut, waterAmbienceMoving;
|
||||
private static SoundChannel[] waterAmbienceChannels = new SoundChannel[3];
|
||||
private static readonly SoundChannel[] waterAmbienceChannels = new SoundChannel[3];
|
||||
|
||||
private static float ambientSoundTimer;
|
||||
private static Vector2 ambientSoundInterval = new Vector2(20.0f, 40.0f); //x = min, y = max
|
||||
|
||||
private static SoundChannel hullSoundChannel;
|
||||
private static Hull hullSoundSource;
|
||||
private static float hullSoundTimer;
|
||||
private static Vector2 hullSoundInterval = new Vector2(45.0f, 90.0f); //x = min, y = max
|
||||
|
||||
//misc
|
||||
private static float[] targetFlowLeft, targetFlowRight;
|
||||
public static List<Sound> FlowSounds = new List<Sound>();
|
||||
public static List<Sound> SplashSounds = new List<Sound>();
|
||||
private static SoundChannel[] flowSoundChannels;
|
||||
@@ -94,11 +100,18 @@ namespace Barotrauma
|
||||
private static float[] fireVolumeRight;
|
||||
|
||||
const float FireSoundRange = 1000.0f;
|
||||
const float FireSoundMediumLimit = 100.0f;
|
||||
const float FireSoundLargeLimit = 200.0f; //switch to large fire sound when the size of a firesource is above this
|
||||
const int fireSizes = 3;
|
||||
private static string[] fireSoundTags = new string[fireSizes] { "fire", "firemedium", "firelarge" };
|
||||
|
||||
// TODO: could use a dictionary to split up the list into smaller lists of same type?
|
||||
private static List<DamageSound> damageSounds;
|
||||
|
||||
private static Dictionary<GUISoundType, List<Sound>> guiSounds;
|
||||
|
||||
private static bool firstTimeInMainMenu = true;
|
||||
|
||||
private static Sound startUpSound;
|
||||
|
||||
public static bool Initialized;
|
||||
@@ -163,6 +176,7 @@ namespace Barotrauma
|
||||
List<KeyValuePair<string, Sound>> miscSoundList = new List<KeyValuePair<string, Sound>>();
|
||||
damageSounds ??= new List<DamageSound>();
|
||||
musicClips ??= new List<BackgroundMusic>();
|
||||
guiSounds ??= new Dictionary<GUISoundType, List<Sound>>();
|
||||
|
||||
bool firstWaterAmbienceLoaded = false;
|
||||
|
||||
@@ -250,6 +264,21 @@ namespace Barotrauma
|
||||
damageSoundType,
|
||||
soundElement.GetAttributeString("requiredtag", "")));
|
||||
|
||||
break;
|
||||
case "guisound":
|
||||
Sound guiSound = GameMain.SoundManager.LoadSound(soundElement, stream: false);
|
||||
if (guiSound == null) { continue; }
|
||||
if (Enum.TryParse(soundElement.GetAttributeString("guisoundtype", null), true, out GUISoundType soundType))
|
||||
{
|
||||
if (guiSounds.ContainsKey(soundType))
|
||||
{
|
||||
guiSounds[soundType].Add(guiSound);
|
||||
}
|
||||
else
|
||||
{
|
||||
guiSounds.Add(soundType, new List<Sound>() { guiSound });
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Sound sound = GameMain.SoundManager.LoadSound(soundElement, false);
|
||||
@@ -294,20 +323,32 @@ namespace Barotrauma
|
||||
});
|
||||
damageSounds.RemoveAll(s => s.sound.Disposed);
|
||||
|
||||
guiSounds.ForEach(kvp =>
|
||||
{
|
||||
kvp.Value?.ForEach(s =>
|
||||
{
|
||||
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
|
||||
});
|
||||
});
|
||||
guiSounds.ForEach(kvp => kvp.Value?.RemoveAll(s => s.Disposed));
|
||||
|
||||
miscSounds?.ForEach(g => g.ForEach(s =>
|
||||
{
|
||||
if (!soundElements.Any(e => SoundElementsEquivalent(s.XElement, e))) { s.Dispose(); }
|
||||
else { miscSoundList.Add(new KeyValuePair<string, Sound>(g.Key, s)); }
|
||||
}));
|
||||
|
||||
|
||||
flowSoundChannels?.ForEach(ch => ch?.Dispose());
|
||||
flowSoundChannels = new SoundChannel[FlowSounds.Count];
|
||||
flowVolumeLeft = new float[FlowSounds.Count];
|
||||
flowVolumeRight = new float[FlowSounds.Count];
|
||||
targetFlowLeft = new float[FlowSounds.Count];
|
||||
targetFlowRight = new float[FlowSounds.Count];
|
||||
|
||||
fireSoundChannels = new SoundChannel[2];
|
||||
fireVolumeLeft = new float[2];
|
||||
fireVolumeRight = new float[2];
|
||||
fireSoundChannels?.ForEach(ch => ch?.Dispose());
|
||||
fireSoundChannels = new SoundChannel[fireSizes];
|
||||
fireVolumeLeft = new float[fireSizes];
|
||||
fireVolumeRight = new float[fireSizes];
|
||||
|
||||
miscSounds = miscSoundList.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
|
||||
|
||||
@@ -319,7 +360,6 @@ namespace Barotrauma
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void Update(float deltaTime)
|
||||
{
|
||||
if (!Initialized) { return; }
|
||||
@@ -355,6 +395,12 @@ namespace Barotrauma
|
||||
}
|
||||
fireVolumeLeft[0] = 0.0f; fireVolumeLeft[1] = 0.0f;
|
||||
fireVolumeRight[0] = 0.0f; fireVolumeRight[1] = 0.0f;
|
||||
if (hullSoundChannel != null)
|
||||
{
|
||||
hullSoundChannel.FadeOutAndDispose();
|
||||
hullSoundChannel = null;
|
||||
hullSoundSource = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -372,12 +418,13 @@ namespace Barotrauma
|
||||
UpdateWaterAmbience(ambienceVolume, deltaTime);
|
||||
UpdateWaterFlowSounds(deltaTime);
|
||||
UpdateRandomAmbience(deltaTime);
|
||||
UpdateHullSounds(deltaTime);
|
||||
UpdateFireSounds(deltaTime);
|
||||
}
|
||||
|
||||
private static void UpdateWaterAmbience(float ambienceVolume, float deltaTime)
|
||||
{
|
||||
if (GameMain.SoundManager.Disabled) { return; }
|
||||
if (GameMain.SoundManager.Disabled || GameMain.GameScreen?.Cam == null) { return; }
|
||||
|
||||
//how fast the sub is moving, scaled to 0.0 -> 1.0
|
||||
float movementSoundVolume = 0.0f;
|
||||
@@ -385,6 +432,7 @@ namespace Barotrauma
|
||||
float insideSubFactor = 0.0f;
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
if (sub == null || sub.Removed) { continue; }
|
||||
float movementFactor = (sub.Velocity == Vector2.Zero) ? 0.0f : sub.Velocity.Length() / 10.0f;
|
||||
movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f);
|
||||
|
||||
@@ -429,6 +477,9 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
|
||||
// Consider the volume set in sounds.xml
|
||||
if (sound != null) { volume *= sound.BaseGain; }
|
||||
|
||||
if ((waterAmbienceChannels[i] == null || !waterAmbienceChannels[i].IsPlaying) && volume > 0.01f)
|
||||
{
|
||||
waterAmbienceChannels[i] = sound.Play(volume, "waterambience");
|
||||
@@ -448,9 +499,12 @@ namespace Barotrauma
|
||||
private static void UpdateWaterFlowSounds(float deltaTime)
|
||||
{
|
||||
if (FlowSounds.Count == 0) { return; }
|
||||
|
||||
float[] targetFlowLeft = new float[FlowSounds.Count];
|
||||
float[] targetFlowRight = new float[FlowSounds.Count];
|
||||
|
||||
for (int i = 0; i < targetFlowLeft.Length; i++)
|
||||
{
|
||||
targetFlowLeft[i] = 0.0f;
|
||||
targetFlowRight[i] = 0.0f;
|
||||
}
|
||||
|
||||
Vector2 listenerPos = new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y);
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
@@ -490,6 +544,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (Character.Controlled?.CharacterHealth?.GetAffliction("psychosis") is AfflictionPsychosis psychosis)
|
||||
{
|
||||
if (psychosis.CurrentFloodType == AfflictionPsychosis.FloodType.Minor)
|
||||
{
|
||||
targetFlowLeft[0] = Math.Max(targetFlowLeft[0], 1.0f);
|
||||
targetFlowRight[0] = Math.Max(targetFlowRight[0], 1.0f);
|
||||
}
|
||||
else if (psychosis.CurrentFloodType == AfflictionPsychosis.FloodType.Major)
|
||||
{
|
||||
targetFlowLeft[FlowSounds.Count - 1] = Math.Max(targetFlowLeft[FlowSounds.Count - 1], 1.0f);
|
||||
targetFlowRight[FlowSounds.Count - 1] = Math.Max(targetFlowRight[FlowSounds.Count - 1], 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < FlowSounds.Count; i++)
|
||||
{
|
||||
flowVolumeLeft[i] = (targetFlowLeft[i] < flowVolumeLeft[i]) ?
|
||||
@@ -534,33 +602,11 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (FireSource fs in hull.FireSources)
|
||||
{
|
||||
Vector2 diff = fs.WorldPosition + fs.Size / 2 - listenerPos;
|
||||
if (Math.Abs(diff.X) < FireSoundRange && Math.Abs(diff.Y) < FireSoundRange)
|
||||
{
|
||||
Vector2 diffLeft = (fs.WorldPosition + new Vector2(fs.Size.X, fs.Size.Y / 2)) - listenerPos;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffLeft.X = 0.0f; }
|
||||
if (diffLeft.X <= 0)
|
||||
{
|
||||
float distFallOffLeft = diffLeft.Length() / FireSoundRange;
|
||||
if (distFallOffLeft < 0.99f)
|
||||
{
|
||||
fireVolumeLeft[0] += (1.0f - distFallOffLeft);
|
||||
if (fs.Size.X > FireSoundLargeLimit) fireVolumeLeft[1] += (1.0f - distFallOffLeft) * ((fs.Size.X - FireSoundLargeLimit) / FireSoundLargeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 diffRight = (fs.WorldPosition + new Vector2(0.0f, fs.Size.Y / 2)) - listenerPos;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffRight.X = 0.0f; }
|
||||
if (diffRight.X >= 0)
|
||||
{
|
||||
float distFallOffRight = diffRight.Length() / FireSoundRange;
|
||||
if (distFallOffRight < 0.99f)
|
||||
{
|
||||
fireVolumeRight[0] += 1.0f - distFallOffRight;
|
||||
if (fs.Size.X > FireSoundLargeLimit) fireVolumeRight[1] += (1.0f - distFallOffRight) * ((fs.Size.X - FireSoundLargeLimit) / FireSoundLargeLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
AddFireVolume(fs);
|
||||
}
|
||||
foreach (FireSource fs in hull.FakeFireSources)
|
||||
{
|
||||
AddFireVolume(fs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,13 +625,58 @@ namespace Barotrauma
|
||||
Vector2 soundPos = new Vector2(GameMain.SoundManager.ListenerPosition.X + (fireVolumeRight[i] - fireVolumeLeft[i]) * 100, GameMain.SoundManager.ListenerPosition.Y);
|
||||
if (fireSoundChannels[i] == null || !fireSoundChannels[i].IsPlaying)
|
||||
{
|
||||
fireSoundChannels[i] = GetSound(i == 0 ? "fire" : "firelarge").Play(1.0f, FlowSoundRange, soundPos);
|
||||
fireSoundChannels[i] = GetSound(fireSoundTags[i]).Play(1.0f, FlowSoundRange, soundPos);
|
||||
fireSoundChannels[i].Looping = true;
|
||||
}
|
||||
fireSoundChannels[i].Gain = Math.Max(fireVolumeRight[i], fireVolumeLeft[i]);
|
||||
fireSoundChannels[i].Position = new Vector3(soundPos, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void AddFireVolume(FireSource fs)
|
||||
{
|
||||
Vector2 diff = fs.WorldPosition + fs.Size / 2 - listenerPos;
|
||||
if (Math.Abs(diff.X) < FireSoundRange && Math.Abs(diff.Y) < FireSoundRange)
|
||||
{
|
||||
Vector2 diffLeft = (fs.WorldPosition + new Vector2(fs.Size.X, fs.Size.Y / 2)) - listenerPos;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffLeft.X = 0.0f; }
|
||||
if (diffLeft.X <= 0)
|
||||
{
|
||||
float distFallOffLeft = diffLeft.Length() / FireSoundRange;
|
||||
if (distFallOffLeft < 0.99f)
|
||||
{
|
||||
fireVolumeLeft[0] += (1.0f - distFallOffLeft);
|
||||
if (fs.Size.X > FireSoundLargeLimit)
|
||||
{
|
||||
fireVolumeLeft[2] += (1.0f - distFallOffLeft) * ((fs.Size.X - FireSoundLargeLimit) / FireSoundLargeLimit);
|
||||
}
|
||||
else if (fs.Size.X > FireSoundMediumLimit)
|
||||
{
|
||||
fireVolumeLeft[1] += (1.0f - distFallOffLeft) * ((fs.Size.X - FireSoundMediumLimit) / FireSoundMediumLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 diffRight = (fs.WorldPosition + new Vector2(0.0f, fs.Size.Y / 2)) - listenerPos;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffRight.X = 0.0f; }
|
||||
if (diffRight.X >= 0)
|
||||
{
|
||||
float distFallOffRight = diffRight.Length() / FireSoundRange;
|
||||
if (distFallOffRight < 0.99f)
|
||||
{
|
||||
fireVolumeRight[0] += 1.0f - distFallOffRight;
|
||||
if (fs.Size.X > FireSoundLargeLimit)
|
||||
{
|
||||
fireVolumeRight[2] += (1.0f - distFallOffRight) * ((fs.Size.X - FireSoundLargeLimit) / FireSoundLargeLimit);
|
||||
}
|
||||
else if (fs.Size.X > FireSoundMediumLimit)
|
||||
{
|
||||
fireVolumeRight[1] += (1.0f - distFallOffRight) * ((fs.Size.X - FireSoundMediumLimit) / FireSoundMediumLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateRandomAmbience(float deltaTime)
|
||||
@@ -606,6 +697,40 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHullSounds(float deltaTime)
|
||||
{
|
||||
if (hullSoundChannel != null && hullSoundChannel.IsPlaying && hullSoundSource != null)
|
||||
{
|
||||
hullSoundChannel.Position = new Vector3(hullSoundSource.WorldPosition, 0.0f);
|
||||
hullSoundChannel.Gain = GetHullSoundVolume(hullSoundSource.Submarine);
|
||||
}
|
||||
|
||||
if (hullSoundTimer > 0.0f)
|
||||
{
|
||||
hullSoundTimer -= deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Level.IsLoadedOutpost && Character.Controlled?.CurrentHull?.Submarine is Submarine sub &&
|
||||
sub.Info != null && !sub.Info.IsOutpost)
|
||||
{
|
||||
hullSoundSource = Character.Controlled.CurrentHull;
|
||||
hullSoundChannel = PlaySound("hull", hullSoundSource.WorldPosition, volume: GetHullSoundVolume(sub), range: 1500.0f);
|
||||
hullSoundTimer = Rand.Range(hullSoundInterval.X, hullSoundInterval.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
hullSoundTimer = 5.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static float GetHullSoundVolume(Submarine sub)
|
||||
{
|
||||
var depth = Level.Loaded == null ? 0.0f : Math.Abs(sub.Position.Y - Level.Loaded.Size.Y) * Physics.DisplayToRealWorldRatio;
|
||||
return Math.Clamp((depth - 800.0f) / 1500.0f, 0.4f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public static Sound GetSound(string soundTag)
|
||||
{
|
||||
var matchingSounds = miscSounds[soundTag].ToList();
|
||||
@@ -637,8 +762,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (sound == null)
|
||||
{
|
||||
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -815,7 +940,9 @@ namespace Barotrauma
|
||||
return "editor";
|
||||
}
|
||||
|
||||
if (Screen.Selected != GameMain.GameScreen) { return "menu"; }
|
||||
if (Screen.Selected != GameMain.GameScreen) { return firstTimeInMainMenu ? "menu" : "default"; }
|
||||
|
||||
firstTimeInMainMenu = false;
|
||||
|
||||
|
||||
if (Character.Controlled != null)
|
||||
@@ -830,6 +957,18 @@ namespace Barotrauma
|
||||
{
|
||||
return "wreck";
|
||||
}
|
||||
|
||||
if (Level.IsLoadedOutpost && Character.Controlled.Submarine == Level.Loaded.StartOutpost)
|
||||
{
|
||||
// Only return music type for specific outpost types to not assume that
|
||||
// every outpost type has an associated music track (switch-case for future tracks)
|
||||
var locationType = Level.Loaded.StartLocation?.Type?.Identifier?.ToLowerInvariant();
|
||||
switch (locationType)
|
||||
{
|
||||
case "research":
|
||||
return locationType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Submarine targetSubmarine = Character.Controlled?.Submarine;
|
||||
@@ -845,12 +984,12 @@ namespace Barotrauma
|
||||
float totalArea = 0.0f;
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Submarine != targetSubmarine) continue;
|
||||
if (hull.Submarine != targetSubmarine) { continue; }
|
||||
floodedArea += hull.WaterVolume;
|
||||
totalArea += hull.Volume;
|
||||
}
|
||||
|
||||
if (totalArea > 0.0f && floodedArea / totalArea > 0.25f) return "flooded";
|
||||
if (totalArea > 0.0f && floodedArea / totalArea > 0.25f) { return "flooded"; }
|
||||
}
|
||||
|
||||
float enemyDistThreshold = 5000.0f;
|
||||
@@ -863,7 +1002,7 @@ namespace Barotrauma
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
if (character.IsDead || !character.Enabled) continue;
|
||||
if (!(character.AIController is EnemyAIController enemyAI) || (!enemyAI.AttackHumans && !enemyAI.AttackRooms)) continue;
|
||||
if (!(character.AIController is EnemyAIController enemyAI) || (!enemyAI.AttackHumans && !enemyAI.AttackRooms)) { continue; }
|
||||
|
||||
if (targetSubmarine != null)
|
||||
{
|
||||
@@ -952,6 +1091,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
tempList.GetRandom().sound?.Play(1.0f, range, position, muffle: ShouldMuffleSound(Character.Controlled, position, range, null));
|
||||
}
|
||||
}
|
||||
|
||||
public static void PlayUISound(GUISoundType soundType)
|
||||
{
|
||||
if (guiSounds == null || guiSounds.Count < 1) { return; }
|
||||
if (guiSounds.TryGetValue(soundType, out List<Sound> sounds))
|
||||
{
|
||||
if (sounds == null || sounds.Count < 1) { return; }
|
||||
sounds.GetRandom()?.Play(null, "ui");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace Barotrauma
|
||||
{
|
||||
Sprite = new Sprite(element, path, file, lazyLoad: lazyLoad);
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
// TODO: what's the purpose of this?
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
List<PropertyConditional> conditionalList = null;
|
||||
|
||||
@@ -67,8 +67,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (sound?.Sound == null)
|
||||
{
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific1 (sound \"{sound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific1 (sound \"{sound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
soundChannel = SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, hullGuess: hull);
|
||||
@@ -93,14 +93,22 @@ namespace Barotrauma
|
||||
var selectedSound = sounds[selectedSoundIndex];
|
||||
if (selectedSound?.Sound == null)
|
||||
{
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific2 (sound \"{selectedSound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace;
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific2 (sound \"{selectedSound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
if (selectedSound.Sound.Disposed)
|
||||
{
|
||||
Submarine.ReloadRoundSound(selectedSound);
|
||||
}
|
||||
soundChannel = SoundPlayer.PlaySound(selectedSound.Sound, worldPosition, selectedSound.Volume, selectedSound.Range, hullGuess: hull);
|
||||
if (soundChannel != null) { soundChannel.Looping = loopSound; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
soundChannel.Position = new Vector3(worldPosition, 0.0f);
|
||||
}
|
||||
|
||||
if (soundChannel != null && soundChannel.Looping)
|
||||
{
|
||||
|
||||
559
Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs
Normal file
559
Barotrauma/BarotraumaClient/ClientSource/SubEditorCommands.cs
Normal file
@@ -0,0 +1,559 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal readonly struct InventorySlotItem
|
||||
{
|
||||
public readonly int Slot;
|
||||
public readonly Item Item;
|
||||
|
||||
public InventorySlotItem(int slot, Item item)
|
||||
{
|
||||
Slot = slot;
|
||||
Item = item;
|
||||
}
|
||||
|
||||
public void Deconstruct(out int slot, out Item item)
|
||||
{
|
||||
slot = Slot;
|
||||
item = Item;
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract partial class Command
|
||||
{
|
||||
public abstract string GetDescription();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A command for setting and reverting a MapEntity rectangle
|
||||
/// <see cref="SubEditorScreen"/>
|
||||
/// <see cref="MapEntity"/>
|
||||
/// </summary>
|
||||
internal class TransformCommand : Command
|
||||
{
|
||||
private readonly List<MapEntity> Receivers;
|
||||
private readonly List<Rectangle> NewData;
|
||||
private readonly List<Rectangle> OldData;
|
||||
private readonly bool Resized;
|
||||
|
||||
/// <summary>
|
||||
/// A command for setting and reverting a MapEntity rectangle
|
||||
/// </summary>
|
||||
/// <param name="receivers">Entities whose rectangle has been altered</param>
|
||||
/// <param name="newData">The new rectangle that is or will be applied to the map entity</param>
|
||||
/// <param name="oldData">Old rectangle the map entity had before</param>
|
||||
/// <param name="resized">If the transform was resized or not</param>
|
||||
/// <remarks>
|
||||
/// All lists should be equal in length, for every receiver there should be a corresponding entry at the same position in newData and oldData.
|
||||
/// </remarks>
|
||||
public TransformCommand(List<MapEntity> receivers, List<Rectangle> newData, List<Rectangle> oldData, bool resized)
|
||||
{
|
||||
Receivers = receivers;
|
||||
NewData = newData;
|
||||
OldData = oldData;
|
||||
Resized = resized;
|
||||
}
|
||||
|
||||
public override void Execute() => SetRects(NewData);
|
||||
public override void UnExecute() => SetRects(OldData);
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
NewData.Clear();
|
||||
OldData.Clear();
|
||||
Receivers.Clear();
|
||||
}
|
||||
|
||||
private void SetRects(IReadOnlyList<Rectangle> rects)
|
||||
{
|
||||
if (Receivers.Count != rects.Count)
|
||||
{
|
||||
DebugConsole.ThrowError($"Receivers.Count did not match Rects.Count ({Receivers.Count} vs {rects.Count}).");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < rects.Count; i++)
|
||||
{
|
||||
MapEntity entity = Receivers[i].GetReplacementOrThis();
|
||||
Rectangle Rect = rects[i];
|
||||
Vector2 diff = Rect.Location.ToVector2() - entity.Rect.Location.ToVector2();
|
||||
entity.Move(diff);
|
||||
entity.Rect = Rect;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
if (Resized)
|
||||
{
|
||||
return TextManager.GetWithVariable("Undo.ResizedItem", "[item]", Receivers.FirstOrDefault()?.Name);
|
||||
}
|
||||
|
||||
return Receivers.Count > 1
|
||||
? TextManager.GetWithVariable("Undo.MovedItemsMultiple", "[count]", Receivers.Count.ToString())
|
||||
: TextManager.GetWithVariable("Undo.MovedItem", "[item]", Receivers.FirstOrDefault()?.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A command that removes and unremoves map entities
|
||||
/// <see cref="ItemPrefab"/>
|
||||
/// <see cref="StructurePrefab"/>
|
||||
/// <seealso cref="SubEditorScreen"/>
|
||||
/// </summary>
|
||||
internal class AddOrDeleteCommand : Command
|
||||
{
|
||||
private readonly Dictionary<InventorySlotItem, Inventory> PreviousInventories = new Dictionary<InventorySlotItem, Inventory>();
|
||||
private readonly List<MapEntity> Receivers;
|
||||
private readonly List<MapEntity> CloneList;
|
||||
private readonly bool WasDeleted;
|
||||
private readonly List<AddOrDeleteCommand> ContainedItemsCommand = new List<AddOrDeleteCommand>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a command where all entities share the same state.
|
||||
/// </summary>
|
||||
/// <param name="receivers">Entities that were deleted or added</param>
|
||||
/// <param name="wasDeleted">Whether or not all entities are or are going to be deleted</param>
|
||||
public AddOrDeleteCommand(List<MapEntity> receivers, bool wasDeleted)
|
||||
{
|
||||
WasDeleted = wasDeleted;
|
||||
Receivers = receivers;
|
||||
|
||||
try
|
||||
{
|
||||
foreach (MapEntity receiver in receivers)
|
||||
{
|
||||
if (receiver is Item it && it.ParentInventory != null)
|
||||
{
|
||||
PreviousInventories.Add(new InventorySlotItem(Array.IndexOf(it.ParentInventory.Items, it), it), it.ParentInventory);
|
||||
}
|
||||
}
|
||||
|
||||
List<MapEntity> clonedTargets = MapEntity.Clone(receivers);
|
||||
|
||||
List<MapEntity> itemsToDelete = new List<MapEntity>();
|
||||
foreach (MapEntity receiver in Receivers)
|
||||
{
|
||||
if (receiver is Item it)
|
||||
{
|
||||
foreach (ItemContainer component in it.GetComponents<ItemContainer>())
|
||||
{
|
||||
if (component.Inventory == null) { continue; }
|
||||
|
||||
itemsToDelete.AddRange(component.Inventory.Items.Where(item => item != null && !item.Removed));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsToDelete.Any())
|
||||
{
|
||||
ContainedItemsCommand.Add(new AddOrDeleteCommand(itemsToDelete, true));
|
||||
foreach (MapEntity item in itemsToDelete)
|
||||
{
|
||||
if (item != null && !item.Removed)
|
||||
{
|
||||
item.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntity clone in clonedTargets)
|
||||
{
|
||||
clone.ShallowRemove();
|
||||
if (clone is Item it)
|
||||
{
|
||||
foreach (ItemContainer container in it.GetComponents<ItemContainer>())
|
||||
{
|
||||
container.Inventory?.DeleteAllItems();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloneList = clonedTargets;
|
||||
}
|
||||
// This should never happen except if we decide to make a new type of MapEntity that isn't finished yet
|
||||
catch (Exception e)
|
||||
{
|
||||
Receivers = new List<MapEntity>();
|
||||
CloneList = new List<MapEntity>();
|
||||
DebugConsole.ThrowError("Could not store object", e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
DeleteUndelete(true);
|
||||
ContainedItemsCommand?.ForEach(cmd => cmd.Execute());
|
||||
}
|
||||
|
||||
public override void UnExecute()
|
||||
{
|
||||
DeleteUndelete(false);
|
||||
ContainedItemsCommand?.ForEach(cmd => cmd.UnExecute());
|
||||
}
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
foreach (MapEntity entity in CloneList)
|
||||
{
|
||||
if (!entity.Removed)
|
||||
{
|
||||
entity.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
CloneList?.Clear();
|
||||
Receivers.Clear();
|
||||
PreviousInventories?.Clear();
|
||||
ContainedItemsCommand?.ForEach(cmd => cmd.Cleanup());
|
||||
}
|
||||
|
||||
private void DeleteUndelete(bool redo)
|
||||
{
|
||||
bool wasDeleted = WasDeleted;
|
||||
|
||||
// We are redoing instead of undoing, flip the behavior
|
||||
if (redo) { wasDeleted = !wasDeleted; }
|
||||
|
||||
if (wasDeleted)
|
||||
{
|
||||
Debug.Assert(Receivers.All(entity => entity.GetReplacementOrThis().Removed), "Tried to redo a deletion but some items were not deleted");
|
||||
|
||||
List<MapEntity> clones = MapEntity.Clone(CloneList);
|
||||
for (int i = 0; i < Math.Min(Receivers.Count, clones.Count); i++)
|
||||
{
|
||||
MapEntity clone = clones[i];
|
||||
MapEntity receiver = Receivers[i];
|
||||
|
||||
if (receiver.GetReplacementOrThis() is Item item && clone is Item cloneItem)
|
||||
{
|
||||
foreach (ItemComponent ic in item.Components)
|
||||
{
|
||||
int index = item.GetComponentIndex(ic);
|
||||
ItemComponent component = cloneItem.Components.ElementAtOrDefault(index);
|
||||
switch (component)
|
||||
{
|
||||
case null:
|
||||
continue;
|
||||
case ItemContainer newContainer when newContainer.Inventory != null && ic is ItemContainer itemContainer && itemContainer.Inventory != null:
|
||||
itemContainer.Inventory.GetReplacementOrThiS().ReplacedBy = newContainer.Inventory;
|
||||
goto default;
|
||||
default:
|
||||
ic.GetReplacementOrThis().ReplacedBy = component;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
receiver.GetReplacementOrThis().ReplacedBy = clone;
|
||||
|
||||
if (clone is Item it)
|
||||
{
|
||||
foreach (var (slotRef, inventory) in PreviousInventories)
|
||||
{
|
||||
if (slotRef.Item == receiver)
|
||||
{
|
||||
inventory.GetReplacementOrThiS().TryPutItem(it, slotRef.Slot, false, false, null, createNetworkEvent: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (MapEntity clone in clones)
|
||||
{
|
||||
clone.Submarine = Submarine.MainSub;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (MapEntity t in Receivers)
|
||||
{
|
||||
MapEntity receiver = t.GetReplacementOrThis();
|
||||
if (!receiver.Removed)
|
||||
{
|
||||
receiver.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeInto(AddOrDeleteCommand master)
|
||||
{
|
||||
master.Receivers.AddRange(Receivers);
|
||||
master.CloneList.AddRange(CloneList);
|
||||
master.ContainedItemsCommand.AddRange(ContainedItemsCommand);
|
||||
foreach (var (slot, item) in PreviousInventories)
|
||||
{
|
||||
master.PreviousInventories.Add(slot, item);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
if (WasDeleted)
|
||||
{
|
||||
return Receivers.Count > 1
|
||||
? TextManager.GetWithVariable("Undo.RemovedItemsMultiple", "[count]", Receivers.Count.ToString())
|
||||
: TextManager.GetWithVariable("Undo.RemovedItem", "[item]", Receivers.FirstOrDefault()?.Name);
|
||||
}
|
||||
|
||||
return Receivers.Count > 1
|
||||
? TextManager.GetWithVariable("Undo.AddedItemsMultiple", "[count]", Receivers.Count.ToString())
|
||||
: TextManager.GetWithVariable("Undo.AddedItem", "[item]", Receivers.FirstOrDefault()?.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A command that places or drops items out of inventories
|
||||
/// </summary>
|
||||
/// <see cref="Inventory"/>
|
||||
/// <see cref="MapEntity"/>
|
||||
internal class InventoryPlaceCommand : Command
|
||||
{
|
||||
private readonly Inventory Inventory;
|
||||
private readonly List<InventorySlotItem> Receivers;
|
||||
private readonly bool wasDropped;
|
||||
|
||||
public InventoryPlaceCommand(Inventory inventory, List<Item> items, bool dropped)
|
||||
{
|
||||
Inventory = inventory;
|
||||
Receivers = items.Select(item => new InventorySlotItem(Array.IndexOf(inventory.Items, item), item)).ToList();
|
||||
wasDropped = dropped;
|
||||
}
|
||||
|
||||
public override void Execute() => ContainUncontain(false);
|
||||
public override void UnExecute() => ContainUncontain(true);
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
Receivers.Clear();
|
||||
}
|
||||
|
||||
private void ContainUncontain(bool drop)
|
||||
{
|
||||
// flip the behavior if the item was dropped instead of inserted
|
||||
if (wasDropped) { drop = !drop; }
|
||||
|
||||
foreach (var (slot, receiver) in Receivers)
|
||||
{
|
||||
Item item = (Item) receiver.GetReplacementOrThis();
|
||||
|
||||
if (drop)
|
||||
{
|
||||
item.Drop(null, createNetworkEvent: false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Inventory.GetReplacementOrThiS().TryPutItem(item, slot, false, false, null, createNetworkEvent: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
if (wasDropped)
|
||||
{
|
||||
return TextManager.GetWithVariable("Undo.DroppedItem", "[item]", Receivers.FirstOrDefault().Item.Name);
|
||||
}
|
||||
|
||||
string container = "[ERROR]";
|
||||
|
||||
if (Inventory.Owner is Item item)
|
||||
{
|
||||
container = item.Name;
|
||||
}
|
||||
|
||||
return Receivers.Count > 1
|
||||
? TextManager.GetWithVariables("Undo.ContainedItemsMultiple", new[] { "[count]", "[container]" }, new[] { Receivers.Count.ToString(), container })
|
||||
: TextManager.GetWithVariables("Undo.ContainedItem", new[] { "[item]", "[container]" }, new[] { Receivers.FirstOrDefault().Item.Name, container });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A command that sets item properties
|
||||
/// </summary>
|
||||
internal class PropertyCommand : Command
|
||||
{
|
||||
private Dictionary<object, List<ISerializableEntity>> OldProperties;
|
||||
private readonly List<ISerializableEntity> Receivers;
|
||||
private readonly string PropertyName;
|
||||
private readonly object NewProperties;
|
||||
private string sanitizedProperty;
|
||||
|
||||
public readonly int PropertyCount;
|
||||
|
||||
/// <summary>
|
||||
/// A command that sets item properties
|
||||
/// </summary>
|
||||
/// <param name="receivers">Affected entities</param>
|
||||
/// <param name="propertyName">Real property name, not all lowercase</param>
|
||||
/// <param name="newData"></param>
|
||||
/// <param name="oldData"></param>
|
||||
public PropertyCommand(List<ISerializableEntity> receivers, string propertyName, object newData, Dictionary<object, List<ISerializableEntity>> oldData)
|
||||
{
|
||||
Receivers = receivers;
|
||||
PropertyName = propertyName;
|
||||
OldProperties = oldData;
|
||||
NewProperties = newData;
|
||||
PropertyCount = receivers.Count;
|
||||
SanitizeProperty();
|
||||
}
|
||||
|
||||
public PropertyCommand(ISerializableEntity receiver, string propertyName, object newData, object oldData)
|
||||
{
|
||||
Receivers = new List<ISerializableEntity> { receiver };
|
||||
PropertyName = propertyName;
|
||||
OldProperties = new Dictionary<object, List<ISerializableEntity>> { { oldData, Receivers } };
|
||||
NewProperties = newData;
|
||||
PropertyCount = 1;
|
||||
SanitizeProperty();
|
||||
}
|
||||
|
||||
public bool MergeInto(PropertyCommand master)
|
||||
{
|
||||
if (!master.Receivers.SequenceEqual(Receivers)) { return false; }
|
||||
master.OldProperties = OldProperties;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SanitizeProperty()
|
||||
{
|
||||
sanitizedProperty = NewProperties switch
|
||||
{
|
||||
float f => f.FormatSingleDecimal(),
|
||||
Point point => XMLExtensions.PointToString(point),
|
||||
Vector2 vector2 => vector2.FormatZeroDecimal(),
|
||||
Vector3 vector3 => vector3.FormatSingleDecimal(),
|
||||
Vector4 vector4 => vector4.FormatSingleDecimal(),
|
||||
Color color => XMLExtensions.ColorToString(color),
|
||||
Rectangle rectangle => XMLExtensions.RectToString(rectangle),
|
||||
_ => NewProperties.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
public override void Execute() => SetProperties(false);
|
||||
public override void UnExecute() => SetProperties(true);
|
||||
|
||||
public override void Cleanup()
|
||||
{
|
||||
Receivers.Clear();
|
||||
OldProperties.Clear();
|
||||
}
|
||||
|
||||
private void SetProperties(bool undo)
|
||||
{
|
||||
foreach (ISerializableEntity t in Receivers)
|
||||
{
|
||||
ISerializableEntity receiver;
|
||||
switch (t)
|
||||
{
|
||||
case MapEntity me when me.GetReplacementOrThis() is ISerializableEntity sEntity:
|
||||
receiver = sEntity;
|
||||
break;
|
||||
case ItemComponent ic when ic.GetReplacementOrThis() is ISerializableEntity sItemComponent:
|
||||
receiver = sItemComponent;
|
||||
break;
|
||||
default:
|
||||
receiver = t;
|
||||
break;
|
||||
}
|
||||
|
||||
object data = NewProperties;
|
||||
|
||||
if (undo)
|
||||
{
|
||||
foreach (var (key, value) in OldProperties)
|
||||
{
|
||||
if (value.Contains(t)) { data = key; }
|
||||
}
|
||||
}
|
||||
|
||||
if (receiver.SerializableProperties != null)
|
||||
{
|
||||
Dictionary<string, SerializableProperty> props = receiver.SerializableProperties;
|
||||
|
||||
if (props.TryGetValue(PropertyName.ToLowerInvariant(), out SerializableProperty prop))
|
||||
{
|
||||
prop.TrySetValue(receiver, data);
|
||||
// Update the editing hud
|
||||
if (MapEntity.EditingHUD == null || (MapEntity.EditingHUD.UserData != receiver && (receiver is ItemComponent ic && MapEntity.EditingHUD.UserData != ic.Item))) { continue; }
|
||||
|
||||
GUIListBox list = MapEntity.EditingHUD.GetChild<GUIListBox>();
|
||||
if (list == null) { continue; }
|
||||
|
||||
IEnumerable<SerializableEntityEditor> editors = list.Content.FindChildren(comp => comp is SerializableEntityEditor).Cast<SerializableEntityEditor>();
|
||||
SerializableEntityEditor.LockEditing = true;
|
||||
foreach (SerializableEntityEditor editor in editors)
|
||||
{
|
||||
if (editor.UserData == receiver && editor.Fields.TryGetValue(PropertyName, out GUIComponent[] _))
|
||||
{
|
||||
editor.UpdateValue(prop, data);
|
||||
}
|
||||
}
|
||||
|
||||
SerializableEntityEditor.LockEditing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
return Receivers.Count > 1
|
||||
? TextManager.GetWithVariables("Undo.ChangedPropertyMultiple", new[] { "[property]", "[count]", "[value]" }, new[] { PropertyName, Receivers.Count.ToString(), sanitizedProperty })
|
||||
: TextManager.GetWithVariables("Undo.ChangedProperty", new[] { "[property]", "[item]", "[value]" }, new[] { PropertyName, Receivers.FirstOrDefault()?.Name, sanitizedProperty });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A command that moves items around in inventories
|
||||
/// </summary>
|
||||
/// <see cref="oldInventory"/>
|
||||
/// <see cref="MapEntity"/>
|
||||
internal class InventoryMoveCommand : Command
|
||||
{
|
||||
private readonly Inventory oldInventory;
|
||||
private readonly Inventory newInventory;
|
||||
private readonly int oldSlot;
|
||||
private readonly int newSlot;
|
||||
private readonly Item targetItem;
|
||||
|
||||
public InventoryMoveCommand(Inventory oldInventory, Inventory newInventory, Item item, int oldSlot, int newSlot)
|
||||
{
|
||||
this.newInventory = newInventory;
|
||||
this.oldInventory = oldInventory;
|
||||
this.oldSlot = oldSlot;
|
||||
this.newSlot = newSlot;
|
||||
targetItem = item;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
{
|
||||
if (targetItem.GetReplacementOrThis() is Item item)
|
||||
{
|
||||
newInventory?.GetReplacementOrThiS().TryPutItem(item, newSlot, true, false, null, createNetworkEvent: false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UnExecute()
|
||||
{
|
||||
if (targetItem.GetReplacementOrThis() is Item item)
|
||||
{
|
||||
oldInventory?.GetReplacementOrThiS().TryPutItem(item, oldSlot, true, false, null, createNetworkEvent: false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Cleanup() { }
|
||||
|
||||
public override string GetDescription()
|
||||
{
|
||||
return TextManager.GetWithVariable("Undo.MovedItem", "[item]", targetItem.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,773 +0,0 @@
|
||||
//
|
||||
// System.Web.HttpUtility
|
||||
//
|
||||
// Authors:
|
||||
// Patrik Torstensson (Patrik.Torstensson@labs2.com)
|
||||
// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
|
||||
// Tim Coleman (tim@timcoleman.com)
|
||||
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
|
||||
//
|
||||
// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using Barotrauma.IO;
|
||||
using System.Security.Permissions;
|
||||
using System.Text;
|
||||
|
||||
namespace RestSharp.Contrib
|
||||
{
|
||||
|
||||
//#if !MONOTOUCH
|
||||
// // CAS - no InheritanceDemand here as the class is sealed
|
||||
// [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||||
//#endif
|
||||
public sealed class HttpUtility
|
||||
{
|
||||
sealed class HttpQSCollection : NameValueCollection
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
int count = Count;
|
||||
if (count == 0)
|
||||
return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
string[] keys = AllKeys;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]);
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
sb.Length--;
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
|
||||
public HttpUtility()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion // Constructors
|
||||
|
||||
#region Methods
|
||||
|
||||
/*
|
||||
public static void HtmlAttributeEncode(string s, TextWriter output)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
#if NET_4_0
|
||||
throw new ArgumentNullException ("output");
|
||||
#else
|
||||
throw new NullReferenceException(".NET emulation");
|
||||
#endif
|
||||
}
|
||||
#if NET_4_0
|
||||
HttpEncoder.Current.HtmlAttributeEncode (s, output);
|
||||
#else
|
||||
output.Write(HttpEncoder.HtmlAttributeEncode(s));
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
public static string HtmlAttributeEncode(string s)
|
||||
{
|
||||
#if NET_4_0
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
using (var sw = new StringWriter ()) {
|
||||
HttpEncoder.Current.HtmlAttributeEncode (s, sw);
|
||||
return sw.ToString ();
|
||||
}
|
||||
#else
|
||||
return HttpEncoder.HtmlAttributeEncode(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string UrlDecode(string str)
|
||||
{
|
||||
return UrlDecode(str, Encoding.UTF8);
|
||||
}
|
||||
|
||||
static char[] GetChars(System.IO.MemoryStream b, Encoding e)
|
||||
{
|
||||
return e.GetChars(b.GetBuffer(), 0, (int)b.Length);
|
||||
}
|
||||
|
||||
static void WriteCharBytes(IList buf, char ch, Encoding e)
|
||||
{
|
||||
if (ch > 255)
|
||||
{
|
||||
foreach (byte b in e.GetBytes(new char[] { ch }))
|
||||
buf.Add(b);
|
||||
}
|
||||
else
|
||||
buf.Add((byte)ch);
|
||||
}
|
||||
|
||||
public static string UrlDecode(string s, Encoding e)
|
||||
{
|
||||
if (null == s)
|
||||
return null;
|
||||
|
||||
if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
|
||||
return s;
|
||||
|
||||
if (e == null)
|
||||
e = Encoding.UTF8;
|
||||
|
||||
long len = s.Length;
|
||||
var bytes = new List<byte>();
|
||||
int xchar;
|
||||
char ch;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
ch = s[i];
|
||||
if (ch == '%' && i + 2 < len && s[i + 1] != '%')
|
||||
{
|
||||
if (s[i + 1] == 'u' && i + 5 < len)
|
||||
{
|
||||
// unicode hex sequence
|
||||
xchar = GetChar(s, i + 2, 4);
|
||||
if (xchar != -1)
|
||||
{
|
||||
WriteCharBytes(bytes, (char)xchar, e);
|
||||
i += 5;
|
||||
}
|
||||
else
|
||||
WriteCharBytes(bytes, '%', e);
|
||||
}
|
||||
else if ((xchar = GetChar(s, i + 1, 2)) != -1)
|
||||
{
|
||||
WriteCharBytes(bytes, (char)xchar, e);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteCharBytes(bytes, '%', e);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '+')
|
||||
WriteCharBytes(bytes, ' ', e);
|
||||
else
|
||||
WriteCharBytes(bytes, ch, e);
|
||||
}
|
||||
|
||||
byte[] buf = bytes.ToArray();
|
||||
bytes = null;
|
||||
return e.GetString(buf);
|
||||
|
||||
}
|
||||
|
||||
public static string UrlDecode(byte[] bytes, Encoding e)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
return UrlDecode(bytes, 0, bytes.Length, e);
|
||||
}
|
||||
|
||||
static int GetInt(byte b)
|
||||
{
|
||||
char c = (char)b;
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int GetChar(byte[] bytes, int offset, int length)
|
||||
{
|
||||
int value = 0;
|
||||
int end = length + offset;
|
||||
for (int i = offset; i < end; i++)
|
||||
{
|
||||
int current = GetInt(bytes[i]);
|
||||
if (current == -1)
|
||||
return -1;
|
||||
value = (value << 4) + current;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int GetChar(string str, int offset, int length)
|
||||
{
|
||||
int val = 0;
|
||||
int end = length + offset;
|
||||
for (int i = offset; i < end; i++)
|
||||
{
|
||||
char c = str[i];
|
||||
if (c > 127)
|
||||
return -1;
|
||||
|
||||
int current = GetInt((byte)c);
|
||||
if (current == -1)
|
||||
return -1;
|
||||
val = (val << 4) + current;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
if (count == 0)
|
||||
return String.Empty;
|
||||
|
||||
if (bytes == null)
|
||||
throw new ArgumentNullException("bytes");
|
||||
|
||||
if (offset < 0 || offset > bytes.Length)
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
|
||||
if (count < 0 || offset + count > bytes.Length)
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
System.IO.MemoryStream acc = new System.IO.MemoryStream();
|
||||
|
||||
int end = count + offset;
|
||||
int xchar;
|
||||
for (int i = offset; i < end; i++)
|
||||
{
|
||||
if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
|
||||
{
|
||||
if (bytes[i + 1] == (byte)'u' && i + 5 < end)
|
||||
{
|
||||
if (acc.Length > 0)
|
||||
{
|
||||
output.Append(GetChars(acc, e));
|
||||
acc.SetLength(0);
|
||||
}
|
||||
xchar = GetChar(bytes, i + 2, 4);
|
||||
if (xchar != -1)
|
||||
{
|
||||
output.Append((char)xchar);
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
|
||||
{
|
||||
acc.WriteByte((byte)xchar);
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (acc.Length > 0)
|
||||
{
|
||||
output.Append(GetChars(acc, e));
|
||||
acc.SetLength(0);
|
||||
}
|
||||
|
||||
if (bytes[i] == '+')
|
||||
{
|
||||
output.Append(' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Append((char)bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (acc.Length > 0)
|
||||
{
|
||||
output.Append(GetChars(acc, e));
|
||||
}
|
||||
|
||||
acc = null;
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
public static byte[] UrlDecodeToBytes(byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
return UrlDecodeToBytes(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public static byte[] UrlDecodeToBytes(string str)
|
||||
{
|
||||
return UrlDecodeToBytes(str, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static byte[] UrlDecodeToBytes(string str, Encoding e)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
if (e == null)
|
||||
throw new ArgumentNullException("e");
|
||||
|
||||
return UrlDecodeToBytes(e.GetBytes(str));
|
||||
}
|
||||
|
||||
public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
if (count == 0)
|
||||
return new byte[0];
|
||||
|
||||
int len = bytes.Length;
|
||||
if (offset < 0 || offset >= len)
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
|
||||
if (count < 0 || offset > len - count)
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
|
||||
System.IO.MemoryStream result = new System.IO.MemoryStream();
|
||||
int end = offset + count;
|
||||
for (int i = offset; i < end; i++)
|
||||
{
|
||||
char c = (char)bytes[i];
|
||||
if (c == '+')
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
else if (c == '%' && i < end - 2)
|
||||
{
|
||||
int xchar = GetChar(bytes, i + 1, 2);
|
||||
if (xchar != -1)
|
||||
{
|
||||
c = (char)xchar;
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
result.WriteByte((byte)c);
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
public static string UrlEncode(string str)
|
||||
{
|
||||
return UrlEncode(str, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static string UrlEncode(string s, Encoding Enc)
|
||||
{
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
if (s == String.Empty)
|
||||
return String.Empty;
|
||||
|
||||
bool needEncode = false;
|
||||
int len = s.Length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
char c = s[i];
|
||||
if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
|
||||
{
|
||||
if (HttpEncoder.NotEncoded(c))
|
||||
continue;
|
||||
|
||||
needEncode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needEncode)
|
||||
return s;
|
||||
|
||||
// avoided GetByteCount call
|
||||
byte[] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
|
||||
int realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
|
||||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen));
|
||||
}
|
||||
|
||||
public static string UrlEncode(byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
if (bytes.Length == 0)
|
||||
return String.Empty;
|
||||
|
||||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length));
|
||||
}
|
||||
|
||||
public static string UrlEncode(byte[] bytes, int offset, int count)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
if (bytes.Length == 0)
|
||||
return String.Empty;
|
||||
|
||||
return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
|
||||
}
|
||||
|
||||
public static byte[] UrlEncodeToBytes(string str)
|
||||
{
|
||||
return UrlEncodeToBytes(str, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static byte[] UrlEncodeToBytes(string str, Encoding e)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
if (str.Length == 0)
|
||||
return new byte[0];
|
||||
|
||||
byte[] bytes = e.GetBytes(str);
|
||||
return UrlEncodeToBytes(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public static byte[] UrlEncodeToBytes(byte[] bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
|
||||
if (bytes.Length == 0)
|
||||
return new byte[0];
|
||||
|
||||
return UrlEncodeToBytes(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
|
||||
{
|
||||
if (bytes == null)
|
||||
return null;
|
||||
#if NET_4_0
|
||||
return HttpEncoder.Current.UrlEncode (bytes, offset, count);
|
||||
#else
|
||||
return HttpEncoder.UrlEncodeToBytes(bytes, offset, count);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string UrlEncodeUnicode(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str));
|
||||
}
|
||||
|
||||
public static byte[] UrlEncodeUnicodeToBytes(string str)
|
||||
{
|
||||
if (str == null)
|
||||
return null;
|
||||
|
||||
if (str.Length == 0)
|
||||
return new byte[0];
|
||||
|
||||
System.IO.MemoryStream result = new System.IO.MemoryStream(str.Length);
|
||||
foreach (char c in str)
|
||||
{
|
||||
HttpEncoder.UrlEncodeChar(c, result, true);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an HTML-encoded string and returns the decoded string.
|
||||
/// </summary>
|
||||
/// <param name="s">The HTML string to decode. </param>
|
||||
/// <returns>The decoded text.</returns>
|
||||
public static string HtmlDecode(string s)
|
||||
{
|
||||
#if NET_4_0
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
using (var sw = new StringWriter ()) {
|
||||
HttpEncoder.Current.HtmlDecode (s, sw);
|
||||
return sw.ToString ();
|
||||
}
|
||||
#else
|
||||
return HttpEncoder.HtmlDecode(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
|
||||
/// </summary>
|
||||
/// <param name="s">The HTML string to decode</param>
|
||||
/// <param name="output">The TextWriter output stream containing the decoded string. </param>
|
||||
/*
|
||||
public static void HtmlDecode(string s, TextWriter output)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
#if NET_4_0
|
||||
throw new ArgumentNullException ("output");
|
||||
#else
|
||||
throw new NullReferenceException(".NET emulation");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(s))
|
||||
{
|
||||
#if NET_4_0
|
||||
HttpEncoder.Current.HtmlDecode (s, output);
|
||||
#else
|
||||
output.Write(HttpEncoder.HtmlDecode(s));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static string HtmlEncode(string s)
|
||||
{
|
||||
#if NET_4_0
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
using (var sw = new StringWriter ()) {
|
||||
HttpEncoder.Current.HtmlEncode (s, sw);
|
||||
return sw.ToString ();
|
||||
}
|
||||
#else
|
||||
return HttpEncoder.HtmlEncode(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
|
||||
/// </summary>
|
||||
/// <param name="s">The string to encode. </param>
|
||||
/// <param name="output">The TextWriter output stream containing the encoded string. </param>
|
||||
/*
|
||||
public static void HtmlEncode(string s, TextWriter output)
|
||||
{
|
||||
if (output == null)
|
||||
{
|
||||
#if NET_4_0
|
||||
throw new ArgumentNullException ("output");
|
||||
#else
|
||||
throw new NullReferenceException(".NET emulation");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(s))
|
||||
{
|
||||
#if NET_4_0
|
||||
HttpEncoder.Current.HtmlEncode (s, output);
|
||||
#else
|
||||
output.Write(HttpEncoder.HtmlEncode(s));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#if NET_4_0
|
||||
public static string HtmlEncode (object value)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
IHtmlString htmlString = value as IHtmlString;
|
||||
if (htmlString != null)
|
||||
return htmlString.ToHtmlString ();
|
||||
|
||||
return HtmlEncode (value.ToString ());
|
||||
}
|
||||
|
||||
public static string JavaScriptStringEncode (string value)
|
||||
{
|
||||
return JavaScriptStringEncode (value, false);
|
||||
}
|
||||
|
||||
public static string JavaScriptStringEncode (string value, bool addDoubleQuotes)
|
||||
{
|
||||
if (String.IsNullOrEmpty (value))
|
||||
return addDoubleQuotes ? "\"\"" : String.Empty;
|
||||
|
||||
int len = value.Length;
|
||||
bool needEncode = false;
|
||||
char c;
|
||||
for (int i = 0; i < len; i++) {
|
||||
c = value [i];
|
||||
|
||||
if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) {
|
||||
needEncode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!needEncode)
|
||||
return addDoubleQuotes ? "\"" + value + "\"" : value;
|
||||
|
||||
var sb = new StringBuilder ();
|
||||
if (addDoubleQuotes)
|
||||
sb.Append ('"');
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
c = value [i];
|
||||
if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
|
||||
sb.AppendFormat ("\\u{0:x4}", (int)c);
|
||||
else switch ((int)c) {
|
||||
case 8:
|
||||
sb.Append ("\\b");
|
||||
break;
|
||||
|
||||
case 9:
|
||||
sb.Append ("\\t");
|
||||
break;
|
||||
|
||||
case 10:
|
||||
sb.Append ("\\n");
|
||||
break;
|
||||
|
||||
case 12:
|
||||
sb.Append ("\\f");
|
||||
break;
|
||||
|
||||
case 13:
|
||||
sb.Append ("\\r");
|
||||
break;
|
||||
|
||||
case 34:
|
||||
sb.Append ("\\\"");
|
||||
break;
|
||||
|
||||
case 92:
|
||||
sb.Append ("\\\\");
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.Append (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (addDoubleQuotes)
|
||||
sb.Append ('"');
|
||||
|
||||
return sb.ToString ();
|
||||
}
|
||||
#endif
|
||||
public static string UrlPathEncode(string s)
|
||||
{
|
||||
#if NET_4_0
|
||||
return HttpEncoder.Current.UrlPathEncode (s);
|
||||
#else
|
||||
return HttpEncoder.UrlPathEncode(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static NameValueCollection ParseQueryString(string query)
|
||||
{
|
||||
return ParseQueryString(query, Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static NameValueCollection ParseQueryString(string query, Encoding encoding)
|
||||
{
|
||||
if (query == null)
|
||||
throw new ArgumentNullException("query");
|
||||
if (encoding == null)
|
||||
throw new ArgumentNullException("encoding");
|
||||
if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
|
||||
return new NameValueCollection();
|
||||
if (query[0] == '?')
|
||||
query = query.Substring(1);
|
||||
|
||||
NameValueCollection result = new HttpQSCollection();
|
||||
ParseQueryString(query, encoding, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
|
||||
{
|
||||
if (query.Length == 0)
|
||||
return;
|
||||
|
||||
string decoded = HtmlDecode(query);
|
||||
int decodedLength = decoded.Length;
|
||||
int namePos = 0;
|
||||
bool first = true;
|
||||
while (namePos <= decodedLength)
|
||||
{
|
||||
int valuePos = -1, valueEnd = -1;
|
||||
for (int q = namePos; q < decodedLength; q++)
|
||||
{
|
||||
if (valuePos == -1 && decoded[q] == '=')
|
||||
{
|
||||
valuePos = q + 1;
|
||||
}
|
||||
else if (decoded[q] == '&')
|
||||
{
|
||||
valueEnd = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
if (decoded[namePos] == '?')
|
||||
namePos++;
|
||||
}
|
||||
|
||||
string name, value;
|
||||
if (valuePos == -1)
|
||||
{
|
||||
name = null;
|
||||
valuePos = namePos;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
|
||||
}
|
||||
if (valueEnd < 0)
|
||||
{
|
||||
namePos = -1;
|
||||
valueEnd = decoded.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
namePos = valueEnd + 1;
|
||||
}
|
||||
value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
|
||||
|
||||
result.Add(name, value);
|
||||
if (namePos == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion // Methods
|
||||
}
|
||||
}
|
||||
@@ -138,14 +138,15 @@ namespace Barotrauma
|
||||
|
||||
public static Color GradientLerp(float t, params Color[] gradient)
|
||||
{
|
||||
if (!MathUtils.IsValid(t)) { return Color.Purple; }
|
||||
System.Diagnostics.Debug.Assert(gradient.Length > 0, "Empty color array passed to the GradientLerp method");
|
||||
if (gradient.Length == 0)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace);
|
||||
DebugConsole.ThrowError("Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("ToolBox.GradientLerp:EmptyColorArray", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace);
|
||||
"Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return Color.Black;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.5.1</Version>
|
||||
<Version>0.10.6.2</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
@@ -178,6 +178,10 @@
|
||||
<_Parameter1>GitBranch</_Parameter1>
|
||||
<_Parameter2>$(BuildBranch)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
<AssemblyAttributes Include="AssemblyMetadata">
|
||||
<_Parameter1>ProjectDir</_Parameter1>
|
||||
<_Parameter2>$(ProjectDir)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
</ItemGroup>
|
||||
<!-- writes the attribute to the customAssemblyInfo file -->
|
||||
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.5.1</Version>
|
||||
<Version>0.10.6.2</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
@@ -180,6 +180,10 @@
|
||||
<_Parameter1>GitBranch</_Parameter1>
|
||||
<_Parameter2>$(BuildBranch)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
<AssemblyAttributes Include="AssemblyMetadata">
|
||||
<_Parameter1>ProjectDir</_Parameter1>
|
||||
<_Parameter2>$(ProjectDir)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
</ItemGroup>
|
||||
<!-- writes the attribute to the customAssemblyInfo file -->
|
||||
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.10.5.1</Version>
|
||||
<Version>0.10.6.2</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
@@ -209,6 +209,10 @@
|
||||
<_Parameter1>GitBranch</_Parameter1>
|
||||
<_Parameter2>$(BuildBranch)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
<AssemblyAttributes Include="AssemblyMetadata">
|
||||
<_Parameter1>ProjectDir</_Parameter1>
|
||||
<_Parameter2>$(ProjectDir)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
</ItemGroup>
|
||||
<!-- writes the attribute to the customAssemblyInfo file -->
|
||||
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.10.5.1</Version>
|
||||
<Version>0.10.6.2</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
@@ -127,6 +127,10 @@
|
||||
<_Parameter1>GitBranch</_Parameter1>
|
||||
<_Parameter2>$(BuildBranch)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
<AssemblyAttributes Include="AssemblyMetadata">
|
||||
<_Parameter1>ProjectDir</_Parameter1>
|
||||
<_Parameter2>$(ProjectDir)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
</ItemGroup>
|
||||
<!-- writes the attribute to the customAssemblyInfo file -->
|
||||
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.10.5.1</Version>
|
||||
<Version>0.10.6.2</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
@@ -140,6 +140,10 @@
|
||||
<_Parameter1>GitBranch</_Parameter1>
|
||||
<_Parameter2>$(BuildBranch)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
<AssemblyAttributes Include="AssemblyMetadata">
|
||||
<_Parameter1>ProjectDir</_Parameter1>
|
||||
<_Parameter2>$(ProjectDir)</_Parameter2>
|
||||
</AssemblyAttributes>
|
||||
</ItemGroup>
|
||||
<!-- writes the attribute to the customAssemblyInfo file -->
|
||||
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
|
||||
|
||||
@@ -420,6 +420,7 @@ namespace Barotrauma
|
||||
if (writeStatus)
|
||||
{
|
||||
WriteStatus(tempBuffer);
|
||||
(AIController as EnemyAIController)?.PetBehavior?.ServerWrite(tempBuffer);
|
||||
HealthUpdatePending = false;
|
||||
}
|
||||
|
||||
@@ -478,7 +479,7 @@ namespace Barotrauma
|
||||
msg.Write(Info == null);
|
||||
msg.Write(entityId);
|
||||
msg.Write(SpeciesName);
|
||||
msg.Write(seed);
|
||||
msg.Write(Seed);
|
||||
|
||||
if (Removed)
|
||||
{
|
||||
@@ -528,19 +529,19 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(info.CurrentOrder.Prefab));
|
||||
msg.Write(info.CurrentOrder.TargetEntity == null ? (UInt16)0 :
|
||||
info.CurrentOrder.TargetEntity.ID);
|
||||
if (info.CurrentOrder.OrderGiver != null)
|
||||
msg.Write(info.CurrentOrder.TargetEntity == null ? (UInt16)0 : info.CurrentOrder.TargetEntity.ID);
|
||||
var hasOrderGiver = info.CurrentOrder.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver) { msg.Write(info.CurrentOrder.OrderGiver.ID); }
|
||||
msg.Write((byte)(string.IsNullOrWhiteSpace(info.CurrentOrderOption) ? 0 : Array.IndexOf(info.CurrentOrder.Prefab.Options, info.CurrentOrderOption)));
|
||||
var hasTargetPosition = info.CurrentOrder.TargetPosition != null;
|
||||
msg.Write(hasTargetPosition);
|
||||
if (hasTargetPosition)
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write(info.CurrentOrder.OrderGiver.ID);
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Position.X);
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Position.Y);
|
||||
msg.Write(info.CurrentOrder.TargetPosition.Hull == null ? (UInt16)0 : info.CurrentOrder.TargetPosition.Hull.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(false);
|
||||
}
|
||||
msg.Write((byte)(string.IsNullOrWhiteSpace(info.CurrentOrderOption) ? 0 :
|
||||
Array.IndexOf(info.CurrentOrder.Prefab.Options, info.CurrentOrderOption)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -247,7 +247,7 @@ namespace Barotrauma
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Failed to write input to command line (window width: " + Console.WindowWidth + ", window height: " + Console.WindowHeight + ")\n"
|
||||
+ e.Message + "\n" + e.StackTrace;
|
||||
+ e.Message + "\n" + e.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.RewriteInputToCommandLine", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
}
|
||||
@@ -1119,6 +1119,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxPlayers > NetConfig.MaxPlayers)
|
||||
{
|
||||
NewMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.");
|
||||
maxPlayers = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
GameMain.Server.ServerSettings.MaxPlayers = maxPlayers;
|
||||
NewMessage("Set the maximum player count to " + maxPlayers + ".");
|
||||
}
|
||||
@@ -1132,6 +1138,12 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxPlayers > NetConfig.MaxPlayers)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"Setting the maximum amount of players to {maxPlayers} failed due to exceeding the limit of {NetConfig.MaxPlayers} players per server. Using the maximum of {NetConfig.MaxPlayers} instead.", client);
|
||||
maxPlayers = NetConfig.MaxPlayers;
|
||||
}
|
||||
|
||||
GameMain.Server.ServerSettings.MaxPlayers = maxPlayers;
|
||||
NewMessage(client.Name + " set the maximum player count to " + maxPlayers + ".");
|
||||
GameMain.Server.SendConsoleMessage("Set the maximum player count to " + maxPlayers + ".", client);
|
||||
@@ -1352,7 +1364,7 @@ namespace Barotrauma
|
||||
ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events[Convert.ToUInt16(args[0])];
|
||||
if (ev != null)
|
||||
{
|
||||
NewMessage(ev.StackTrace, Color.Lime);
|
||||
NewMessage(ev.StackTrace.CleanupStackTrace(), Color.Lime);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Barotrauma
|
||||
msg.Write((byte)monsters.Count);
|
||||
foreach (Character monster in monsters)
|
||||
{
|
||||
monster.WriteSpawnData(msg, monster.ID, restrictMessageSize: false);
|
||||
monster.WriteSpawnData(msg, monster.OriginalID, restrictMessageSize: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,14 @@ namespace Barotrauma
|
||||
c.InGame && (IsOwner(c) || c.HasPermission(ClientPermissions.ManageCampaign)));
|
||||
}
|
||||
|
||||
public void LoadPets()
|
||||
{
|
||||
if (petsElement != null)
|
||||
{
|
||||
PetBehavior.LoadPets(petsElement);
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults)
|
||||
{
|
||||
lastUpdateID++;
|
||||
@@ -229,6 +237,9 @@ namespace Barotrauma
|
||||
c.Inventory.DeleteAllItems();
|
||||
}
|
||||
|
||||
petsElement = new XElement("pets");
|
||||
PetBehavior.SavePets(petsElement);
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
if (leavingSub != Submarine.MainSub && !leavingSub.DockedTo.Contains(Submarine.MainSub))
|
||||
@@ -694,6 +705,10 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
pendingHireInfos.Add(match);
|
||||
if (pendingHireInfos.Count + CrewManager.CharacterInfos.Count() >= CrewManager.MaxCrewSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
location.HireManager.PendingHires = pendingHireInfos;
|
||||
}
|
||||
@@ -764,6 +779,11 @@ namespace Barotrauma
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
UpgradeManager?.SavePendingUpgrades(modeElement, UpgradeManager?.PendingUpgrades);
|
||||
|
||||
if (petsElement != null)
|
||||
{
|
||||
modeElement.Add(petsElement);
|
||||
}
|
||||
|
||||
// save bots
|
||||
CrewManager.SaveMultiplayer(modeElement);
|
||||
|
||||
|
||||
@@ -67,8 +67,26 @@ namespace Barotrauma.Items.Components
|
||||
if (!CheckCharacterSuccess(c.Character))
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
c.Character.SelectedItems[0]?.GetComponent<Wire>()?.CreateNetworkEvent();
|
||||
c.Character.SelectedItems[1]?.GetComponent<Wire>()?.CreateNetworkEvent();
|
||||
c.Character.Inventory?.CreateNetworkEvent();
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
var selectedWire = c.Character.SelectedItems[i]?.GetComponent<Wire>();
|
||||
if (selectedWire == null) { continue; }
|
||||
|
||||
selectedWire.CreateNetworkEvent();
|
||||
var panel1 = selectedWire.Connections[0]?.ConnectionPanel;
|
||||
if (panel1 != null && panel1 != this) { panel1.item.CreateServerEvent(panel1); }
|
||||
var panel2 = selectedWire.Connections[1]?.ConnectionPanel;
|
||||
if (panel2 != null && panel2 != this) { panel2.item.CreateServerEvent(panel2); }
|
||||
|
||||
CoroutineManager.InvokeAfter(() =>
|
||||
{
|
||||
item.CreateServerEvent(this);
|
||||
if (panel1 != null && panel1 != this) { panel1.item.CreateServerEvent(panel1); }
|
||||
if (panel2 != null && panel2 != this) { panel2.item.CreateServerEvent(panel2); }
|
||||
if (!selectedWire.Item.Removed) { selectedWire.CreateNetworkEvent(); }
|
||||
}, 1.0f);
|
||||
}
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, c.Character.ID });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
try
|
||||
{
|
||||
WritePropertyChange(msg, extraData, false);
|
||||
WritePropertyChange(msg, extraData, inGameEditableOnly: !GameMain.NetworkMember.IsServer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -222,7 +222,7 @@ namespace Barotrauma
|
||||
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
ReadPropertyChange(msg, true, c);
|
||||
ReadPropertyChange(msg, inGameEditableOnly: GameMain.NetworkMember.IsServer, sender: c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Combine:
|
||||
UInt16 combineTargetID = msg.ReadUInt16();
|
||||
@@ -367,23 +367,42 @@ namespace Barotrauma
|
||||
|
||||
public void CreateServerEvent<T>(T ic) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) return;
|
||||
if (index == -1) { return; }
|
||||
|
||||
object[] extraData = new object[] { NetEntityEvent.Type.ComponentState, index };
|
||||
ic.ServerAppendExtraData(ref extraData);
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, extraData);
|
||||
}
|
||||
|
||||
public void CreateServerEvent<T>(T ic, object[] extraData) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) { return; }
|
||||
|
||||
object[] data = new object[] { NetEntityEvent.Type.ComponentState, index }.Concat(extraData).ToArray();
|
||||
GameMain.Server.CreateEntityEvent(this, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user