Unstable 1.1.14.0

This commit is contained in:
Markus Isberg
2023-10-02 16:43:54 +03:00
parent 94f5a93a0c
commit cf8f0de659
606 changed files with 21906 additions and 11456 deletions
@@ -211,6 +211,9 @@ namespace Barotrauma.Items.Components
#endif
public bool DisableHeadRotation { get; set; }
[Serialize(false, IsPropertySaveable.No, description: "If true, this item can't be used if the character is also holding a ranged weapon.")]
public bool DisableWhenRangedWeaponEquipped { get; set; }
[ConditionallyEditable(ConditionallyEditable.ConditionType.Attachable, MinValueFloat = 0.0f, MaxValueFloat = 0.999f, DecimalCount = 3), Serialize(0.55f, IsPropertySaveable.No, description: "Sprite depth that's used when the item is NOT attached to a wall.")]
public float SpriteDepthWhenDropped
{
@@ -343,11 +346,9 @@ namespace Barotrauma.Items.Components
DeattachFromWall();
}
if (setTransform)
{
if (Pusher != null) { Pusher.Enabled = false; }
if (item.body != null) { item.body.Enabled = true; }
}
if (Pusher != null) { Pusher.Enabled = false; }
if (item.body != null) { item.body.Enabled = true; }
IsActive = false;
attachTargetCell = null;
@@ -616,6 +617,7 @@ namespace Barotrauma.Items.Components
{
//set to submarine-relative position
item.SetTransform(ConvertUnits.ToSimUnits(item.WorldPosition - attachTarget.Submarine.Position), 0.0f, false);
body.SetTransformIgnoreContacts(item.SimPosition, 0.0f);
}
item.Submarine = attachTarget.Submarine;
}
@@ -688,6 +690,7 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (UsageDisabledByRangedWeapon(character)) { return false; }
if (!attachable || item.body == null) { return character == null || (character.IsKeyDown(InputType.Aim) && characterUsable); }
if (character != null)
{
@@ -792,19 +795,27 @@ namespace Barotrauma.Items.Components
Vector2 userPos = useWorldCoordinates ? user.WorldPosition : user.Position;
Vector2 attachPos = userPos + mouseDiff;
//offset the position by half the size of the grid to get the item to adhere to the grid in the same way as in the sub editor
//in the sub editor, we align the top-left corner of the item with the grid
//but here the origin of the item is placed at the attach position, so we need to offset it
Vector2 offset = new Vector2(
-(item.Rect.Width / 2) % Submarine.GridSize.X,
(item.Rect.Height / 2) % Submarine.GridSize.Y);
if (user.Submarine != null)
{
if (Submarine.PickBody(
ConvertUnits.ToSimUnits(user.Position),
ConvertUnits.ToSimUnits(user.Position + mouseDiff), collisionCategory: Physics.CollisionWall) != null)
{
attachPos = userPos + mouseDiff * Submarine.LastPickedFraction;
attachPos = userPos + mouseDiff * Submarine.LastPickedFraction + offset;
//round down if we're placing on the right side and vice versa: ensures we don't round the position inside a wall
return
new Vector2(
mouseDiff.X > 0 ? (float)Math.Floor(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X,
mouseDiff.Y > 0 ? (float)Math.Floor(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.Y);
(mouseDiff.X > 0 ? MathF.Floor(attachPos.X / Submarine.GridSize.X) : MathF.Ceiling(attachPos.X / Submarine.GridSize.X)) * Submarine.GridSize.X,
(mouseDiff.Y > 0 ? MathF.Floor(attachPos.Y / Submarine.GridSize.Y) : MathF.Ceiling(attachPos.Y / Submarine.GridSize.Y)) * Submarine.GridSize.Y)
- offset;
}
}
else if (Level.Loaded != null)
@@ -827,10 +838,9 @@ namespace Barotrauma.Items.Components
}
}
return
new Vector2(
MathUtils.RoundTowardsClosest(attachPos.X, Submarine.GridSize.X),
MathUtils.RoundTowardsClosest(attachPos.Y, Submarine.GridSize.Y));
return new Vector2(
MathUtils.RoundTowardsClosest(attachPos.X + offset.X, Submarine.GridSize.X),
MathUtils.RoundTowardsClosest(attachPos.Y + offset.Y, Submarine.GridSize.Y)) - offset;
}
private Voronoi2.VoronoiCell GetAttachTargetCell(float maxDist)
@@ -903,7 +913,7 @@ namespace Barotrauma.Items.Components
{
scaledHandlePos[0] = handlePos[0] * item.Scale;
scaledHandlePos[1] = handlePos[1] * item.Scale;
bool aim = picker.IsKeyDown(InputType.Aim) && aimPos != Vector2.Zero && picker.CanAim;
bool aim = picker.IsKeyDown(InputType.Aim) && aimPos != Vector2.Zero && picker.CanAim && !UsageDisabledByRangedWeapon(picker);
if (aim)
{
picker.AnimController.HoldItem(deltaTime, item, scaledHandlePos, holdPos + swingPos, aimPos + swingPos, aim, holdAngle, aimAngle);
@@ -963,6 +973,15 @@ namespace Barotrauma.Items.Components
}
}
protected bool UsageDisabledByRangedWeapon(Character character)
{
if (DisableWhenRangedWeaponEquipped && character != null)
{
if (character.HeldItems.Any(it => it.GetComponent<RangedWeapon>() != null)) { return true; }
}
return false;
}
public override void ReceiveSignal(Signal signal, Connection connection)
{
//do nothing
@@ -1005,14 +1024,12 @@ namespace Barotrauma.Items.Components
}
else
{
if (item.ParentInventory != null)
if (body != null)
{
if (body != null)
{
item.body = body;
body.Enabled = false;
}
}
body.SetTransformIgnoreContacts(item.SimPosition, item.Rotation);
item.body = body;
body.Enabled = item.ParentInventory == null;
}
DeattachFromWall();
}
}
@@ -37,7 +37,20 @@ namespace Barotrauma.Items.Components
[Serialize("", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public string OwnerName { get; set; }
private string ownerNameLocalized;
[Serialize("", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public string OwnerNameLocalized
{
get { return ownerNameLocalized; }
set
{
if (value.IsNullOrWhiteSpace()) { return; }
ownerNameLocalized = value;
OwnerName = TextManager.Get(value).Fallback(value).Value;
}
}
[Serialize("", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public Identifier OwnerJobId { get; set; }
@@ -67,6 +80,9 @@ namespace Barotrauma.Items.Components
[Serialize("0,0", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public Vector2 OwnerSheetIndex { get; set; }
[Serialize(false, IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public bool SpawnPointTagsGiven { get; set; }
public IdCard(Item item, ContentXElement element) : base(item, element) { }
public void Initialize(WayPoint spawnPoint, Character character)
@@ -135,7 +135,7 @@ namespace Barotrauma.Items.Components
private void CreateTriggerBody()
{
System.Diagnostics.Debug.Assert(trigger == null, "LevelResource trigger already created!");
var body = item.body ?? holdable.Body;
var body = item.body ?? holdable?.Body;
if (body != null && Attached)
{
trigger = new PhysicsBody(body.Width, body.Height, body.Radius,
@@ -189,7 +189,7 @@ namespace Barotrauma.Items.Components
impactQueue.Clear();
return;
}
if (picker == null && !picker.HeldItems.Contains(item))
if (picker == null || !picker.HeldItems.Contains(item))
{
impactQueue.Clear();
IsActive = false;
@@ -218,7 +218,8 @@ namespace Barotrauma.Items.Components
AnimController ac = picker.AnimController;
if (!hitting)
{
bool aim = item.RequireAimToUse && picker.AllowInput && picker.IsKeyDown(InputType.Aim) && reloadTimer <= 0 && picker.CanAim;
bool aim = item.RequireAimToUse && picker.AllowInput && picker.IsKeyDown(InputType.Aim) && reloadTimer <= 0 && picker.CanAim &&
!UsageDisabledByRangedWeapon(picker);
if (aim)
{
UpdateSwingPos(deltaTime, out Vector2 swingPos);
@@ -364,7 +365,7 @@ namespace Barotrauma.Items.Components
}
hitTargets.Add(targetStructure);
}
else if (f2.Body.UserData is Item targetItem)
else if ((f2.Body.UserData as Item ?? f2.UserData as Item) is Item targetItem)
{
if (AllowHitMultiple)
{
@@ -410,7 +411,7 @@ namespace Barotrauma.Items.Components
Limb targetLimb = target.UserData as Limb;
Character targetCharacter = targetLimb?.character ?? target.UserData as Character;
Structure targetStructure = target.UserData as Structure ?? targetFixture.UserData as Structure;
Item targetItem = target.UserData as Item;
Item targetItem = target.UserData as Item ?? targetFixture.UserData as Item;
Entity targetEntity = targetCharacter ?? targetStructure ?? targetItem ?? target.UserData as Entity;
if (Attack != null)
{
@@ -73,6 +73,7 @@ namespace Barotrauma.Items.Components
{
//return if someone is already trying to pick the item
if (pickTimer > 0.0f) { return false; }
if (PickingTime >= float.MaxValue) { return false; }
if (picker == null || picker.Inventory == null) { return false; }
if (!picker.Inventory.AccessibleWhenAlive && !picker.Inventory.AccessibleByOwner) { return false; }
@@ -112,10 +113,16 @@ namespace Barotrauma.Items.Components
}
}
public virtual bool OnPicked(Character picker)
{
return OnPicked(picker, pickDroppedStack: true);
}
public virtual bool OnPicked(Character picker, bool pickDroppedStack)
{
//if the item has multiple Pickable components (e.g. Holdable and Wearable, check that we don't equip it in hands when the item is worn or vice versa)
if (item.GetComponents<Pickable>().Count() > 0)
if (item.GetComponents<Pickable>().Any())
{
bool alreadyEquipped = false;
for (int i = 0; i < picker.Inventory.Capacity; i++)
@@ -132,11 +139,13 @@ namespace Barotrauma.Items.Components
}
if (alreadyEquipped) { return false; }
}
var droppedStack = pickDroppedStack ? item.DroppedStack.ToList() : null;
if (picker.Inventory.TryPutItemWithAutoEquipCheck(item, picker, allowedSlots))
{
if (!picker.HeldItems.Contains(item) && item.body != null) { item.body.Enabled = false; }
this.picker = picker;
for (int i = item.linkedTo.Count - 1; i >= 0; i--)
{
item.linkedTo[i].RemoveLinked(item);
@@ -147,14 +156,22 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker);
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) SoundPlayer.PlayUISound(GUISoundType.PickItem);
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) { SoundPlayer.PlayUISound(GUISoundType.PickItem); }
PlaySound(ActionType.OnPicked, picker);
#endif
if (pickDroppedStack)
{
foreach (var droppedItem in droppedStack)
{
if (droppedItem == item) { continue; }
droppedItem.GetComponent<Pickable>().OnPicked(picker, pickDroppedStack: false);
}
}
return true;
}
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) { SoundPlayer.PlayUISound(GUISoundType.PickItemFail); }
#endif
return false;
@@ -183,12 +200,15 @@ namespace Barotrauma.Items.Components
}
#if CLIENT
Character.Controlled?.UpdateHUDProgressBar(
this,
item.WorldPosition,
pickTimer / requiredTime,
GUIStyle.Red, GUIStyle.Green,
!string.IsNullOrWhiteSpace(PickingMsg) ? PickingMsg : this is Door ? "progressbar.opening" : "progressbar.deattaching");
if (requiredTime < float.MaxValue)
{
Character.Controlled?.UpdateHUDProgressBar(
this,
item.WorldPosition,
pickTimer / requiredTime,
GUIStyle.Red, GUIStyle.Green,
!string.IsNullOrWhiteSpace(PickingMsg) ? PickingMsg : this is Door ? "progressbar.opening" : "progressbar.deattaching");
}
#endif
picker.AnimController.UpdateUseItem(!picker.IsClimbing, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((pickTimer / 10.0f) % 0.1f));
pickTimer += CoroutineManager.DeltaTime;
@@ -197,12 +217,14 @@ namespace Barotrauma.Items.Components
}
StopPicking(picker);
bool isNotRemote = true;
if (!item.Removed)
{
bool isNotRemote = true;
#if CLIENT
isNotRemote = !picker.IsRemotePlayer;
isNotRemote = !picker.IsRemotePlayer;
#endif
if (isNotRemote) OnPicked(picker);
if (isNotRemote) { OnPicked(picker); }
}
yield return CoroutineStatus.Success;
}
@@ -608,6 +608,7 @@ namespace Barotrauma.Items.Components
float closestDist = float.MaxValue;
foreach (Limb limb in targetCharacter.AnimController.Limbs)
{
if (limb.Removed || limb.IgnoreCollisions || limb.Hidden || limb.IsSevered) { continue; }
float dist = Vector2.DistanceSquared(item.SimPosition, limb.SimPosition);
if (dist < closestDist)
{
@@ -716,7 +717,7 @@ namespace Barotrauma.Items.Components
private readonly float repairTimeOut = 5;
public override bool CrewAIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
if (!(objective.OperateTarget is Gap leak))
if (objective.OperateTarget is not Gap leak)
{
Reset();
return true;
@@ -806,36 +807,50 @@ namespace Barotrauma.Items.Components
// Press the trigger only when the tool is approximately facing the target.
Vector2 fromItemToLeak = leak.WorldPosition - item.WorldPosition;
var angle = VectorExtensions.Angle(VectorExtensions.Forward(item.body.TransformedRotation), fromItemToLeak);
bool repair = true;
if (angle < MathHelper.PiOver4)
{
if (Submarine.PickBody(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionWall, allowInsideFixture: true)?.UserData is Item i)
{
var door = i.GetComponent<Door>();
// Hit a door, abandon so that we don't weld it shut.
return door != null && !door.CanBeTraversed;
{
if (i.GetComponent<Door>() is Door door && !door.CanBeTraversed )
{
// Hit a door, don't repair so that we don't weld it shut.
if (door.Stuck > 90)
{
// Almost stuck -> just abandon.
return false;
}
if (door.Stuck > 50)
{
repair = false;
}
}
}
// Check that we don't hit any friendlies
if (Submarine.PickBodies(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionCharacter).None(hit =>
if (repair)
{
if (hit.UserData is Character c)
// Check that we don't hit any friendlies
if (Submarine.PickBodies(item.SimPosition, leak.SimPosition, collisionCategory: Physics.CollisionCharacter).None(hit =>
{
if (c == character) { return false; }
return HumanAIController.IsFriendly(character, c);
if (hit.UserData is Character c)
{
if (c == character) { return false; }
return HumanAIController.IsFriendly(character, c);
}
return false;
}))
{
character.SetInput(InputType.Shoot, false, true);
Use(deltaTime, character);
}
return false;
}))
}
repairTimer += deltaTime;
if (repairTimer > repairTimeOut)
{
character.SetInput(InputType.Shoot, false, true);
Use(deltaTime, character);
repairTimer += deltaTime;
if (repairTimer > repairTimeOut)
{
#if DEBUG
DebugConsole.NewMessage($"{character.Name}: timed out while welding a leak in {leak.FlowTargetHull.DisplayName}.", color: Color.Yellow);
DebugConsole.NewMessage($"{character.Name}: timed out while welding a leak in {leak.FlowTargetHull.DisplayName}.", color: Color.Yellow);
#endif
Reset();
return true;
}
Reset();
return true;
}
}
}
@@ -912,7 +927,7 @@ namespace Barotrauma.Items.Components
// A general purpose system could be better, but it would most likely require changes in the way we define the status effects in xml.
foreach (ISerializableEntity target in currentTargets)
{
if (target is not Door door) { continue; }
if (target is not Door door) { continue; }
if (!door.CanBeWelded || !door.Item.IsInteractable(user)) { continue; }
foreach (var propertyEffect in effect.PropertyEffects)
{