(d9829ac) v0.9.4.0
This commit is contained in:
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
|
||||
get { return item.body ?? body; }
|
||||
}
|
||||
|
||||
[Serialize(false, true)]
|
||||
[Serialize(false, true, description: "Is the item currently attached to a wall (only valid if Attachable is set to true).")]
|
||||
public bool Attached
|
||||
{
|
||||
get { return attached && item.ParentInventory == null; }
|
||||
@@ -50,56 +50,58 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
[Serialize(true, true, description: "Can the item be pointed to a specific direction or do the characters always hold it in a static pose.")]
|
||||
public bool Aimable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Should the character adjust its pose when aiming with the item. Most noticeable underwater, where the character will rotate its entire body to face the direction the item is aimed at.")]
|
||||
public bool ControlPose
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Can the item be attached to walls.")]
|
||||
public bool Attachable
|
||||
{
|
||||
get { return attachable; }
|
||||
set { attachable = value; }
|
||||
}
|
||||
|
||||
[Serialize(true, false)]
|
||||
[Serialize(true, false, description: "Can the item be reattached to walls after it has been deattached (only valid if Attachable is set to true).")]
|
||||
public bool Reattachable
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Should the item be attached to a wall by default when it's placed in the submarine editor.")]
|
||||
public bool AttachedByDefault
|
||||
{
|
||||
get { return attachedByDefault; }
|
||||
set { attachedByDefault = value; }
|
||||
}
|
||||
|
||||
[Serialize("0.0,0.0", false),Editable]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "The position the character holds the item at (in pixels, as an offset from the character's shoulder)."+
|
||||
" For example, a value of 10,-100 would make the character hold the item 100 pixels below the shoulder and 10 pixels forwards.")]
|
||||
public Vector2 HoldPos
|
||||
{
|
||||
get { return ConvertUnits.ToDisplayUnits(holdPos); }
|
||||
set { holdPos = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
[Serialize("0.0,0.0", false)]
|
||||
[Serialize("0.0,0.0", false, description: "The position the character holds the item at when aiming (in pixels, as an offset from the character's shoulder)."+
|
||||
" Works similarly as HoldPos, except that the position is rotated according to the direction the player is aiming at. For example, a value of 10,-100 would make the character hold the item 100 pixels below the shoulder and 10 pixels forwards when aiming directly to the right.")]
|
||||
public Vector2 AimPos
|
||||
{
|
||||
get { return ConvertUnits.ToDisplayUnits(aimPos); }
|
||||
set { aimPos = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false), Editable]
|
||||
[Editable, Serialize(0.0f, false, description: "The rotation at which the character holds the item (in degrees, relative to the rotation of the character's hand).")]
|
||||
public float HoldAngle
|
||||
{
|
||||
get { return MathHelper.ToDegrees(holdAngle); }
|
||||
@@ -107,21 +109,21 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
private Vector2 swingAmount;
|
||||
[Serialize("0.0,0.0", false), Editable]
|
||||
[Editable, Serialize("0.0,0.0", false, description: "How much the item swings around when aiming/holding it (in pixels, as an offset from AimPos/HoldPos).")]
|
||||
public Vector2 SwingAmount
|
||||
{
|
||||
get { return ConvertUnits.ToDisplayUnits(swingAmount); }
|
||||
set { swingAmount = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false), Editable]
|
||||
[Editable, Serialize(0.0f, false, description: "How fast the item swings around when aiming/holding it (only valid if SwingAmount is set).")]
|
||||
public float SwingSpeed { get; set; }
|
||||
|
||||
[Serialize(false, false), Editable]
|
||||
[Editable, Serialize(false, false, description: "Should the item swing around when it's being held.")]
|
||||
public bool SwingWhenHolding { get; set; }
|
||||
[Serialize(false, false), Editable]
|
||||
[Editable, Serialize(false, false, description: "Should the item swing around when it's being aimed.")]
|
||||
public bool SwingWhenAiming { get; set; }
|
||||
[Serialize(false, false), Editable]
|
||||
[Editable, Serialize(false, false, description: "Should the item swing around when it's being used (for example, when firing a weapon or a welding tool).")]
|
||||
public bool SwingWhenUsing { get; set; }
|
||||
|
||||
public Holdable(Item item, XElement element)
|
||||
@@ -189,9 +191,16 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public override void Load(XElement componentElement)
|
||||
public override void Load(XElement componentElement, bool usePrefabValues)
|
||||
{
|
||||
base.Load(componentElement);
|
||||
base.Load(componentElement, usePrefabValues);
|
||||
|
||||
if (usePrefabValues)
|
||||
{
|
||||
//this needs to be loaded regardless
|
||||
Attached = componentElement.GetAttributeBool("attached", attached);
|
||||
}
|
||||
|
||||
if (attachable)
|
||||
{
|
||||
prevMsg = DisplayMsg;
|
||||
@@ -221,24 +230,24 @@ namespace Barotrauma.Items.Components
|
||||
item.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (picker == null)
|
||||
{
|
||||
if (dropper == null) return;
|
||||
if (dropper == null) { return; }
|
||||
picker = dropper;
|
||||
}
|
||||
if (picker.Inventory == null) return;
|
||||
if (picker.Inventory == null) { return; }
|
||||
|
||||
item.Submarine = picker.Submarine;
|
||||
if (item.body != null)
|
||||
{
|
||||
item.body.ResetDynamics();
|
||||
Limb heldHand;
|
||||
Limb arm;
|
||||
Limb heldHand, arm;
|
||||
Vector2 diff = Vector2.Zero;
|
||||
if (picker.Inventory.IsInLimbSlot(item, InvSlotType.LeftHand))
|
||||
{
|
||||
heldHand = picker.AnimController.GetLimb(LimbType.LeftHand);
|
||||
@@ -249,11 +258,18 @@ namespace Barotrauma.Items.Components
|
||||
heldHand = picker.AnimController.GetLimb(LimbType.RightHand);
|
||||
arm = picker.AnimController.GetLimb(LimbType.RightArm);
|
||||
}
|
||||
|
||||
float xDif = (heldHand.SimPosition.X - arm.SimPosition.X) / 2f;
|
||||
float yDif = (heldHand.SimPosition.Y - arm.SimPosition.Y) / 2.5f;
|
||||
//hand simPosition is actually in the wrist so need to move the item out from it slightly
|
||||
item.SetTransform(heldHand.SimPosition + new Vector2(xDif, yDif), 0.0f);
|
||||
if (heldHand != null && arm != null)
|
||||
{
|
||||
//hand simPosition is actually in the wrist so need to move the item out from it slightly
|
||||
diff = new Vector2(
|
||||
(heldHand.SimPosition.X - arm.SimPosition.X) / 2f,
|
||||
(heldHand.SimPosition.Y - arm.SimPosition.Y) / 2.5f);
|
||||
item.SetTransform(heldHand.SimPosition + diff, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SetTransform(picker.SimPosition, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
picker.DeselectItem(item);
|
||||
|
||||
@@ -16,14 +16,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private float deattachTimer;
|
||||
|
||||
[Serialize(1.0f, false)]
|
||||
[Serialize(1.0f, false, description: "How long it takes to deattach the item from the level walls (in seconds).")]
|
||||
public float DeattachDuration
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "How far along the item is to being deattached. When the timer goes above DeattachDuration, the item is deattached.")]
|
||||
public float DeattachTimer
|
||||
{
|
||||
get { return deattachTimer; }
|
||||
|
||||
@@ -15,38 +15,32 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool hitting;
|
||||
|
||||
private Attack attack;
|
||||
|
||||
private float range;
|
||||
|
||||
private Character user;
|
||||
|
||||
private float reload;
|
||||
|
||||
private float reloadTimer;
|
||||
|
||||
private HashSet<Entity> hitTargets = new HashSet<Entity>();
|
||||
private readonly Attack attack;
|
||||
|
||||
public Character User
|
||||
{
|
||||
get { return user; }
|
||||
}
|
||||
private readonly HashSet<Entity> hitTargets = new HashSet<Entity>();
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public Character User { get; private set; }
|
||||
|
||||
[Serialize(0.0f, false, description: "An estimation of how close the item has to be to the target for it to hit. Used by AI characters to determine when they're close enough to hit a target.")]
|
||||
public float Range
|
||||
{
|
||||
get { return ConvertUnits.ToDisplayUnits(range); }
|
||||
set { range = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
[Serialize(0.5f, false)]
|
||||
[Serialize(0.5f, false, description: "How long the user has to wait before they can hit with the weapon again (in seconds).")]
|
||||
public float Reload
|
||||
{
|
||||
get { return reload; }
|
||||
set { reload = Math.Max(0.0f, value); }
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Can the weapon hit multiple targets per swing.")]
|
||||
public bool AllowHitMultiple
|
||||
{
|
||||
get;
|
||||
@@ -85,6 +79,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (hitPos < MathHelper.PiOver4) { return false; }
|
||||
|
||||
ActivateNearbySleepingCharacters();
|
||||
reloadTimer = reload;
|
||||
|
||||
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
|
||||
@@ -162,7 +157,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
hitPos = MathUtils.WrapAnglePi(hitPos - deltaTime * 15f);
|
||||
ac.HoldItem(deltaTime, item, handlePos, new Vector2(2, 0), Vector2.Zero, false, hitPos, holdAngle + hitPos); // aimPos not used -> zero (new Vector2(-0.3f, 0.2f)), holdPos new Vector2(0.6f, -0.1f)
|
||||
if (hitPos < -MathHelper.PiOver4 * 1.2f)
|
||||
if (hitPos < -MathHelper.PiOver2)
|
||||
{
|
||||
RestoreCollision();
|
||||
hitting = false;
|
||||
@@ -172,12 +167,36 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activate sleeping ragdolls that are close enough to hit with the weapon (otherwise the collision will not be registered)
|
||||
/// </summary>
|
||||
private void ActivateNearbySleepingCharacters()
|
||||
{
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (!c.Enabled || !c.AnimController.BodyInRest) { continue; }
|
||||
//do a broad check first
|
||||
if (Math.Abs(c.WorldPosition.X - item.WorldPosition.X) > 1000.0f) { continue; }
|
||||
if (Math.Abs(c.WorldPosition.Y - item.WorldPosition.Y) > 1000.0f) { continue; }
|
||||
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
float hitRange = 2.0f;
|
||||
if (Vector2.DistanceSquared(limb.SimPosition, item.SimPosition) < hitRange * hitRange)
|
||||
{
|
||||
c.AnimController.BodyInRest = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetUser(Character character)
|
||||
{
|
||||
if (user == character) { return; }
|
||||
if (user != null && user.Removed) { user = null; }
|
||||
if (User == character) { return; }
|
||||
if (User != null && User.Removed) { User = null; }
|
||||
|
||||
user = character;
|
||||
User = character;
|
||||
|
||||
if (item.body?.FarseerBody == null || item.Removed ||
|
||||
!GameMain.World.BodyList.Contains(item.body.FarseerBody))
|
||||
@@ -185,9 +204,9 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (user != null)
|
||||
if (User != null)
|
||||
{
|
||||
foreach (Limb limb in user.AnimController.Limbs)
|
||||
foreach (Limb limb in User.AnimController.Limbs)
|
||||
{
|
||||
if (limb.body.FarseerBody != null && GameMain.World.BodyList.Contains(limb.body.FarseerBody))
|
||||
{
|
||||
@@ -216,18 +235,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool OnCollision(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
if (user == null || user.Removed)
|
||||
if (User == null || User.Removed)
|
||||
{
|
||||
RestoreCollision();
|
||||
hitting = false;
|
||||
user = null;
|
||||
User = null;
|
||||
}
|
||||
|
||||
Character targetCharacter = null;
|
||||
Limb targetLimb = null;
|
||||
Structure targetStructure = null;
|
||||
|
||||
attack?.SetUser(user);
|
||||
attack?.SetUser(User);
|
||||
|
||||
if (f2.Body.UserData is Limb)
|
||||
{
|
||||
@@ -283,16 +302,16 @@ namespace Barotrauma.Items.Components
|
||||
if (targetLimb != null)
|
||||
{
|
||||
targetLimb.character.LastDamageSource = item;
|
||||
attack.DoDamageToLimb(user, targetLimb, item.WorldPosition, 1.0f);
|
||||
attack.DoDamageToLimb(User, targetLimb, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.LastDamageSource = item;
|
||||
attack.DoDamage(user, targetCharacter, item.WorldPosition, 1.0f);
|
||||
attack.DoDamage(User, targetCharacter, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else if (targetStructure != null)
|
||||
{
|
||||
attack.DoDamage(user, targetStructure, item.WorldPosition, 1.0f);
|
||||
attack.DoDamage(User, targetStructure, item.WorldPosition, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -326,7 +345,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: user);
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: User);
|
||||
}
|
||||
|
||||
if (DeleteOnUse)
|
||||
|
||||
@@ -10,27 +10,22 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
class Propulsion : ItemComponent
|
||||
{
|
||||
enum UsableIn
|
||||
public enum UseEnvironment
|
||||
{
|
||||
Air, Water, Both
|
||||
};
|
||||
|
||||
private float force;
|
||||
|
||||
private float useState;
|
||||
|
||||
private UsableIn usableIn;
|
||||
|
||||
[Serialize(0.0f, false), Editable(MinValueFloat = -1000.0f, MaxValueFloat = 1000.0f)]
|
||||
public float Force
|
||||
{
|
||||
get { return force; }
|
||||
set { force = value; }
|
||||
}
|
||||
[Serialize(UseEnvironment.Both, false, description: "Can the item be used in air, underwater or both.")]
|
||||
public UseEnvironment UsableIn { get; set; }
|
||||
|
||||
[Serialize(0.0f, false, description: "The force to apply to the user's body."), Editable(MinValueFloat = -1000.0f, MaxValueFloat = 1000.0f)]
|
||||
public float Force { get; set; }
|
||||
|
||||
#if CLIENT
|
||||
private string particles;
|
||||
[Serialize("", false)]
|
||||
[Serialize("", false, description: "The name of the particle prefab the item emits when used.")]
|
||||
public string Particles
|
||||
{
|
||||
get { return particles; }
|
||||
@@ -41,19 +36,6 @@ namespace Barotrauma.Items.Components
|
||||
public Propulsion(Item item, XElement element)
|
||||
: base(item,element)
|
||||
{
|
||||
switch (element.GetAttributeString("usablein", "both").ToLowerInvariant())
|
||||
{
|
||||
case "air":
|
||||
usableIn = UsableIn.Air;
|
||||
break;
|
||||
case "water":
|
||||
usableIn = UsableIn.Water;
|
||||
break;
|
||||
case "both":
|
||||
default:
|
||||
usableIn = UsableIn.Both;
|
||||
break;
|
||||
}
|
||||
ResetSoundRange();
|
||||
}
|
||||
|
||||
@@ -67,18 +49,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (character.AnimController.InWater)
|
||||
{
|
||||
if (usableIn == UsableIn.Air) return true;
|
||||
if (UsableIn == UseEnvironment.Air) return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (usableIn == UsableIn.Water) return true;
|
||||
if (UsableIn == UseEnvironment.Water) return true;
|
||||
}
|
||||
|
||||
Vector2 dir = Vector2.Normalize(character.CursorPosition - character.Position);
|
||||
//move upwards if the cursor is at the position of the character
|
||||
if (!MathUtils.IsValid(dir)) dir = Vector2.UnitY;
|
||||
|
||||
Vector2 propulsion = dir * force;
|
||||
Vector2 propulsion = dir * Force;
|
||||
|
||||
if (character.AnimController.InWater) character.AnimController.TargetMovement = dir;
|
||||
|
||||
|
||||
@@ -15,28 +15,28 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private Vector2 barrelPos;
|
||||
|
||||
[Serialize("0.0,0.0", false)]
|
||||
[Serialize("0.0,0.0", false, description: "The position of the barrel as an offset from the item's center (in pixels). Determines where the projectiles spawn.")]
|
||||
public string BarrelPos
|
||||
{
|
||||
get { return XMLExtensions.Vector2ToString(ConvertUnits.ToDisplayUnits(barrelPos)); }
|
||||
set { barrelPos = ConvertUnits.ToSimUnits(XMLExtensions.ParseVector2(value)); }
|
||||
}
|
||||
|
||||
[Serialize(1.0f, false)]
|
||||
[Serialize(1.0f, false, description: "How long the user has to wait before they can fire the weapon again (in seconds).")]
|
||||
public float Reload
|
||||
{
|
||||
get { return reload; }
|
||||
set { reload = Math.Max(value, 0.0f); }
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "Random spread applied to the firing angle of the projectiles when used by a character with sufficient skills to use the weapon (in degrees).")]
|
||||
public float Spread
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "Random spread applied to the firing angle of the projectiles when used by a character with insufficient skills to use the weapon (in degrees).")]
|
||||
public float UnskilledSpread
|
||||
{
|
||||
get;
|
||||
@@ -109,30 +109,21 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
foreach (Item item in containedItems)
|
||||
{
|
||||
projectile = item.GetComponent<Projectile>();
|
||||
if (projectile != null) break;
|
||||
}
|
||||
//projectile not found, see if one of the contained items contains projectiles
|
||||
if (projectile == null)
|
||||
{
|
||||
foreach (Item item in containedItems)
|
||||
var containedSubItems = item.ContainedItems;
|
||||
if (containedSubItems == null) { continue; }
|
||||
foreach (Item subItem in containedSubItems)
|
||||
{
|
||||
var containedSubItems = item.ContainedItems;
|
||||
if (containedSubItems == null) { continue; }
|
||||
foreach (Item subItem in containedSubItems)
|
||||
projectile = subItem.GetComponent<Projectile>();
|
||||
//apply OnUse statuseffects to the container in case it has to react to it somehow
|
||||
//(play a sound, spawn more projectiles, reduce condition...)
|
||||
if (subItem.Condition > 0.0f)
|
||||
{
|
||||
projectile = subItem.GetComponent<Projectile>();
|
||||
//apply OnUse statuseffects to the container in case it has to react to it somehow
|
||||
//(play a sound, spawn more projectiles, reduce condition...)
|
||||
if (subItem.Condition > 0.0f)
|
||||
{
|
||||
subItem.GetComponent<ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
|
||||
}
|
||||
if (projectile != null) break;
|
||||
subItem.GetComponent<ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
|
||||
}
|
||||
if (projectile != null) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (projectile == null) return true;
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
#if CLIENT
|
||||
using Barotrauma.Particles;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -25,41 +22,58 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private Vector2 debugRayStartPos, debugRayEndPos;
|
||||
|
||||
[Serialize("Both", false)]
|
||||
[Serialize("Both", false, description: "Can the item be used in air, water or both.")]
|
||||
public UseEnvironment UsableIn
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "The distance at which the item can repair targets.")]
|
||||
public float Range { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "Random spread applied to the firing angle when used by a character with sufficient skills to use the tool (in degrees).")]
|
||||
public float Spread
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false, description: "Random spread applied to the firing angle when used by a character with insufficient skills to use the tool (in degrees).")]
|
||||
public float UnskilledSpread
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0.0f, false, description: "How many units of damage the item removes from structures per second.")]
|
||||
public float StructureFixAmount
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "How much the item decreases the size of fires per second.")]
|
||||
public float ExtinguishAmount
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
[Serialize("0.0,0.0", false)]
|
||||
[Serialize("0.0,0.0", false, description: "The position of the barrel as an offset from the item's center (in pixels).")]
|
||||
public Vector2 BarrelPos { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Can the item repair things through walls.")]
|
||||
public bool RepairThroughWalls { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Can the item repair multiple things at once, or will it only affect the first thing the ray from the barrel hits.")]
|
||||
public bool RepairMultiple { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
[Serialize(false, false, description: "Can the item repair things through holes in walls.")]
|
||||
public bool RepairThroughHoles { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
[Serialize(0.0f, false, description: "The probability of starting a fire somewhere along the ray fired from the barrel (for example, 0.1 = 10% chance to start a fire during a second of use).")]
|
||||
public float FireProbability { get; set; }
|
||||
|
||||
[Serialize(0.0f, false, description: "Force applied to the entity the ray hits.")]
|
||||
public float TargetForce { get; set; }
|
||||
|
||||
public Vector2 TransformedBarrelPos
|
||||
{
|
||||
get
|
||||
@@ -164,10 +178,12 @@ namespace Barotrauma.Items.Components
|
||||
if (item.Submarine != null) { rayStart += item.Submarine.SimPosition; }
|
||||
}
|
||||
|
||||
float spread = MathHelper.ToRadians(MathHelper.Lerp(UnskilledSpread, Spread, degreeOfSuccess));
|
||||
float angle = item.body.Rotation + spread * Rand.Range(-0.5f, 0.5f);
|
||||
Vector2 rayEnd = rayStart +
|
||||
ConvertUnits.ToSimUnits(new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation)) * Range * item.body.Dir);
|
||||
(float)Math.Cos(angle),
|
||||
(float)Math.Sin(angle)) * Range * item.body.Dir);
|
||||
|
||||
List<Body> ignoredBodies = new List<Body>();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
@@ -319,6 +335,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return true; }
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new ISerializableEntity[] { targetStructure });
|
||||
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
|
||||
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
|
||||
|
||||
@@ -341,15 +358,43 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (targetCharacter.Removed) { return false; }
|
||||
targetCharacter.LastDamageSource = item;
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter });
|
||||
Limb closestLimb = null;
|
||||
float closestDist = float.MaxValue;
|
||||
foreach (Limb limb in targetCharacter.AnimController.Limbs)
|
||||
{
|
||||
float dist = Vector2.DistanceSquared(item.SimPosition, limb.SimPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestLimb = limb;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestLimb != null && !MathUtils.NearlyEqual(TargetForce, 0.0f))
|
||||
{
|
||||
Vector2 dir = closestLimb.WorldPosition - item.WorldPosition;
|
||||
dir = dir.LengthSquared() < 0.0001f ? Vector2.UnitY : Vector2.Normalize(dir);
|
||||
closestLimb.body.ApplyForce(dir * TargetForce, maxVelocity: 10.0f);
|
||||
}
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse,
|
||||
closestLimb == null ? new ISerializableEntity[] { targetCharacter } : new ISerializableEntity[] { targetCharacter, closestLimb });
|
||||
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
|
||||
return true;
|
||||
}
|
||||
else if (targetBody.UserData is Limb targetLimb)
|
||||
{
|
||||
if (targetLimb.character == null || targetLimb.character.Removed) { return false; }
|
||||
|
||||
if (!MathUtils.NearlyEqual(TargetForce, 0.0f))
|
||||
{
|
||||
Vector2 dir = targetLimb.WorldPosition - item.WorldPosition;
|
||||
dir = dir.LengthSquared() < 0.0001f ? Vector2.UnitY : Vector2.Normalize(dir);
|
||||
targetLimb.body.ApplyForce(dir * TargetForce, maxVelocity: 10.0f);
|
||||
}
|
||||
|
||||
targetLimb.character.LastDamageSource = item;
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb });
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new ISerializableEntity[] { targetLimb.character, targetLimb });
|
||||
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
|
||||
return true;
|
||||
}
|
||||
@@ -359,6 +404,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, targetItem.AllPropertyObjects);
|
||||
|
||||
if (targetItem.body != null && !MathUtils.NearlyEqual(TargetForce, 0.0f))
|
||||
{
|
||||
Vector2 dir = targetItem.WorldPosition - item.WorldPosition;
|
||||
dir = dir.LengthSquared() < 0.0001f ? Vector2.UnitY : Vector2.Normalize(dir);
|
||||
targetItem.body.ApplyForce(dir * TargetForce, maxVelocity: 10.0f);
|
||||
}
|
||||
|
||||
var levelResource = targetItem.GetComponent<LevelResource>();
|
||||
if (levelResource != null && levelResource.IsActive &&
|
||||
levelResource.requiredItems.Any() &&
|
||||
@@ -509,6 +561,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
effect.Apply(actionType, deltaTime, item, targets);
|
||||
}
|
||||
else if (effect.HasTargetType(StatusEffect.TargetType.Character))
|
||||
{
|
||||
effect.Apply(actionType, deltaTime, item, targets.Where(t => t is Character));
|
||||
}
|
||||
else if (effect.HasTargetType(StatusEffect.TargetType.Limb))
|
||||
{
|
||||
effect.Apply(actionType, deltaTime, item, targets.Where(t => t is Limb));
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
// Hard-coded progress bars for welding doors stuck.
|
||||
// A general purpose system could be better, but it would most likely require changes in the way we define the status effects in xml.
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool midAir;
|
||||
|
||||
[Serialize(1.0f, false)]
|
||||
[Serialize(1.0f, false, description: "The impulse applied to the physics body of the item when thrown. Higher values make the item be thrown faster.")]
|
||||
public float ThrowForce
|
||||
{
|
||||
get { return throwForce; }
|
||||
|
||||
Reference in New Issue
Block a user