(d9829ac) v0.9.4.0

This commit is contained in:
Regalis
2019-10-24 18:05:42 +02:00
parent 9aa12bcac2
commit b39922a074
319 changed files with 12516 additions and 6815 deletions
@@ -42,17 +42,17 @@ namespace Barotrauma.Items.Components
public int DockingDir { get; private set; }
[Serialize("32.0,32.0", false)]
[Serialize("32.0,32.0", false, description: "How close the docking port has to be to another port to dock.")]
public Vector2 DistanceTolerance { get; set; }
[Serialize(32.0f, false)]
[Serialize(32.0f, false, description: "How close together the docking ports are forced when docked.")]
public float DockedDistance
{
get;
set;
}
[Serialize(true, false)]
[Serialize(true, false, description: "Is the port horizontal.")]
public bool IsHorizontal
{
get;
@@ -189,9 +189,7 @@ namespace Barotrauma.Items.Components
GameMain.GameScreen.Cam.Shake = Vector2.Distance(DockingTarget.item.Submarine.Velocity, item.Submarine.Velocity);
}
DockingDir = IsHorizontal ?
Math.Sign(DockingTarget.item.WorldPosition.X - item.WorldPosition.X) :
Math.Sign(DockingTarget.item.WorldPosition.Y - item.WorldPosition.Y);
DockingDir = GetDir(DockingTarget);
DockingTarget.DockingDir = -DockingDir;
if (door != null && DockingTarget.door != null)
@@ -230,9 +228,7 @@ namespace Barotrauma.Items.Components
if (!(joint is WeldJoint))
{
DockingDir = IsHorizontal ?
Math.Sign(DockingTarget.item.WorldPosition.X - item.WorldPosition.X) :
Math.Sign(DockingTarget.item.WorldPosition.Y - item.WorldPosition.Y);
DockingDir = GetDir(DockingTarget);
DockingTarget.DockingDir = -DockingDir;
ApplyStatusEffects(ActionType.OnUse, 1.0f);
@@ -312,7 +308,7 @@ namespace Barotrauma.Items.Components
joint.CollideConnected = true;
}
public int GetDir()
public int GetDir(DockingPort dockingTarget = null)
{
if (DockingDir != 0) { return DockingDir; }
@@ -325,7 +321,12 @@ namespace Barotrauma.Items.Components
Math.Sign(door.Item.WorldPosition.Y - door.LinkedGap.linkedTo[0].WorldPosition.Y);
}
}
if (dockingTarget != null)
{
return IsHorizontal ?
Math.Sign(dockingTarget.item.WorldPosition.X - item.WorldPosition.X) :
Math.Sign(dockingTarget.item.WorldPosition.Y - item.WorldPosition.Y);
}
if (item.Submarine != null)
{
return IsHorizontal ?
@@ -964,57 +965,5 @@ namespace Barotrauma.Items.Components
msg.Write(hulls != null && hulls[0] != null && hulls[1] != null && gap != null);
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool isDocked = msg.ReadBoolean();
for (int i = 0; i < 2; i++)
{
if (hulls[i] == null) continue;
item.linkedTo.Remove(hulls[i]);
hulls[i].Remove();
hulls[i] = null;
}
if (gap != null)
{
item.linkedTo.Remove(gap);
gap.Remove();
gap = null;
}
if (isDocked)
{
ushort dockingTargetID = msg.ReadUInt16();
bool isLocked = msg.ReadBoolean();
Entity targetEntity = Entity.FindEntityByID(dockingTargetID);
if (targetEntity == null || !(targetEntity is Item))
{
DebugConsole.ThrowError("Invalid docking port network event (can't dock to " + targetEntity.ToString() + ")");
return;
}
DockingTarget = (targetEntity as Item).GetComponent<DockingPort>();
if (DockingTarget == null)
{
DebugConsole.ThrowError("Invalid docking port network event (" + targetEntity + " doesn't have a docking port component)");
return;
}
Dock(DockingTarget);
if (isLocked)
{
Lock(isNetworkMessage: true, forcePosition: true);
}
}
else
{
Undock();
}
}
}
}
@@ -61,7 +61,7 @@ namespace Barotrauma.Items.Components
public bool CanBeWelded = true;
private float stuck;
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "How badly stuck the door is (in percentages). If the percentage reaches 100, the door needs to be cut open to make it usable again.")]
public float Stuck
{
get { return stuck; }
@@ -74,10 +74,10 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(3.0f, true), Editable]
[Serialize(3.0f, true, description: "How quickly the door opens."), Editable]
public float OpeningSpeed { get; private set; }
[Serialize(3.0f, true), Editable]
[Serialize(3.0f, true, description: "How quickly the door closes."), Editable]
public float ClosingSpeed { get; private set; }
public bool? PredictedState { get; private set; }
@@ -121,10 +121,10 @@ namespace Barotrauma.Items.Components
public bool IsHorizontal { get; private set; }
[Serialize("0.0,0.0,0.0,0.0", false)]
[Serialize("0.0,0.0,0.0,0.0", false, description: "Position and size of the window on the door. The upper left corner is 0,0. Set the width and height to 0 if you don't want the door to have a window.")]
public Rectangle Window { get; set; }
[Editable, Serialize(false, true)]
[Editable, Serialize(false, true, description: "Is the door currently open.")]
public bool IsOpen
{
get { return isOpen; }
@@ -135,7 +135,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(false, false)]
[Serialize(false, false, description: "If the door has integrated buttons, it can be opened by interacting with it directly (instead of using buttons wired to it).")]
public bool HasIntegratedButtons { get; private set; }
public float OpenState
@@ -153,7 +153,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(false, false)]
[Serialize(false, false, description: "Characters and items cannot pass through impassable doors. Useful for things such as ducts that should only let water and air through.")]
public bool Impassable
{
get;
@@ -48,28 +48,28 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 5000.0f)]
[Serialize(100.0f, true, description: "How far the discharge can travel from the item."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 5000.0f)]
public float Range
{
get;
set;
}
[Serialize(10.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, ToolTip = "How much further can the discharge be carried when moving across walls.")]
[Serialize(10.0f, true, description: "How much further can the discharge be carried when moving across walls."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
public float RangeMultiplierInWalls
{
get;
set;
}
[Serialize(0.25f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f)]
[Serialize(0.25f, true, description: "The duration of an individual discharge (in seconds)."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f)]
public float Duration
{
get;
set;
}
[Serialize(false, true), Editable()]
[Serialize(false, true, "If set to true, the discharge cannot travel inside the submarine nor shock anyone inside."), Editable]
public bool OutdoorsOnly
{
get;
@@ -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; }
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
/// </summary>
Vector2 DrawSize { get; }
void Draw(SpriteBatch spriteBatch, bool editing);
void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1);
#endif
}
@@ -57,7 +57,7 @@ namespace Barotrauma.Items.Components
protected CoroutineHandle delayedCorrectionCoroutine;
protected float correctionTimer;
[Editable, Serialize(0.0f, false)]
[Editable, Serialize(0.0f, false, description: "How long it takes to pick up the item (in seconds).")]
public float PickingTime
{
get;
@@ -114,45 +114,42 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, false)] //Editable for doors to do their magic
[Editable, Serialize(false, false, description: "Can the item be picked up (or interacted with, if the pick action does something else than picking up the item).")] //Editable for doors to do their magic
public bool CanBePicked
{
get { return canBePicked; }
set { canBePicked = value; }
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the interface of the item (if it has one) be drawn when the item is equipped.")]
public bool DrawHudWhenEquipped
{
get;
private set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Can the item be selected by interacting with it.")]
public bool CanBeSelected
{
get { return canBeSelected; }
set { canBeSelected = value; }
}
//Transfer conditions between same prefab items
[Serialize(false, false)]
[Serialize(false, false, description: "Can the item be combined with other items of the same type.")]
public bool CanBeCombined
{
get { return canBeCombined; }
set { canBeCombined = value; }
}
//Remove item if combination results in 0 condition
[Serialize(false, false)]
[Serialize(false, false, description: "Should the item be removed if combining it with an other item causes the condition of this item to drop to 0.")]
public bool RemoveOnCombined
{
get { return removeOnCombined; }
set { removeOnCombined = value; }
}
//Can the "Use" action be triggered by characters or just other items/statuseffects
[Serialize(false, false)]
[Serialize(false, false, description: "Can the \"Use\" action of the item be triggered by characters or just other items/StatusEffects.")]
public bool CharacterUsable
{
get { return characterUsable; }
@@ -160,7 +157,7 @@ namespace Barotrauma.Items.Components
}
//Remove item if combination results in 0 condition
[Serialize(true, false), Editable(ToolTip = "Can the properties of the component be edited in-game (only applicable if the component has in-game editable properties).")]
[Serialize(true, false, description: "Can the properties of the component be edited in-game (only applicable if the component has in-game editable properties)."), Editable()]
public bool AllowInGameEditing
{
get;
@@ -179,7 +176,7 @@ namespace Barotrauma.Items.Components
protected set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the item be deleted when it's used.")]
public bool DeleteOnUse
{
get;
@@ -196,7 +193,7 @@ namespace Barotrauma.Items.Components
get { return name; }
}
[Editable, Serialize("", true, translationTextTag: "ItemMsg")]
[Editable, Serialize("", true, translationTextTag: "ItemMsg", description: "A text displayed next to the item when it's highlighted (generally instructs how to interact with the item, e.g. \"[Mouse1] Pick up\").")]
public string Msg
{
get;
@@ -213,7 +210,7 @@ namespace Barotrauma.Items.Components
/// <summary>
/// How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
/// </summary>
[Serialize(0f, false)]
[Serialize(0f, false, description: "How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).")]
public float CombatPriority { get; private set; }
public ItemComponent(Item item, XElement element)
@@ -400,7 +397,7 @@ namespace Barotrauma.Items.Components
}
}
public virtual bool Combine(Item item)
public virtual bool Combine(Item item, Character user)
{
if (canBeCombined && this.item.Prefab == item.Prefab && item.Condition > 0.0f && this.item.Condition > 0.0f)
{
@@ -670,9 +667,9 @@ namespace Barotrauma.Items.Components
}
}
public virtual void Load(XElement componentElement)
public virtual void Load(XElement componentElement, bool usePrefabValues)
{
if (componentElement == null) return;
if (componentElement == null || usePrefabValues) { return; }
foreach (XAttribute attribute in componentElement.Attributes())
{
if (!SerializableProperties.TryGetValue(attribute.Name.ToString().ToLowerInvariant(), out SerializableProperty property)) continue;
@@ -8,7 +8,6 @@ namespace Barotrauma.Items.Components
{
partial class ItemContainer : ItemComponent, IDrawableComponent
{
private List<RelatedItem> containableItems;
public ItemInventory Inventory;
private List<Pair<Item, StatusEffect>> itemsWithStatusEffects;
@@ -17,7 +16,7 @@ namespace Barotrauma.Items.Components
//how many items can be contained
private int capacity;
[Serialize(5, false)]
[Serialize(5, false, description: "How many items can be contained inside this item.")]
public int Capacity
{
get { return capacity; }
@@ -25,18 +24,19 @@ namespace Barotrauma.Items.Components
}
private bool hideItems;
[Serialize(true, false)]
[Serialize(true, false, description: "Should the items contained inside this item be hidden."
+ " If set to false, you should use the ItemPos and ItemInterval properties to determine where the items get rendered.")]
public bool HideItems
{
get { return hideItems; }
set
{
set
{
hideItems = value;
Drawable = !hideItems;
}
}
[Serialize(true, false)]
[Serialize(true, false, description: "Should the inventory of this item be visible when the item is selected.")]
public bool DrawInventory
{
get;
@@ -44,28 +44,23 @@ namespace Barotrauma.Items.Components
}
[Serialize(false, false)]
[Serialize(false, false, description: "If set to true, interacting with this item will make the character interact with the contained item(s), automatically picking them up if they can be picked up.")]
public bool AutoInteractWithContained
{
get;
set;
}
[Serialize("0.5,0.5", false)]
public Vector2 HudPos { get; set; }
[Serialize(5, false)]
[Serialize(5, false, description: "How many inventory slots the inventory has per row.")]
public int SlotsPerRow { get; set; }
public List<RelatedItem> ContainableItems
{
get { return containableItems; }
}
public List<RelatedItem> ContainableItems { get; private set; }
public ItemContainer(Item item, XElement element)
: base (item, element)
{
Inventory = new ItemInventory(item, this, capacity, HudPos, SlotsPerRow);
containableItems = new List<RelatedItem>();
Inventory = new ItemInventory(item, this, capacity, SlotsPerRow);
ContainableItems = new List<RelatedItem>();
foreach (XElement subElement in element.Elements())
{
@@ -78,7 +73,7 @@ namespace Barotrauma.Items.Components
DebugConsole.ThrowError("Error in item config \"" + item.ConfigFile + "\" - containable with no identifiers.");
continue;
}
containableItems.Add(containable);
ContainableItems.Add(containable);
break;
}
}
@@ -94,7 +89,7 @@ namespace Barotrauma.Items.Components
{
item.SetContainedItemPositions();
RelatedItem ri = containableItems.Find(x => x.MatchesItem(containedItem));
RelatedItem ri = ContainableItems.Find(x => x.MatchesItem(containedItem));
if (ri != null)
{
itemsWithStatusEffects.RemoveAll(i => i.First == containedItem);
@@ -118,8 +113,8 @@ namespace Barotrauma.Items.Components
public bool CanBeContained(Item item)
{
if (containableItems.Count == 0) return true;
return (containableItems.Find(x => x.MatchesItem(item)) != null);
if (ContainableItems.Count == 0) return true;
return (ContainableItems.Find(x => x.MatchesItem(item)) != null);
}
public override void Update(float deltaTime, Camera cam)
@@ -189,9 +184,10 @@ namespace Barotrauma.Items.Components
return (picker != null);
}
public override bool Combine(Item item)
public override bool Combine(Item item, Character user)
{
if (!containableItems.Any(x => x.MatchesItem(item))) return false;
if (!ContainableItems.Any(x => x.MatchesItem(item))) { return false; }
if (user != null && !user.CanAccessInventory(Inventory)) { return false; }
if (Inventory.TryPutItem(item, null))
{
@@ -286,20 +282,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);
string containedString = componentElement.GetAttributeString("contained", "");
string[] itemIdStrings = containedString.Split(',');
itemIds = new ushort[itemIdStrings.Length];
for (int i = 0; i < itemIdStrings.Length; i++)
{
ushort id = 0;
if (!ushort.TryParse(itemIdStrings[i], out id)) continue;
if (!ushort.TryParse(itemIdStrings[i], out ushort id)) { continue; }
itemIds[i] = id;
}
}
@@ -23,7 +23,7 @@ namespace Barotrauma.Items.Components
partial class Controller : ItemComponent, IServerSerializable
{
//where the limbs of the user should be positioned when using the controller
private List<LimbPos> limbPositions;
private readonly List<LimbPos> limbPositions;
private Direction dir;
@@ -51,7 +51,9 @@ namespace Barotrauma.Items.Components
get { return user; }
}
[Serialize(false, false), Editable(ToolTip = "When enabled, the item will continuously send out a 0/1 signal and interacting with it will flip the signal (making the item behave like a switch). When disabled, the item will simply send out 1 when interacted with.")]
public IEnumerable<LimbPos> LimbPositions { get { return limbPositions; } }
[Editable, Serialize(false, false, description: "When enabled, the item will continuously send out a 0/1 signal and interacting with it will flip the signal (making the item behave like a switch). When disabled, the item will simply send out 1 when interacted with.")]
public bool IsToggle
{
get;
@@ -146,7 +148,7 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, user);
if (limbPositions.Count == 0) return;
if (limbPositions.Count == 0) { return; }
user.AnimController.Anim = AnimController.Animation.UsingConstruction;
@@ -22,8 +22,8 @@ namespace Barotrauma.Items.Components
private float prevVoltage;
[Editable(0.0f, 10000000.0f, ToolTip = "The amount of force exerted on the submarine when the engine is operating at full power."),
Serialize(2000.0f, true)]
[Editable(0.0f, 10000000.0f),
Serialize(2000.0f, true, description: "The amount of force exerted on the submarine when the engine is operating at full power.")]
public float MaxForce
{
get { return maxForce; }
@@ -33,7 +33,9 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize("0.0,0.0", true)]
[Editable, Serialize("0.0,0.0", true,
description: "The position of the propeller as an offset from the item's center (in pixels)."+
" Determines where the particles spawn and the position that causes characters to take damage from the engine if the PropellerDamage is defined.")]
public Vector2 PropellerPos
{
get;
@@ -148,6 +150,16 @@ namespace Barotrauma.Items.Components
force = MathHelper.Lerp(force, 0.0f, 0.1f);
}
public override void FlipX(bool relativeToSub)
{
PropellerPos = new Vector2(-PropellerPos.X, PropellerPos.Y);
}
public override void FlipY(bool relativeToSub)
{
PropellerPos = new Vector2(PropellerPos.X, -PropellerPos.Y);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f, float signalStrength = 1.0f)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
@@ -22,23 +22,23 @@ namespace Barotrauma.Items.Components
private bool hasPower;
private Dictionary<Hull, HullData> hullDatas;
private readonly Dictionary<Hull, HullData> hullDatas;
[Editable(ToolTip = "Does the machine require inputs from water detectors in order to show the water levels inside rooms."), Serialize(false, true)]
[Editable, Serialize(false, true, description: "Does the machine require inputs from water detectors in order to show the water levels inside rooms.")]
public bool RequireWaterDetectors
{
get;
set;
}
[Editable(ToolTip = "Does the machine require inputs from oxygen detectors in order to show the oxygen levels inside rooms."), Serialize(true, true)]
[Editable, Serialize(true, true, description: "Does the machine require inputs from oxygen detectors in order to show the oxygen levels inside rooms.")]
public bool RequireOxygenDetectors
{
get;
set;
}
[Editable(ToolTip = "Should damaged walls be displayed by the machine."), Serialize(true, true)]
[Editable, Serialize(true, true, description: "Should damaged walls be displayed by the machine.")]
public bool ShowHullIntegrity
{
get;
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
private set;
}
[Editable(ToolTip = "How much oxygen the machine generates when operating at full power."), Serialize(400.0f, true)]
[Editable, Serialize(400.0f, true, description: "How much oxygen the machine generates when operating at full power.")]
public float GeneratedAmount
{
get { return generatedAmount; }
@@ -17,7 +17,7 @@ namespace Barotrauma.Items.Components
private bool hasPower;
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "How fast the item is currently pumping water (-100 = full speed out, 100 = full speed in). Intended to be used by StatusEffect conditionals (setting this value in XML has no effect).")]
public float FlowPercentage
{
get { return flowPercentage; }
@@ -29,7 +29,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(80.0f, false)]
[Serialize(80.0f, false, description: "How fast the item pumps water in/out when operating at 100%.")]
public float MaxFlow
{
get { return maxFlow; }
@@ -51,6 +51,8 @@ namespace Barotrauma.Items.Components
const float AIUpdateInterval = 0.2f;
private float aiUpdateTimer;
private Character lastAIUser;
private Character lastUser;
private Character LastUser
{
@@ -63,7 +65,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable(0.0f, float.MaxValue, ToolTip = "How much power (kW) the reactor generates when operating at full capacity."), Serialize(10000.0f, true)]
[Editable(0.0f, float.MaxValue), Serialize(10000.0f, true, description: "How much power (kW) the reactor generates when operating at full capacity.")]
public float MaxPowerOutput
{
get { return maxPowerOutput; }
@@ -73,21 +75,21 @@ namespace Barotrauma.Items.Components
}
}
[Editable(0.0f, float.MaxValue, ToolTip = "How long the temperature has to stay critical until a meltdown occurs."), Serialize(120.0f, true)]
[Editable(0.0f, float.MaxValue), Serialize(120.0f, true, description: "How long the temperature has to stay critical until a meltdown occurs.")]
public float MeltdownDelay
{
get { return meltDownDelay; }
set { meltDownDelay = Math.Max(value, 0.0f); }
}
[Editable(0.0f, float.MaxValue, ToolTip = "How long the temperature has to stay critical until the reactor catches fire."), Serialize(30.0f, true)]
[Editable(0.0f, float.MaxValue), Serialize(30.0f, true, description: "How long the temperature has to stay critical until the reactor catches fire.")]
public float FireDelay
{
get { return fireDelay; }
set { fireDelay = Math.Max(value, 0.0f); }
}
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "Current temperature of the reactor (0% - 100%). Indended to be used by StatusEffect conditionals.")]
public float Temperature
{
get { return temperature; }
@@ -98,7 +100,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "Current fission rate of the reactor (0% - 100%). Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float FissionRate
{
get { return fissionRate; }
@@ -109,7 +111,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "Current turbine output of the reactor (0% - 100%). Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float TurbineOutput
{
get { return turbineOutput; }
@@ -120,7 +122,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.2f, true), Editable(0.0f, 1000.0f, ToolTip = "How fast the condition of the contained fuel rods deteriorates.")]
[Serialize(0.2f, true, description: "How fast the condition of the contained fuel rods deteriorates per second."), Editable(0.0f, 1000.0f)]
public float FuelConsumptionRate
{
get { return fuelConsumptionRate; }
@@ -131,7 +133,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(false, true)]
[Serialize(false, true, description: "Is the temperature currently critical. Intended to be used by StatusEffect conditionals (setting the value from XML has no effect).")]
public bool TemperatureCritical
{
get { return temperature > allowedTemperature.Y; }
@@ -143,7 +145,7 @@ namespace Barotrauma.Items.Components
private float targetFissionRate;
private float targetTurbineOutput;
[Serialize(false, true)]
[Serialize(false, true, description: "Is the automatic temperature control currently on. Indended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public bool AutoTemp
{
get { return autoTemp; }
@@ -193,6 +195,18 @@ namespace Barotrauma.Items.Components
}
#endif
//if an AI character was using the item on the previous frame but not anymore, turn autotemp on
// (= bots turn autotemp back on when leaving the reactor)
if (lastAIUser != null)
{
if (lastAIUser.SelectedConstruction != item && lastAIUser.CanInteractWith(item))
{
AutoTemp = true;
unsentChanges = true;
lastAIUser = null;
}
}
prevAvailableFuel = AvailableFuel;
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
@@ -562,7 +576,7 @@ namespace Barotrauma.Items.Components
character.Speak(TextManager.Get("DialogReactorTaken"), null, 0.0f, "reactortaken", 10.0f);
}
LastUser = character;
LastUser = lastAIUser = character;
switch (objective.Option.ToLowerInvariant())
{
@@ -65,35 +65,37 @@ namespace Barotrauma.Items.Components
private bool useDirectionalPing = false;
private Vector2 pingDirection = new Vector2(1.0f, 0.0f);
private Sprite pingCircle, directionalPingCircle, screenOverlay, screenBackground;
private Sprite pingCircle, directionalPingCircle;
private Sprite screenOverlay, screenBackground;
private Sprite sonarBlip;
private Sprite lineSprite;
private bool aiPingCheckPending;
//the float value is a timer used for disconnecting the transducer if no signal is received from it for 1 second
private List<ConnectedTransducer> connectedTransducers;
private readonly List<ConnectedTransducer> connectedTransducers;
public IEnumerable<SonarTransducer> ConnectedTransducers
{
get { return connectedTransducers.Select(t => t.Transducer); }
}
[Serialize(DefaultSonarRange, false)]
[Serialize(DefaultSonarRange, false, description: "The maximum range of the sonar.")]
public float Range
{
get { return range; }
set { range = MathHelper.Clamp(value, 0.0f, 100000.0f); }
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the sonar display the walls of the submarine it is inside.")]
public bool DetectSubmarineWalls
{
get;
set;
}
[Serialize(false, false), Editable(ToolTip = "Does the sonar have to be connected to external transducers to work.")]
[Editable, Serialize(false, false, description: "Does the sonar have to be connected to external transducers to work.")]
public bool UseTransducers
{
get;
@@ -74,9 +74,10 @@ namespace Barotrauma.Items.Components
}
}
}
[Editable(0.0f, 1.0f, decimals: 3, ToolTip = "How full the ballast tanks should be when the submarine is not being steered upwards/downwards."
+" Can be used to compensate if the ballast tanks are too large/small relative to the size of the submarine."), Serialize(0.5f, true)]
[Editable(0.0f, 1.0f, decimals: 3),
Serialize(0.5f, true, description: "How full the ballast tanks should be when the submarine is not being steered upwards/downwards."
+ " Can be used to compensate if the ballast tanks are too large/small relative to the size of the submarine.")]
public float NeutralBallastLevel
{
get { return neutralBallastLevel; }
@@ -86,7 +87,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(1000.0f, true)]
[Serialize(1000.0f, true, description: "How close the docking port has to be to another docking port for the docking mode to become active.")]
public float DockingAssistThreshold
{
get;
@@ -521,98 +522,5 @@ namespace Barotrauma.Items.Components
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power, signalStrength);
}
}
public void ServerRead(ClientNetObject type, IReadMessage msg, Barotrauma.Networking.Client c)
{
bool autoPilot = msg.ReadBoolean();
bool dockingButtonClicked = msg.ReadBoolean();
Vector2 newSteeringInput = targetVelocity;
bool maintainPos = false;
Vector2? newPosToMaintain = null;
bool headingToStart = false;
if (autoPilot)
{
maintainPos = msg.ReadBoolean();
if (maintainPos)
{
newPosToMaintain = new Vector2(
msg.ReadSingle(),
msg.ReadSingle());
}
else
{
headingToStart = msg.ReadBoolean();
}
}
else
{
newSteeringInput = new Vector2(msg.ReadSingle(), msg.ReadSingle());
}
if (!item.CanClientAccess(c)) return;
user = c.Character;
AutoPilot = autoPilot;
if (dockingButtonClicked)
{
item.SendSignal(0, "1", "toggle_docking", sender: Character.Controlled);
}
if (!AutoPilot)
{
steeringInput = newSteeringInput;
steeringAdjustSpeed = MathHelper.Lerp(0.2f, 1.0f, c.Character.GetSkillLevel("helm") / 100.0f);
}
else
{
MaintainPos = newPosToMaintain != null;
posToMaintain = newPosToMaintain;
if (posToMaintain == null)
{
LevelStartSelected = headingToStart;
LevelEndSelected = !headingToStart;
UpdatePath();
}
else
{
LevelStartSelected = false;
LevelEndSelected = false;
}
}
//notify all clients of the changed state
unsentChanges = true;
}
public void ServerWrite(IWriteMessage msg, Barotrauma.Networking.Client c, object[] extraData = null)
{
msg.Write(autoPilot);
if (!autoPilot)
{
//no need to write steering info if autopilot is controlling
msg.Write(steeringInput.X);
msg.Write(steeringInput.Y);
msg.Write(targetVelocity.X);
msg.Write(targetVelocity.Y);
msg.Write(steeringAdjustSpeed);
}
else
{
msg.Write(posToMaintain != null);
if (posToMaintain != null)
{
msg.Write(((Vector2)posToMaintain).X);
msg.Write(((Vector2)posToMaintain).Y);
}
else
{
msg.Write(LevelStartSelected);
}
}
}
}
}
@@ -14,7 +14,7 @@ namespace Barotrauma.Items.Components
private float charge;
private float rechargeVoltage, outputVoltage;
private float rechargeVoltage;
//how fast the battery can be recharged
private float maxRechargeSpeed;
@@ -38,39 +38,38 @@ namespace Barotrauma.Items.Components
private set;
}
[Serialize("0,0", true)]
[Serialize("0,0", true, description: "The position of the progress bar indicating the charge of the item. In pixels as an offset from the upper left corner of the sprite.")]
public Vector2 IndicatorPosition
{
get { return indicatorPosition; }
set { indicatorPosition = value; }
}
[Serialize("0,0", true)]
[Serialize("0,0", true, description: "The size of the progress bar indicating the charge of the item (in pixels).")]
public Vector2 IndicatorSize
{
get { return indicatorSize; }
set { indicatorSize = value; }
}
[Serialize(false, true)]
[Serialize(false, true, description: "Should the progress bar indicating the charge of the item fill up horizontally or vertically.")]
public bool IsHorizontal
{
get { return isHorizontal; }
set { isHorizontal = value; }
}
[Editable(ToolTip = "Maximum output of the device when fully charged (kW)."), Serialize(10.0f, true)]
[Editable, Serialize(10.0f, true, description: "Maximum output of the device when fully charged (kW).")]
public float MaxOutPut { set; get; }
[Serialize(10.0f, true), Editable(ToolTip = "The maximum capacity of the device (kW * min). "+
"For example, a value of 1000 means the device can output 100 kilowatts of power for 10 minutes, or 1000 kilowatts for 1 minute.")]
[Editable, Serialize(10.0f, true, description: "The maximum capacity of the device (kW * min). For example, a value of 1000 means the device can output 100 kilowatts of power for 10 minutes, or 1000 kilowatts for 1 minute.")]
public float Capacity
{
get { return capacity; }
set { capacity = Math.Max(value, 1.0f); }
}
[Editable, Serialize(0.0f, true)]
[Editable, Serialize(0.0f, true, description: "The current charge of the device.")]
public float Charge
{
get { return charge; }
@@ -92,15 +91,14 @@ namespace Barotrauma.Items.Components
public float ChargePercentage => MathUtils.Percentage(Charge, Capacity);
[Serialize(10.0f, true), Editable(ToolTip = "How fast the device can be recharged. "+
"For example, a recharge speed of 100 kW and a capacity of 1000 kW*min would mean it takes 10 minutes to fully charge the device.")]
[Editable, Serialize(10.0f, true, description: "How fast the device can be recharged. For example, a recharge speed of 100 kW and a capacity of 1000 kW*min would mean it takes 10 minutes to fully charge the device.")]
public float MaxRechargeSpeed
{
get { return maxRechargeSpeed; }
set { maxRechargeSpeed = Math.Max(value, 1.0f); }
}
[Serialize(10.0f, true), Editable]
[Editable, Serialize(10.0f, true, description: "The current recharge speed of the device.")]
public float RechargeSpeed
{
get { return rechargeSpeed; }
@@ -223,7 +221,6 @@ namespace Barotrauma.Items.Components
}
rechargeVoltage = 0.0f;
outputVoltage = 0.0f;
}
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
@@ -241,7 +238,10 @@ namespace Barotrauma.Items.Components
#endif
RechargeSpeed = maxRechargeSpeed * aiRechargeTargetRatio;
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
}
#endif
character.Speak(TextManager.GetWithVariables("DialogChargeBatteries", new string[2] { "[itemname]", "[rate]" },
@@ -258,7 +258,10 @@ namespace Barotrauma.Items.Components
#endif
RechargeSpeed = 0.0f;
#if CLIENT
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = RechargeSpeed / Math.Max(maxRechargeSpeed, 1.0f);
}
#endif
character.Speak(TextManager.GetWithVariables("DialogStopChargingBatteries", new string[2] { "[itemname]", "[rate]" },
new string[2] { item.Name, ((int)(rechargeSpeed / maxRechargeSpeed * 100.0f)).ToString() },
@@ -280,7 +283,10 @@ namespace Barotrauma.Items.Components
float rechargeRate = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f);
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
rechargeSpeedSlider.BarScroll = rechargeRate;
if (rechargeSpeedSlider != null)
{
rechargeSpeedSlider.BarScroll = rechargeRate;
}
#endif
}
}
@@ -290,10 +296,6 @@ namespace Barotrauma.Items.Components
{
rechargeVoltage = Math.Min(power, 1.0f);
}
else
{
outputVoltage = power;
}
}
}
}
@@ -41,30 +41,30 @@ namespace Barotrauma.Items.Components
get { return powerLoad; }
}
[Serialize(true, true), Editable(ToolTip = "Can the item be damaged if too much power is supplied to the power grid.")]
[Editable, Serialize(true, true, description: "Can the item be damaged if too much power is supplied to the power grid.")]
public bool CanBeOverloaded
{
get;
set;
}
[Serialize(2.0f, true), Editable(MinValueFloat = 1.0f, ToolTip =
[Editable(MinValueFloat = 1.0f), Serialize(2.0f, true, description:
"How much power has to be supplied to the grid relative to the load before item starts taking damage. "
+"E.g. a value of 2 means that the grid has to be receiving twice as much power as the devices in the grid are consuming.")]
+ "E.g. a value of 2 means that the grid has to be receiving twice as much power as the devices in the grid are consuming.")]
public float OverloadVoltage
{
get;
set;
}
[Serialize(0.15f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f, ToolTip = "The probability for a fire to start when the item breaks.")]
[Serialize(0.15f, true, description: "The probability for a fire to start when the item breaks."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1.0f)]
public float FireProbability
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Is the item currently overloaded. Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public bool Overload
{
get;
@@ -22,8 +22,8 @@ namespace Barotrauma.Items.Components
//the maximum amount of power the item can draw from connected items
protected float powerConsumption;
[Serialize(0.5f, true), Editable(ToolTip = "The minimum voltage required for the device to function. "+
"The voltage is calculated as power / powerconsumption, meaning that a device "+
[Editable, Serialize(0.5f, true, description: "The minimum voltage required for the device to function. " +
"The voltage is calculated as power / powerconsumption, meaning that a device " +
"with a power consumption of 1000 kW would need at least 500 kW of power to work if the minimum voltage is set to 0.5.")]
public float MinVoltage
{
@@ -31,14 +31,14 @@ namespace Barotrauma.Items.Components
set { minVoltage = value; }
}
[Editable(ToolTip = "How much power the device draws (or attempts to draw) from the electrical grid."), Serialize(0.0f, true)]
[Editable, Serialize(0.0f, true, description: "How much power the device draws (or attempts to draw) from the electrical grid when active.")]
public float PowerConsumption
{
get { return powerConsumption; }
set { powerConsumption = value; }
}
[Serialize(false, true)]
[Serialize(false, true, description: "Is the device currently active. Inactive devices don't consume power.")]
public override bool IsActive
{
get { return base.IsActive; }
@@ -52,21 +52,21 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "The current power consumption of the device. Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float CurrPowerConsumption
{
get {return currPowerConsumption; }
set { currPowerConsumption = value; }
}
[Serialize(0.0f, true)]
[Serialize(0.0f, true, description: "The current voltage of the item (calculated as power consumption / available power). Intended to be used by StatusEffect conditionals (setting the value from XML is not recommended).")]
public float Voltage
{
get { return voltage; }
set { voltage = Math.Max(0.0f, value); }
}
[Editable(ToolTip = "Can the item be damaged by electomagnetic pulses."), Serialize(true, true)]
[Editable, Serialize(true, true, description: "Can the item be damaged by electomagnetic pulses.")]
public bool VulnerableToEMP
{
get;
@@ -57,14 +57,14 @@ namespace Barotrauma.Items.Components
private float persistentStickJointTimer;
[Serialize(10.0f, false)]
[Serialize(10.0f, false, description: "The impulse applied to the physics body of the item when it's launched. Higher values make the projectile faster.")]
public float LaunchImpulse
{
get { return launchImpulse; }
set { launchImpulse = value; }
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "The rotation of the item relative to the rotation of the weapon when launched (in degrees).")]
public float LaunchRotation
{
get { return MathHelper.ToDegrees(LaunchRotationRadians); }
@@ -77,7 +77,7 @@ namespace Barotrauma.Items.Components
private set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "When set to true, the item can stick to any target it hits.")]
//backwards compatibility, can stick to anything
public bool DoesStick
{
@@ -85,49 +85,52 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Can the item stick to the character it hits.")]
public bool StickToCharacters
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Can the item stick to the structure it hits.")]
public bool StickToStructures
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Can the item stick to the item it hits.")]
public bool StickToItems
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Hitscan projectiles cast a ray forwards and immediately hit whatever the ray hits. "+
"It is recommended to use hitscans for very fast-moving projectiles such as bullets, because using extremely fast launch velocities may cause physics glitches.")]
public bool Hitscan
{
get;
set;
}
[Serialize(1, false)]
[Serialize(1, false, description: "How many hitscans should be done when the projectile is launched. "
+ "Multiple hitscans can be used to simulate weapons that fire multiple projectiles at the same time" +
" without having to actually use multiple projectile items, for example shotguns.")]
public int HitScanCount
{
get;
set;
}
[Serialize(false, false)]
[Serialize(false, false, description: "Should the item be deleted when it hits something.")]
public bool RemoveOnHit
{
get;
set;
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "Random spread applied to the launch angle of the projectile (in degrees).")]
public float Spread
{
get;
@@ -21,64 +21,63 @@ namespace Barotrauma.Items.Components
public float LastActiveTime;
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, DecimalCount = 2, ToolTip = "How fast the condition of the item deteriorates per second.")]
[Serialize(0.0f, true, description: "How fast the condition of the item deteriorates per second."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, DecimalCount = 2)]
public float DeteriorationSpeed
{
get;
set;
}
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2, ToolTip = "Minimum initial delay before the item starts to deteriorate.")]
[Serialize(0.0f, true, description: "Minimum initial delay before the item starts to deteriorate."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
public float MinDeteriorationDelay
{
get;
set;
}
[Serialize(0.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2, ToolTip = "Maximum initial delay before the item starts to deteriorate.")]
[Serialize(0.0f, true, description: "Maximum initial delay before the item starts to deteriorate."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f, DecimalCount = 2)]
public float MaxDeteriorationDelay
{
get;
set;
}
[Serialize(50.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The item won't deteriorate spontaneously if the condition is below this value. For example, if set to 10, the condition will spontaneously drop to 10 and then stop dropping (unless the item is damaged further by external factors). Percentages of max condition.")]
[Serialize(50.0f, true, description: "The item won't deteriorate spontaneously if the condition is below this value. For example, if set to 10, the condition will spontaneously drop to 10 and then stop dropping (unless the item is damaged further by external factors). Percentages of max condition."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
public float MinDeteriorationCondition
{
get;
set;
}
[Serialize(0f, true)]
[Serialize(0f, true, description: "How low a traitor must get the item's condition for it to start breaking down.")]
public float MinSabotageCondition
{
get;
set;
}
[Serialize(80.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The condition of the item has to be below this before the repair UI becomes usable. Percentages of max condition.")]
[Serialize(80.0f, true, description: "The condition of the item has to be below this before the repair UI becomes usable. Percentages of max condition."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
public float ShowRepairUIThreshold
{
get;
set;
}
[Serialize(100.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with insufficient skill levels.")]
[Serialize(100.0f, true, description: "The amount of time it takes to fix the item with insufficient skill levels."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
public float FixDurationLowSkill
{
get;
set;
}
[Serialize(10.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The amount of time it takes to fix the item with sufficient skill levels.")]
[Serialize(10.0f, true, description: "The amount of time it takes to fix the item with sufficient skill levels."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f)]
public float FixDurationHighSkill
{
get;
set;
}
//if enabled, the deterioration timer will always run regardless if the item is being used or not
[Serialize(false, false)]
[Serialize(false, false, description: "If set to true, the deterioration timer will always run regardless if the item is being used or not.")]
public bool DeteriorateAlways
{
get;
@@ -199,7 +198,7 @@ namespace Barotrauma.Items.Components
{
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient)
{
deteriorationTimer -= deltaTime;
deteriorationTimer -= deltaTime * GetDeteriorationDelayMultiplier();
#if SERVER
if (deteriorationTimer <= 0.0f) { item.CreateServerEvent(this); }
#endif
@@ -336,7 +335,7 @@ namespace Barotrauma.Items.Components
else if (ic is Pump pump)
{
//pumps don't deteriorate if they're not running
if (Math.Abs(pump.FlowPercentage) > 1.0f) { return true; }
if (Math.Abs(pump.FlowPercentage) > 1.0f && pump.IsActive) { return true; }
}
else if (ic is Reactor reactor)
{
@@ -357,6 +356,26 @@ namespace Barotrauma.Items.Components
return DeteriorateAlways;
}
private float GetDeteriorationDelayMultiplier()
{
foreach (ItemComponent ic in item.Components)
{
if (ic is Engine engine)
{
return Math.Abs(engine.Force) / 100.0f;
}
else if (ic is Pump pump)
{
return Math.Abs(pump.FlowPercentage) / 100.0f;
}
else if (ic is Reactor reactor)
{
return (reactor.FissionRate + reactor.TurbineOutput) / 200.0f;
}
}
return 1.0f;
}
private void UpdateFixAnimation(Character character)
{
character.AnimController.UpdateUseItem(false, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((item.Condition / item.MaxCondition) % 0.1f));
@@ -173,7 +173,7 @@ namespace Barotrauma.Items.Components
if (i == ropeBodies.Length - 2)
{
item.Combine(projectile);
item.Combine(projectile, user: null);
ropeBodies[ropeBodies.Length - 1].Enabled = false;
IsActive = false;
}
@@ -221,7 +221,7 @@ namespace Barotrauma.Items.Components
{
//attempt to recontain the projectile in the launcher
//eq automatically reload a spear into a speargun when picking the spear up
if (!projectile.body.Enabled) item.Combine(projectile);
if (!projectile.body.Enabled) item.Combine(projectile, user: null);
foreach (PhysicsBody b in ropeBodies)
{
@@ -11,25 +11,29 @@ namespace Barotrauma.Items.Components
protected float[] timeSinceReceived;
protected float[] receivedSignal;
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
[InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f), Serialize(999999.0f, true)]
[Serialize(999999.0f, true, description: "The output of the item is restricted below this value."),
InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f)]
public float ClampMax
{
get;
set;
}
[InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f), Serialize(-999999.0f, true)]
[Serialize(-999999.0f, true, description: "The output of the item is restricted above this value."),
InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f)]
public float ClampMin
{
get;
set;
}
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true)]
[InGameEditable(DecimalCount = 2),
Serialize(0.0f, true, description: "The item must have received signals to both inputs within this timeframe to output the sum of the signals." +
" If set to 0, the inputs must be received at the same time.")]
public float TimeFrame
{
get { return timeFrame; }
@@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true)]
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true, description: "The item sends the output if both inputs have received a non-zero signal within the timeframe. If set to 0, the inputs must receive a signal at the same time.")]
public float TimeFrame
{
get { return timeFrame; }
@@ -23,14 +23,14 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("1", true)]
[InGameEditable, Serialize("1", true, description: "The signal sent when both inputs have received a non-zero signal.")]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("", true)]
[InGameEditable, Serialize("", true, description: "The signal sent when both inputs have not received a non-zero signal (if empty, no signal is sent).")]
public string FalseOutput
{
get { return falseOutput; }
@@ -21,7 +21,7 @@ namespace Barotrauma.Items.Components
private List<ushort> disconnectedWireIds;
[Serialize(false, true), Editable(ToolTip = "Locked connection panels cannot be rewired in-game.")]
[Editable, Serialize(false, true, description: "Locked connection panels cannot be rewired in-game.")]
public bool Locked
{
get;
@@ -171,9 +171,9 @@ namespace Barotrauma.Items.Components
return true;
}
public override void Load(XElement element)
public override void Load(XElement element, bool usePrefabValues)
{
base.Load(element);
base.Load(element, usePrefabValues);
List<Connection> loadedConnections = new List<Connection>();
@@ -12,9 +12,9 @@ namespace Barotrauma.Items.Components
public bool ContinuousSignal;
public bool State;
public string Connection;
[Serialize("", false, translationTextTag = "Label.")]
[Serialize("", false, translationTextTag: "Label.", description: "The text displayed on this button/tickbox."), Editable]
public string Label { get; set; }
[Serialize("1", false)]
[Serialize("1", false, description: "The signal sent out when this button is pressed or this tickbox checked."), Editable]
public string Signal { get; set; }
public string Name => "CustomInterfaceElement";
@@ -40,7 +40,7 @@ namespace Barotrauma.Items.Components
}
private string[] labels;
[Serialize("", true)]
[Serialize("", true, description: "The texts displayed on the buttons/tickboxes, separated by commas.")]
public string Labels
{
get { return string.Join(",", labels); }
@@ -55,7 +55,7 @@ namespace Barotrauma.Items.Components
}
}
private string[] signals;
[Serialize("", true)]
[Serialize("", true, description: "The signals sent when the buttons are pressed or the tickboxes checked, separated by commas.")]
public string Signals
{
//use semicolon as a separator because comma may be needed in the signals (for color or vector values for example)
@@ -9,9 +9,12 @@ namespace Barotrauma.Items.Components
{
public readonly string Signal;
public readonly float SignalStrength;
public float SendTimer;
//in number of frames
public int SendTimer;
//in number of frames
public int SendDuration;
public DelayedSignal(string signal, float signalStrength, float sendTimer)
public DelayedSignal(string signal, float signalStrength, int sendTimer)
{
Signal = signal;
SignalStrength = signalStrength;
@@ -19,25 +22,35 @@ namespace Barotrauma.Items.Components
}
}
const int SignalQueueSize = 500;
private int signalQueueSize;
private int delayTicks;
private Queue<DelayedSignal> signalQueue;
private DelayedSignal prevQueuedSignal;
[InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f, DecimalCount = 2), Serialize(1.0f, true)]
private float delay;
[InGameEditable(MinValueFloat = 0.0f, MaxValueFloat = 60.0f, DecimalCount = 2), Serialize(1.0f, true, description: "How long the item delays the signals (in seconds).")]
public float Delay
{
get;
set;
get { return delay; }
set
{
if (value == delay) { return; }
delay = value;
delayTicks = (int)(delay / Timing.Step);
signalQueueSize = delayTicks * 2;
}
}
[InGameEditable(ToolTip = "Should the component discard previously received signals when a new one is received."), Serialize(false, true)]
[InGameEditable, Serialize(false, true, description: "Should the component discard previously received signals when a new one is received.")]
public bool ResetWhenSignalReceived
{
get;
set;
}
[InGameEditable(ToolTip = "Should the component discard previously received signals when the incoming signal changes."), Serialize(false, true)]
[InGameEditable, Serialize(false, true, description: "Should the component discard previously received signals when the incoming signal changes.")]
public bool ResetWhenDifferentSignalReceived
{
get;
@@ -55,13 +68,15 @@ namespace Barotrauma.Items.Components
{
foreach (var val in signalQueue)
{
val.SendTimer -= deltaTime;
val.SendTimer -= 1;
}
while (signalQueue.Count > 0 && signalQueue.Peek().SendTimer <= 0.0f)
while (signalQueue.Count > 0 && signalQueue.Peek().SendTimer <= 0)
{
var signalOut = signalQueue.Dequeue();
var signalOut = signalQueue.Peek();
signalOut.SendDuration -= 1;
item.SendSignal(0, signalOut.Signal, "signal_out", null, signalStrength: signalOut.SignalStrength);
if (signalOut.SendDuration <= 0) { signalQueue.Dequeue(); } else { break; }
}
}
@@ -70,13 +85,28 @@ namespace Barotrauma.Items.Components
switch (connection.Name)
{
case "signal_in":
if (signalQueue.Count >= SignalQueueSize) return;
if (ResetWhenSignalReceived) signalQueue.Clear();
if (signalQueue.Count >= signalQueueSize) { return; }
if (ResetWhenSignalReceived) { prevQueuedSignal = null; signalQueue.Clear(); }
if (ResetWhenDifferentSignalReceived && signalQueue.Count > 0 && signalQueue.Peek().Signal != signal)
{
prevQueuedSignal = null;
signalQueue.Clear();
}
signalQueue.Enqueue(new DelayedSignal(signal, signalStrength, Delay));
if (prevQueuedSignal != null &&
prevQueuedSignal.Signal == signal &&
MathUtils.NearlyEqual(prevQueuedSignal.SignalStrength, signalStrength) &&
((prevQueuedSignal.SendTimer + prevQueuedSignal.SendDuration == delayTicks) || (prevQueuedSignal.SendTimer <= 0 && prevQueuedSignal.SendDuration > 0)))
{
prevQueuedSignal.SendDuration += 1;
return;
}
prevQueuedSignal = new DelayedSignal(signal, signalStrength, delayTicks)
{
SendDuration = 1
};
signalQueue.Enqueue(prevQueuedSignal);
break;
}
}
@@ -15,21 +15,21 @@ namespace Barotrauma.Items.Components
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
[InGameEditable, Serialize("1", true)]
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signals are equal.")]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("", true)]
[InGameEditable, Serialize("", true, description: "The signal this item outputs when the received signals are not equal.")]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true)]
[InGameEditable(DecimalCount = 2), Serialize(0.0f, true, description: "The maximum amount of time between the received signals. If set to 0, the signals must be received at the same time.")]
public float TimeFrame
{
get { return timeFrame; }
@@ -25,7 +25,8 @@ namespace Barotrauma.Items.Components
public PhysicsBody ParentBody;
[Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f), Serialize(100.0f, true)]
[Serialize(100.0f, true, description: "The range of the emitted light. Higher values are more performance-intensive."),
Editable(MinValueFloat = 0.0f, MaxValueFloat = 2048.0f)]
public float Range
{
get { return range; }
@@ -40,8 +41,8 @@ namespace Barotrauma.Items.Components
public float Rotation;
[Editable(ToolTip = "Should structures cast shadows when light from this light source hits them. "+
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range."), Serialize(true, true)]
[Editable, Serialize(true, true, description: "Should structures cast shadows when light from this light source hits them. " +
"Disabling shadows increases the performance of the game, and is recommended for lights with a short range.")]
public bool CastShadows
{
get { return castShadows; }
@@ -54,8 +55,8 @@ namespace Barotrauma.Items.Components
}
}
[Editable(ToolTip = "Lights drawn behind submarines don't cast any shadows and are much faster to draw than shadow-casting lights. "+
"It's recommended to enable this on decorative lights outside the submarine's hull."), Serialize(false, true)]
[Editable, Serialize(false, true, description: "Lights drawn behind submarines don't cast any shadows and are much faster to draw than shadow-casting lights. " +
"It's recommended to enable this on decorative lights outside the submarine's hull.")]
public bool DrawBehindSubs
{
get { return drawBehindSubs; }
@@ -68,7 +69,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true)]
[Editable, Serialize(false, true, description: "Is the light currently on.")]
public bool IsOn
{
get { return IsActive; }
@@ -83,7 +84,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "How heavily the light flickers. 0 = no flickering, 1 = the light will alternate between completely dark and full brightness.")]
public float Flicker
{
get { return flicker; }
@@ -93,7 +94,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(0.0f, true)]
[Editable, Serialize(0.0f, true, description: "How rapidly the light blinks on and off (in Hz). 0 = no blinking.")]
public float BlinkFrequency
{
get { return blinkFrequency; }
@@ -103,7 +104,7 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("1.0,1.0,1.0,1.0", true)]
[InGameEditable, Serialize("255,255,255,255", true, description: "The color of the emitted light (R,G,B,A).")]
public Color LightColor
{
get { return lightColor; }
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
{
class MemoryComponent : ItemComponent
{
[InGameEditable, Serialize("", true)]
[InGameEditable, Serialize("", true, description: "The currently stored signal the item outputs.")]
public string Value
{
get;
@@ -9,32 +9,23 @@ namespace Barotrauma.Items.Components
partial class MotionSensor : ItemComponent
{
private const float UpdateInterval = 0.1f;
private string output, falseOutput;
private bool motionDetected;
private float rangeX, rangeY;
private Vector2 detectOffset;
private float updateTimer;
[Serialize(false, false)]
public bool MotionDetected
{
get { return motionDetected; }
set { motionDetected = value; }
}
[Serialize(false, false, description: "Has the item currently detected movement. Intended to be used by StatusEffect conditionals (setting this value in XML has no effect).")]
public bool MotionDetected { get; set; }
[Serialize(false, true), Editable]
[Editable, Serialize(false, true, description: "Should the sensor only detect the movement of humans?")]
public bool OnlyHumans
{
get;
set;
}
[InGameEditable, Serialize(0.0f, true)]
[InGameEditable, Serialize(0.0f, true, description: "Horizontal detection range.")]
public float RangeX
{
get { return rangeX; }
@@ -43,7 +34,7 @@ namespace Barotrauma.Items.Components
rangeX = MathHelper.Clamp(value, 0.0f, 1000.0f);
}
}
[InGameEditable, Serialize(0.0f, true)]
[InGameEditable, Serialize(0.0f, true, description: "Vertical movement detection range.")]
public float RangeY
{
get { return rangeY; }
@@ -53,7 +44,7 @@ namespace Barotrauma.Items.Components
}
}
[Serialize("0,0", true), Editable(ToolTip = "The position to detect the movement at relative to the item. For example, 0,100 would detect movement 100 units above the item.")]
[Editable, Serialize("0,0", true, description: "The position to detect the movement at relative to the item. For example, 0,100 would detect movement 100 units above the item.")]
public Vector2 DetectOffset
{
get { return detectOffset; }
@@ -65,21 +56,13 @@ namespace Barotrauma.Items.Components
}
}
[InGameEditable, Serialize("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("1", true, description: "The signal the item outputs when it has detected movement.")]
public string Output { get; set; }
[InGameEditable, Serialize("", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[InGameEditable, Serialize("", true, description: "The signal the item outputs when it has not detected movement.")]
public string FalseOutput { get; set; }
[Editable(ToolTip = "How fast the objects within the detector's range have to be moving (in m/s).", DecimalCount = 3), Serialize(0.01f, true)]
[Editable(DecimalCount = 3), Serialize(0.01f, true, description: "How fast the objects within the detector's range have to be moving (in m/s).")]
public float MinimumVelocity
{
get;
@@ -88,7 +71,7 @@ namespace Barotrauma.Items.Components
public MotionSensor(Item item, XElement element)
: base (item, element)
: base(item, element)
{
IsActive = true;
@@ -101,21 +84,21 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
string signalOut = motionDetected ? output : falseOutput;
string signalOut = MotionDetected ? Output : FalseOutput;
if (!string.IsNullOrEmpty(signalOut)) item.SendSignal(1, signalOut, "state_out", null);
updateTimer -= deltaTime;
if (updateTimer > 0.0f) return;
motionDetected = false;
MotionDetected = false;
updateTimer = UpdateInterval;
if (item.body != null && item.body.Enabled)
{
if (Math.Abs(item.body.LinearVelocity.X) > MinimumVelocity || Math.Abs(item.body.LinearVelocity.Y) > MinimumVelocity)
{
motionDetected = true;
MotionDetected = true;
}
}
@@ -126,7 +109,7 @@ namespace Barotrauma.Items.Components
foreach (Character c in Character.CharacterList)
{
if (OnlyHumans && c.ConfigPath != Character.HumanConfigFile) { continue; }
if (OnlyHumans && !c.IsHuman) { continue; }
//do a rough check based on the position of the character's collider first
//before the more accurate limb-based check
@@ -140,11 +123,20 @@ namespace Barotrauma.Items.Components
if (limb.LinearVelocity.LengthSquared() <= MinimumVelocity * MinimumVelocity) continue;
if (MathUtils.CircleIntersectsRectangle(limb.WorldPosition, ConvertUnits.ToDisplayUnits(limb.body.GetMaxExtent()), detectRect))
{
motionDetected = true;
MotionDetected = true;
break;
}
}
}
}
public override void FlipX(bool relativeToSub)
{
detectOffset.X = -detectOffset.X;
}
public override void FlipY(bool relativeToSub)
{
detectOffset.Y = -detectOffset.Y;
}
}
}
@@ -20,14 +20,17 @@ namespace Barotrauma.Items.Components
private float phase;
[InGameEditable, Serialize(WaveType.Pulse, true)]
[InGameEditable, Serialize(WaveType.Pulse, true, description: "What kind of a signal the item outputs." +
" Pulse: periodically sends out a signal of 1." +
" Sine: sends out a sine wave oscillating between -1 and 1." +
" Square: sends out a signal that alternates between 0 and 1.")]
public WaveType OutputType
{
get;
set;
}
[InGameEditable(DecimalCount = 2), Serialize(1.0f, true)]
[InGameEditable(DecimalCount = 2), Serialize(1.0f, true, description: "How fast the signal oscillates, or how fast the pulses are sent (in Hz).")]
public float Frequency
{
get { return frequency; }
@@ -16,16 +16,16 @@ namespace Barotrauma.Items.Components
private bool nonContinuousOutputSent;
[InGameEditable, Serialize("1", true)]
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the regular expression.")]
public string Output { get; set; }
[InGameEditable, Serialize("0", true)]
[Serialize("0", true, description: "The signal this item outputs when the received signal does not match the regular expression.")]
public string FalseOutput { get; set; }
[Serialize(true, true), InGameEditable(ToolTip = "Should the component keep sending the output even after it stops receiving a signal, or only send an output when it receives a signal.")]
[InGameEditable, Serialize(true, true, description: "Should the component keep sending the output even after it stops receiving a signal, or only send an output when it receives a signal.")]
public bool ContinuousOutput { get; set; }
[InGameEditable, Serialize("", true)]
[InGameEditable, Serialize("", true, description: "The regular expression used to check the incoming signals.")]
public string Expression
{
get { return expression; }
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
{ "signal_in5", "signal_out5" }
};
[Editable, Serialize(1000.0f, true)]
[Editable, Serialize(1000.0f, true, description: "The maximum amount of power that can pass through the item.")]
public float MaxPower
{
get { return maxPower; }
@@ -32,7 +32,7 @@ namespace Barotrauma.Items.Components
}
}
[Editable, Serialize(false, true)]
[Editable, Serialize(false, true, description: "Can the relay currently pass power and signals through it.")]
public bool IsOn
{
get
@@ -4,29 +4,13 @@ namespace Barotrauma.Items.Components
{
class SignalCheckComponent : ItemComponent
{
private string output, falseOutput;
[InGameEditable, Serialize("1", true, description: "The signal this item outputs when the received signal matches the target signal.")]
public string Output { get; set; }
[InGameEditable, Serialize("0", true, description: "The signal this item outputs when the received signal does not match the target signal.")]
public string FalseOutput { get; set; }
private string targetSignal;
[InGameEditable, Serialize("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("0", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[InGameEditable, Serialize("", true)]
public string TargetSignal
{
get { return targetSignal; }
set { targetSignal = value; }
}
[InGameEditable, Serialize("", true, description: "The value to compare the received signals against.")]
public string TargetSignal { get; set; }
public SignalCheckComponent(Item item, XElement element)
: base(item, element)
@@ -38,17 +22,17 @@ namespace Barotrauma.Items.Components
switch (connection.Name)
{
case "signal_in":
string signalOut = (signal == targetSignal) ? output : falseOutput;
string signalOut = (signal == TargetSignal) ? Output : FalseOutput;
if (string.IsNullOrWhiteSpace(signalOut)) return;
item.SendSignal(stepsTaken, signalOut, "signal_out", sender, signalStrength);
break;
case "set_output":
output = signal;
Output = signal;
break;
case "set_targetsignal":
targetSignal = signal;
TargetSignal = signal;
break;
}
}
@@ -5,7 +5,7 @@ namespace Barotrauma.Items.Components
{
class SmokeDetector : ItemComponent
{
[Serialize(50.0f, false)]
[Serialize(50.0f, false, description: "How large the fire has to be for the detector to react to it.")]
public float FireSizeThreshold
{
get; set;
@@ -4,27 +4,17 @@ namespace Barotrauma.Items.Components
{
class WaterDetector : ItemComponent
{
private string output, falseOutput;
//how often the detector can switch from state to another
const float StateSwitchInterval = 1.0f;
private bool isInWater;
private float stateSwitchDelay;
[InGameEditable, Serialize("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, Serialize("1", true, description: "The signal the item sends out when it's underwater.")]
public string Output { get; set; }
[InGameEditable, Serialize("0", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[InGameEditable, Serialize("0", true, description: "The signal the item sends out when it's not underwater.")]
public string FalseOutput { get; set; }
public WaterDetector(Item item, XElement element)
: base(item, element)
@@ -64,7 +54,7 @@ namespace Barotrauma.Items.Components
}
}
string signalOut = isInWater ? output : falseOutput;
string signalOut = isInWater ? Output : FalseOutput;
if (!string.IsNullOrEmpty(signalOut))
{
item.SendSignal(0, signalOut, "signal_out", null);
@@ -19,17 +19,17 @@ namespace Barotrauma.Items.Components
private string prevSignal;
[Serialize(Character.TeamType.None, false)]
[Serialize(Character.TeamType.None, false, description: "WiFi components can only communicate with components that have the same Team ID.")]
public Character.TeamType TeamID { get; set; }
[Serialize(20000.0f, false)]
[Serialize(20000.0f, false, description: "How close the recipient has to be to receive a signal from this WiFi component.")]
public float Range
{
get { return range; }
set { range = Math.Max(value, 0.0f); }
}
[InGameEditable, Serialize(1, true)]
[InGameEditable, Serialize(1, true, description: "WiFi components can only communicate with components that use the same channel.")]
public int Channel
{
get { return channel; }
@@ -39,25 +39,24 @@ namespace Barotrauma.Items.Components
}
}
[Editable(ToolTip =
"If enabled, any signals received from another chat-linked wifi component are displayed "+
"as chat messages in the chatbox of the player holding the item."), Serialize(false, false)]
[Editable, Serialize(false, false, description: "If enabled, any signals received from another chat-linked wifi component are displayed " +
"as chat messages in the chatbox of the player holding the item.")]
public bool LinkToChat
{
get;
set;
}
[Editable(ToolTip = "How many seconds have to pass between signals for a message to be displayed in the chatbox. "+
"Setting this to a very low value is not recommended, because it may cause an excessive amount of chat messages to be created "+
"if there are chat-linked wifi components that transmit a continuous signal."), Serialize(1.0f, true)]
[Editable, Serialize(1.0f, true, description: "How many seconds have to pass between signals for a message to be displayed in the chatbox. " +
"Setting this to a very low value is not recommended, because it may cause an excessive amount of chat messages to be created " +
"if there are chat-linked wifi components that transmit a continuous signal.")]
public float MinChatMessageInterval
{
get;
set;
}
[Editable(ToolTip = "If set to true, the component will only create chat messages when the received signal changes."), Serialize(false, true)]
[Editable, Serialize(false, true, description: "If set to true, the component will only create chat messages when the received signal changes.")]
public bool DiscardDuplicateChatMessages
{
get;
@@ -55,6 +55,8 @@ namespace Barotrauma.Items.Components
public bool Hidden;
private float removeNodeDelay;
private bool locked;
public bool Locked
{
@@ -71,7 +73,7 @@ namespace Barotrauma.Items.Components
get { return connections; }
}
[Serialize(5000.0f, false)]
[Serialize(5000.0f, false, description: "The maximum distance the wire can extend (in pixels).")]
public float MaxLength
{
get;
@@ -255,17 +257,18 @@ namespace Barotrauma.Items.Components
public override void Drop(Character dropper)
{
ClearConnections(dropper);
ClearConnections(dropper);
IsActive = false;
}
public override void Update(float deltaTime, Camera cam)
{
if (nodes.Count == 0) return;
removeNodeDelay -= deltaTime;
if (nodes.Count == 0) { return; }
Submarine sub = null;
if (connections[0] != null && connections[0].Item.Submarine != null) sub = connections[0].Item.Submarine;
if (connections[1] != null && connections[1].Item.Submarine != null) sub = connections[1].Item.Submarine;
if (connections[0] != null && connections[0].Item.Submarine != null) { sub = connections[0].Item.Submarine; }
if (connections[1] != null && connections[1].Item.Submarine != null) { sub = connections[1].Item.Submarine; }
if (Screen.Selected != GameMain.SubEditorScreen)
{
@@ -354,10 +357,12 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (character == null) return false;
#if CLIENT
if (character == Character.Controlled && character.SelectedConstruction != null) return false;
#endif
if (character == null) { return false; }
if (character == Character.Controlled && character.SelectedConstruction != null) { return false; }
if (Screen.Selected == GameMain.SubEditorScreen && !PlayerInput.LeftButtonClicked())
{
return false;
}
if (newNodePos != Vector2.Zero && canPlaceNode && nodes.Count > 0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
{
@@ -384,11 +389,12 @@ namespace Barotrauma.Items.Components
public override bool SecondaryUse(float deltaTime, Character character = null)
{
if (nodes.Count > 1)
if (nodes.Count > 1 && removeNodeDelay <= 0.0f)
{
nodes.RemoveAt(nodes.Count - 1);
UpdateSections();
}
removeNodeDelay = 0.1f;
Drawable = IsActive || sections.Count > 0;
return true;
@@ -668,9 +674,9 @@ namespace Barotrauma.Items.Components
UpdateSections();
}
public override void Load(XElement componentElement)
public override void Load(XElement componentElement, bool usePrefabValues)
{
base.Load(componentElement);
base.Load(componentElement, usePrefabValues);
string nodeString = componentElement.GetAttributeString("nodes", "");
if (nodeString == "") return;
@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
private Character user;
[Serialize("0,0", false)]
[Serialize("0,0", false, description: "The position of the barrel relative to the upper left corner of the base sprite (in pixels).")]
public Vector2 BarrelPos
{
get
@@ -57,21 +57,21 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false, description: "The impulse applied to the physics body of the projectile (the higher the impulse, the faster the projectiles are launched).")]
public float LaunchImpulse
{
get { return launchImpulse; }
set { launchImpulse = value; }
}
[Serialize(5.0f, false), Editable(0.0f, 1000.0f)]
[Editable(0.0f, 1000.0f), Serialize(5.0f, false, description: "The period of time the user has to wait between shots.")]
public float Reload
{
get { return reloadTime; }
set { reloadTime = value; }
}
[Serialize("0.0,0.0", true), Editable]
[Editable, Serialize("0.0,0.0", true, description: "The range at which the barrel can rotate. TODO")]
public Vector2 RotationLimits
{
get
@@ -94,39 +94,49 @@ namespace Barotrauma.Items.Components
}
}
[Serialize(5.0f, false), Editable(0.0f, 1000.0f, DecimalCount = 2)]
[Editable(0.0f, 1000.0f, DecimalCount = 2),
Serialize(5.0f, false, description: "How much torque is applied to rotate the barrel when the item is used by a character"
+ " with insufficient skills to operate it. Higher values make the barrel rotate faster.")]
public float SpringStiffnessLowSkill
{
get;
private set;
}
[Serialize(2.0f, false), Editable(0.0f, 1000.0f, DecimalCount = 2)]
[Editable(0.0f, 1000.0f, DecimalCount = 2),
Serialize(2.0f, false, description: "How much torque is applied to rotate the barrel when the item is used by a character"
+ " with sufficient skills to operate it. Higher values make the barrel rotate faster.")]
public float SpringStiffnessHighSkill
{
get;
private set;
}
[Serialize(50.0f, false), Editable(0.0f, 1000.0f, DecimalCount = 2)]
[Editable(0.0f, 1000.0f, DecimalCount = 2),
Serialize(50.0f, false, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character"
+ " with insufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at.")]
public float SpringDampingLowSkill
{
get;
private set;
}
[Serialize(10.0f, false), Editable(0.0f, 1000.0f, DecimalCount = 2)]
[Editable(0.0f, 1000.0f, DecimalCount = 2),
Serialize(10.0f, false, description: "How much torque is applied to resist the movement of the barrel when the item is used by a character"
+ " with sufficient skills to operate it. Higher values make the aiming more \"snappy\", stopping the barrel from swinging around the direction it's being aimed at.")]
public float SpringDampingHighSkill
{
get;
private set;
}
[Serialize(1.0f, false), Editable(0.0f, 100.0f, DecimalCount = 2)]
[Editable(0.0f, 100.0f, DecimalCount = 2),
Serialize(1.0f, false, description: "Maximum angular velocity of the barrel when used by a character with insufficient skills to operate it.")]
public float RotationSpeedLowSkill
{
get;
private set;
}
[Serialize(5.0f, false), Editable(0.0f, 100.0f, DecimalCount = 2)]
[Editable(0.0f, 100.0f, DecimalCount = 2),
Serialize(5.0f, false, description: "Maximum angular velocity of the barrel when used by a character with sufficient skills to operate it."),]
public float RotationSpeedHighSkill
{
get;
@@ -134,7 +144,7 @@ namespace Barotrauma.Items.Components
}
private float baseRotationRad;
[Serialize(0.0f, true), Editable(0.0f, 360.0f)]
[Editable(0.0f, 360.0f), Serialize(0.0f, true, description: "The angle of the turret's base in degrees.")]
public float BaseRotation
{
get { return MathHelper.ToDegrees(baseRotationRad); }
@@ -104,7 +104,7 @@ namespace Barotrauma
case WearableType.Husk:
case WearableType.Herpes:
Limb = LimbType.Head;
HideLimb = false;
HideLimb = type == WearableType.Husk || type == WearableType.Herpes;
HideOtherWearables = false;
InheritLimbDepth = true;
InheritTextureScale = true;