38f1ddb...178a853: v0.8.9.1, removed content folder

This commit is contained in:
Joonas Rikkonen
2019-03-18 19:46:58 +02:00
parent 38f1ddb6fe
commit 6c0679c297
1054 changed files with 151673 additions and 144931 deletions
@@ -11,24 +11,35 @@ namespace Barotrauma.Items.Components
{
//the position(s) in the item that the Character grabs
protected Vector2[] handlePos;
private Vector2[] scaledHandlePos;
private InputType prevPickKey;
private string prevMsg;
private List<RelatedItem> prevRequiredItems;
private Dictionary<RelatedItem.RelationType, List<RelatedItem>> prevRequiredItems;
//the distance from the holding characters elbow to center of the physics body of the item
protected Vector2 holdPos;
protected Vector2 aimPos;
//protected bool aimable;
private float swingState;
private bool attachable, attached, attachedByDefault;
private PhysicsBody body;
public PhysicsBody Pusher
{
get;
private set;
}
//the angle in which the Character holds the item
protected float holdAngle;
public PhysicsBody Body
{
get { return item.body ?? body; }
}
[Serialize(false, true)]
public bool Attached
{
@@ -36,6 +47,13 @@ namespace Barotrauma.Items.Components
set { attached = value; }
}
[Serialize(true, true)]
public bool Aimable
{
get;
set;
}
[Serialize(false, false)]
public bool ControlPose
{
@@ -50,6 +68,13 @@ namespace Barotrauma.Items.Components
set { attachable = value; }
}
[Serialize(true, false)]
public bool Reattachable
{
get;
set;
}
[Serialize(false, false)]
public bool AttachedByDefault
{
@@ -57,7 +82,7 @@ namespace Barotrauma.Items.Components
set { attachedByDefault = value; }
}
[Serialize("0.0,0.0", false)]
[Serialize("0.0,0.0", false),Editable]
public Vector2 HoldPos
{
get { return ConvertUnits.ToDisplayUnits(holdPos); }
@@ -71,25 +96,62 @@ namespace Barotrauma.Items.Components
set { aimPos = ConvertUnits.ToSimUnits(value); }
}
[Serialize(0.0f, false)]
[Serialize(0.0f, false), Editable]
public float HoldAngle
{
get { return MathHelper.ToDegrees(holdAngle); }
set { holdAngle = MathHelper.ToRadians(value); }
}
private Vector2 swingAmount;
[Serialize("0.0,0.0", false), Editable]
public Vector2 SwingAmount
{
get { return ConvertUnits.ToDisplayUnits(swingAmount); }
set { swingAmount = ConvertUnits.ToSimUnits(value); }
}
[Serialize(0.0f, false), Editable]
public float SwingSpeed { get; set; }
[Serialize(false, false), Editable]
public bool SwingWhenHolding { get; set; }
[Serialize(false, false), Editable]
public bool SwingWhenAiming { get; set; }
[Serialize(false, false), Editable]
public bool SwingWhenUsing { get; set; }
public Holdable(Item item, XElement element)
: base(item, element)
{
body = item.body;
handlePos = new Vector2[2];
Pusher = null;
if (element.GetAttributeBool("blocksplayers", false))
{
Pusher = new PhysicsBody(item.body.width, item.body.height, item.body.radius, item.body.Density)
{
BodyType = FarseerPhysics.Dynamics.BodyType.Dynamic,
CollidesWith = Physics.CollisionCharacter,
CollisionCategories = Physics.CollisionItemBlocking,
Enabled = false
};
Pusher.FarseerBody.FixedRotation = false;
Pusher.FarseerBody.GravityScale = 0.0f;
}
handlePos = new Vector2[2];
scaledHandlePos = new Vector2[2];
Vector2 previousValue = Vector2.Zero;
for (int i = 1; i < 3; i++)
{
handlePos[i - 1] = element.GetAttributeVector2("handle" + i, Vector2.Zero);
handlePos[i - 1] = ConvertUnits.ToSimUnits(handlePos[i - 1]);
int index = i - 1;
string attributeName = "handle" + i;
var attribute = element.Attribute(attributeName);
// If no value is defind for handle2, use the value of handle1.
var value = attribute != null ? ConvertUnits.ToSimUnits(XMLExtensions.ParseVector2(attribute.Value)) : previousValue;
handlePos[index] = value;
previousValue = value;
}
canBePicked = true;
@@ -98,7 +160,7 @@ namespace Barotrauma.Items.Components
{
prevMsg = Msg;
prevPickKey = PickKey;
prevRequiredItems = new List<RelatedItem>(requiredItems);
prevRequiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(requiredItems);
if (item.Submarine != null)
{
@@ -131,7 +193,7 @@ namespace Barotrauma.Items.Components
{
prevMsg = Msg;
prevPickKey = PickKey;
prevRequiredItems = new List<RelatedItem>(requiredItems);
prevRequiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(requiredItems);
}
}
@@ -156,7 +218,8 @@ namespace Barotrauma.Items.Components
item.body = body;
}
}
if (Pusher != null) Pusher.Enabled = false;
if (item.body != null) item.body.Enabled = true;
IsActive = false;
@@ -177,18 +240,17 @@ namespace Barotrauma.Items.Components
{
heldHand = picker.AnimController.GetLimb(LimbType.LeftHand);
arm = picker.AnimController.GetLimb(LimbType.LeftArm);
}
else
{
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);
item.SetTransform(heldHand.SimPosition + new Vector2(xDif, yDif), 0.0f);
}
picker.DeselectItem(item);
@@ -242,12 +304,28 @@ namespace Barotrauma.Items.Components
IsActive = false;
}
public bool CanBeAttached()
{
if (!attachable || !Reattachable) return false;
//can be attached anywhere in sub editor
if (Screen.Selected == GameMain.SubEditorScreen) return true;
//can be attached anywhere inside hulls
if (item.CurrentHull != null) return true;
return Structure.GetAttachTarget(item.WorldPosition) != null;
}
public bool CanBeDeattached()
{
if (!attachable || !attached) return true;
//don't allow deattaching if outside hulls and not in sub editor
return item.CurrentHull != null || Screen.Selected == GameMain.SubEditorScreen;
//allow deattaching everywhere in sub editor
if (Screen.Selected == GameMain.SubEditorScreen) return true;
//don't allow deattaching if part of a sub and outside hulls
return item.Submarine == null || item.CurrentHull != null;
}
public override bool Pick(Character picker)
@@ -281,7 +359,7 @@ namespace Barotrauma.Items.Components
item.CreateServerEvent(this);
if (picker != null)
{
Networking.GameServer.Log(picker.LogName + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
GameServer.Log(picker.LogName + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
}
}
return true;
@@ -290,10 +368,25 @@ namespace Barotrauma.Items.Components
return false;
}
private void AttachToWall()
public void AttachToWall()
{
if (!attachable) return;
//outside hulls/subs -> we need to check if the item is being attached on a structure outside the sub
if (item.CurrentHull == null && item.Submarine == null)
{
Structure attachTarget = Structure.GetAttachTarget(item.WorldPosition);
if (attachTarget != null)
{
if (attachTarget.Submarine != null)
{
//set to submarine-relative position
item.SetTransform(ConvertUnits.ToSimUnits(item.WorldPosition - attachTarget.Submarine.Position), 0.0f, false);
}
item.Submarine = attachTarget.Submarine;
}
}
var containedItems = item.ContainedItems;
if (containedItems != null)
{
@@ -309,12 +402,12 @@ namespace Barotrauma.Items.Components
Msg = prevMsg;
PickKey = prevPickKey;
requiredItems = new List<RelatedItem>(prevRequiredItems);
requiredItems = new Dictionary<RelatedItem.RelationType, List<RelatedItem>>(prevRequiredItems);
attached = true;
}
private void DeattachFromWall()
public void DeattachFromWall()
{
if (!attachable) return;
@@ -328,15 +421,15 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body == null) return true;
if (!attachable || item.body == null) return (character == null || character.IsKeyDown(InputType.Aim));
if (character != null)
{
if (!character.IsKeyDown(InputType.Aim)) return false;
if (character.CurrentHull == null) return false;
if (!CanBeAttached()) return false;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(character.LogName + " attached " + item.Name+" to a wall", ServerLog.MessageType.ItemInteraction);
GameServer.Log(character.LogName + " attached " + item.Name + " to a wall", ServerLog.MessageType.ItemInteraction);
}
item.Drop();
}
@@ -356,42 +449,57 @@ namespace Barotrauma.Items.Components
if (item.body == null || !item.body.Enabled) return;
if (picker == null || !picker.HasEquippedItem(item))
{
if (Pusher != null) Pusher.Enabled = false;
IsActive = false;
return;
}
Vector2 swing = Vector2.Zero;
if (swingAmount != Vector2.Zero)
{
swingState += deltaTime;
swingState %= 1.0f;
if (SwingWhenHolding ||
(SwingWhenAiming && picker.IsKeyDown(InputType.Aim)) ||
(SwingWhenUsing && picker.IsKeyDown(InputType.Aim) && picker.IsKeyDown(InputType.Use)))
{
swing = swingAmount * new Vector2(
PerlinNoise.GetPerlin(swingState * SwingSpeed * 0.1f, swingState * SwingSpeed * 0.1f) - 0.5f,
PerlinNoise.GetPerlin(swingState * SwingSpeed * 0.1f + 0.5f, swingState * SwingSpeed * 0.1f + 0.5f) - 0.5f);
}
}
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) Flip(item);
item.Submarine = picker.Submarine;
if (picker.HasSelectedItem(item))
{
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim) && aimPos != Vector2.Zero, holdAngle);
scaledHandlePos[0] = handlePos[0] * item.Scale;
scaledHandlePos[1] = handlePos[1] * item.Scale;
picker.AnimController.HoldItem(deltaTime, item, scaledHandlePos, holdPos + swing, aimPos + swing, picker.IsKeyDown(InputType.Aim) && aimPos != Vector2.Zero, holdAngle);
}
else
{
Limb equipLimb = null;
if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Face) || picker.Inventory.IsInLimbSlot(item, InvSlotType.Head))
if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Headset) || picker.Inventory.IsInLimbSlot(item, InvSlotType.Head))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Head);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Torso))
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.InnerClothes) ||
picker.Inventory.IsInLimbSlot(item, InvSlotType.OuterClothes))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Torso);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Legs))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Waist);
}
if (equipLimb != null)
{
float itemAngle = (equipLimb.Rotation + holdAngle * picker.AnimController.Dir);
Matrix itemTransfrom = Matrix.CreateRotationZ(equipLimb.Rotation);
Vector2 transformedHandlePos = Vector2.Transform(handlePos[0], itemTransfrom);
Vector2 transformedHandlePos = Vector2.Transform(handlePos[0] * item.Scale, itemTransfrom);
item.body.ResetDynamics();
item.SetTransform(equipLimb.SimPosition - transformedHandlePos, itemAngle);
@@ -434,20 +542,19 @@ namespace Barotrauma.Items.Components
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
public override void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
if (!attachable || body == null)
{
DebugConsole.ThrowError("Sent an attachment event for an item that's not attachable.");
}
base.ServerWrite(msg, c, extraData);
if (!attachable || body == null) return;
msg.Write(Attached);
msg.Write(body.SimPosition.X);
msg.Write(body.SimPosition.Y);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
public override void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
base.ClientRead(type, msg, sendingTime);
bool shouldBeAttached = msg.ReadBoolean();
Vector2 simPosition = new Vector2(msg.ReadFloat(), msg.ReadFloat());
@@ -459,9 +566,12 @@ namespace Barotrauma.Items.Components
if (shouldBeAttached)
{
Drop(false, null);
item.SetTransform(simPosition, 0.0f);
AttachToWall();
if (!attached)
{
Drop(false, null);
item.SetTransform(simPosition, 0.0f);
AttachToWall();
}
}
else
{
@@ -0,0 +1,100 @@
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class LevelResource : ItemComponent, IServerSerializable
{
[Serialize(1.0f, false)]
public float DeattachDuration
{
get;
set;
}
[Serialize(0.0f, false)]
public float DeattachTimer
{
get { return deattachTimer; }
set
{
deattachTimer = Math.Max(0.0f, value);
//clients don't deattach the item until the server says so (handled in ClientRead)
if (GameMain.Client == null && deattachTimer >= DeattachDuration)
{
holdable.DeattachFromWall();
}
}
}
private PhysicsBody trigger;
private Holdable holdable;
private float deattachTimer;
public LevelResource(Item item, XElement element) : base(item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
if (!holdable.Attached)
{
trigger.Enabled = false;
IsActive = false;
}
else
{
if (Vector2.DistanceSquared(item.SimPosition, trigger.SimPosition) > 0.01f)
{
trigger.SetTransform(item.SimPosition, 0.0f);
}
}
}
public override void OnItemLoaded()
{
holdable = item.GetComponent<Holdable>();
if (holdable == null)
{
DebugConsole.ThrowError("Error while initializing item \"" + item.Name + "\". Level resources require a Holdable component.");
IsActive = false;
return;
}
holdable.Reattachable = false;
holdable.PickingTime = float.MaxValue;
var body = item.body ?? holdable.Body;
if (body != null)
{
trigger = new PhysicsBody(body.width, body.height, body.radius, body.Density)
{
UserData = item
};
trigger.FarseerBody.IsSensor = true;
trigger.FarseerBody.IsStatic = true;
trigger.FarseerBody.CollisionCategories = Physics.CollisionWall;
}
}
protected override void RemoveComponentSpecific()
{
if (trigger != null)
{
trigger.Remove();
trigger = null;
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(deattachTimer);
}
}
}
@@ -27,6 +27,11 @@ namespace Barotrauma.Items.Components
private HashSet<Entity> hitTargets = new HashSet<Entity>();
public Character User
{
get { return user; }
}
[Serialize(0.0f, false)]
public float Range
{
@@ -56,7 +61,7 @@ namespace Barotrauma.Items.Components
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "attack") continue;
attack = new Attack(subElement);
attack = new Attack(subElement, item.Name + ", MeleeWeapon");
}
}
@@ -78,7 +83,7 @@ namespace Barotrauma.Items.Components
SetUser(character);
if (hitPos < MathHelper.Pi * 0.69f) return false;
if (hitPos < MathHelper.PiOver4) return false;
reloadTimer = reload;
@@ -129,6 +134,7 @@ namespace Barotrauma.Items.Components
if (!picker.HasSelectedItem(item)) IsActive = false;
reloadTimer -= deltaTime;
if (reloadTimer < 0) { reloadTimer = 0; }
if (!picker.IsKeyDown(InputType.Aim) && !hitting) hitPos = 0.0f;
@@ -138,32 +144,34 @@ namespace Barotrauma.Items.Components
AnimController ac = picker.AnimController;
//TODO: refactor the hitting logic (get rid of the magic numbers, make it possible to use different kinds of animations for different items)
if (!hitting)
{
if (picker.IsKeyDown(InputType.Aim))
if (picker.IsKeyDown(InputType.Aim) && reloadTimer <= 0)
{
hitPos = Math.Min(hitPos + deltaTime * 5.0f, MathHelper.Pi * 0.7f);
ac.HoldItem(deltaTime, item, handlePos, new Vector2(0.6f, -0.1f), new Vector2(-0.3f, 0.2f), false, hitPos);
hitPos = MathUtils.WrapAnglePi(Math.Min(hitPos + deltaTime * 5f, MathHelper.PiOver4));
ac.HoldItem(deltaTime, item, handlePos, aimPos, Vector2.Zero, false, hitPos, holdAngle + hitPos);
}
else
{
ac.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, false, holdAngle);
hitPos = 0;
ac.HoldItem(deltaTime, item, handlePos, holdPos, Vector2.Zero, false, holdAngle);
}
}
else
{
hitPos -= deltaTime * 15.0f;
ac.HoldItem(deltaTime, item, handlePos, new Vector2(0.6f, -0.1f), new Vector2(-0.3f, 0.2f), false, hitPos);
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)
{
RestoreCollision();
hitting = false;
hitTargets.Clear();
hitPos = 0;
}
}
}
private void SetUser(Character character)
{
if (user == character) return;
@@ -173,14 +181,12 @@ namespace Barotrauma.Items.Components
{
foreach (Limb limb in user.AnimController.Limbs)
{
try
if (limb.body.FarseerBody != null)
{
item.body.FarseerBody.RestoreCollisionWith(limb.body.FarseerBody);
}
catch
{
continue;
if (GameMain.World.BodyList.Contains(limb.body.FarseerBody))
{
item.body.FarseerBody.RestoreCollisionWith(limb.body.FarseerBody);
}
}
}
}
@@ -199,11 +205,6 @@ namespace Barotrauma.Items.Components
item.body.CollisionCategories = Physics.CollisionItem;
item.body.CollidesWith = Physics.CollisionWall;
//foreach (Limb l in picker.AnimController.Limbs)
//{
// item.body.FarseerBody.RestoreCollisionWith(l.body.FarseerBody);
//}
}
@@ -220,6 +221,8 @@ namespace Barotrauma.Items.Components
Limb targetLimb = null;
Structure targetStructure = null;
attack?.SetUser(user);
if (f2.Body.UserData is Limb)
{
targetLimb = (Limb)f2.Body.UserData;
@@ -273,10 +276,12 @@ namespace Barotrauma.Items.Components
{
if (targetLimb != null)
{
targetLimb.character.LastDamageSource = item;
attack.DoDamageToLimb(user, targetLimb, item.WorldPosition, 1.0f);
}
else if (targetCharacter != null)
{
targetCharacter.LastDamageSource = item;
attack.DoDamage(user, targetCharacter, item.WorldPosition, 1.0f);
}
else if (targetStructure != null)
@@ -293,7 +298,14 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null && targetCharacter != null) //TODO: Log structure hits
{
GameMain.Server.CreateEntityEvent(item, new object[] { Networking.NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, targetCharacter.ID });
GameMain.Server.CreateEntityEvent(item, new object[]
{
Networking.NetEntityEvent.Type.ApplyStatusEffect,
ActionType.OnUse,
null, //itemcomponent
targetCharacter.ID, targetLimb
});
string logStr = picker?.LogName + " used " + item.Name;
if (item.ContainedItems != null && item.ContainedItems.Length > 0)
@@ -303,9 +315,11 @@ namespace Barotrauma.Items.Components
logStr += " on " + targetCharacter.LogName + ".";
Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack);
}
if (targetCharacter != null) //TODO: Allow OnUse to happen on structures too maybe??
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter);
{
ApplyStatusEffects(ActionType.OnUse, 1.0f, targetCharacter, targetLimb, user: user);
}
if (DeleteOnUse)
{
@@ -1,11 +1,13 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class Pickable : ItemComponent
class Pickable : ItemComponent, IServerSerializable
{
protected Character picker;
@@ -13,6 +15,8 @@ namespace Barotrauma.Items.Components
private float pickTimer;
private Character activePicker;
public List<InvSlotType> AllowedSlots
{
get { return allowedSlots; }
@@ -36,13 +40,14 @@ namespace Barotrauma.Items.Components
InvSlotType allowedSlot = InvSlotType.None;
foreach (string slot in slots)
{
if (slot.ToLowerInvariant() == "bothhands")
switch (slot.ToLowerInvariant())
{
allowedSlot = InvSlotType.LeftHand | InvSlotType.RightHand;
}
else
{
allowedSlot = allowedSlot | (InvSlotType)Enum.Parse(typeof(InvSlotType), slot.Trim());
case "bothhands":
allowedSlot = InvSlotType.LeftHand | InvSlotType.RightHand;
break;
default:
allowedSlot = allowedSlot | (InvSlotType)Enum.Parse(typeof(InvSlotType), slot.Trim());
break;
}
}
allowedSlots.Add(allowedSlot);
@@ -59,8 +64,9 @@ namespace Barotrauma.Items.Components
if (PickingTime > 0.0f)
{
if (picker.PickingItem == null)
if (picker.PickingItem == null && PickingTime <= float.MaxValue)
{
item.CreateServerEvent(this);
CoroutineManager.StartCoroutine(WaitForPick(picker, PickingTime));
}
return false;
@@ -90,7 +96,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItem);
PlaySound(ActionType.OnPicked, item.WorldPosition);
PlaySound(ActionType.OnPicked, item.WorldPosition, picker);
#endif
return true;
@@ -105,6 +111,7 @@ namespace Barotrauma.Items.Components
private IEnumerable<object> WaitForPick(Character picker, float requiredTime)
{
activePicker = picker;
picker.PickingItem = item;
var leftHand = picker.AnimController.GetLimb(LimbType.LeftHand);
@@ -127,7 +134,7 @@ namespace Barotrauma.Items.Components
Color.Red, Color.Green);
#endif
picker.AnimController.UpdateUseItem(true, item.SimPosition + Vector2.UnitY * ((pickTimer / 10.0f) % 0.1f));
picker.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * ((pickTimer / 10.0f) % 0.1f));
pickTimer += CoroutineManager.DeltaTime;
@@ -143,28 +150,31 @@ namespace Barotrauma.Items.Components
private void StopPicking(Character picker)
{
picker.AnimController.Anim = AnimController.Animation.None;
picker.PickingItem = null;
if (picker != null)
{
picker.AnimController.Anim = AnimController.Animation.None;
picker.PickingItem = null;
}
activePicker = null;
pickTimer = 0.0f;
}
protected void DropConnectedWires(Character character)
{
Vector2 pos = character == null ? item.SimPosition : character.SimPosition;
var connectionPanel = item.GetComponent<ConnectionPanel>();
if (connectionPanel == null) return;
foreach (Connection c in connectionPanel.Connections)
foreach (ConnectionPanel connectionPanel in item.GetComponents<ConnectionPanel>())
{
foreach (Wire w in c.Wires)
foreach (Connection c in connectionPanel.Connections)
{
if (w == null) continue;
w.Item.Drop(character);
w.Item.SetTransform(pos, 0.0f);
foreach (Wire w in c.Wires)
{
if (w == null) continue;
w.Item.Drop(character);
w.Item.SetTransform(pos, 0.0f);
}
}
}
}
}
public override void Drop(Character dropper)
@@ -204,5 +214,22 @@ namespace Barotrauma.Items.Components
}
}
public virtual void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(activePicker == null ? (ushort)0 : activePicker.ID);
}
public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
ushort pickerID = msg.ReadUInt16();
if (pickerID == 0)
{
StopPicking(activePicker);
}
else
{
Pick(Entity.FindEntityByID(pickerID) as Character);
}
}
}
}
@@ -11,18 +11,16 @@ namespace Barotrauma.Items.Components
{
enum UsableIn
{
Air,Water,Both
Air, Water, Both
};
private float force;
private string particles;
private float useState;
private UsableIn usableIn;
[Serialize(0.0f, false)]
[Serialize(0.0f, false), Editable(MinValueFloat = 0.0f, MaxValueFloat = 1000.0f)]
public float Force
{
get { return force; }
@@ -30,6 +28,7 @@ namespace Barotrauma.Items.Components
}
#if CLIENT
private string particles;
[Serialize("", false)]
public string Particles
{
@@ -1,4 +1,5 @@
using FarseerPhysics;
using FarseerPhysics.Collision;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using System;
@@ -81,7 +82,7 @@ namespace Barotrauma.Items.Components
limbBodies.Add(l.body.FarseerBody);
}
float degreeOfFailure = (100.0f - DegreeOfSuccess(character)) / 100.0f;
float degreeOfFailure = 1.0f - DegreeOfSuccess(character);
degreeOfFailure *= degreeOfFailure;
@@ -90,50 +91,80 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
}
Projectile projectile = null;
Item[] containedItems = item.ContainedItems;
if (containedItems != null)
if (containedItems == null) return true;
foreach (Item item in containedItems)
{
foreach (Item projectile 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)
{
if (projectile == null) continue;
//find the projectile-itemcomponent of the projectile,
//and add the limbs of the shooter to the list of bodies to be ignored
//so that the player can't shoot himself
Projectile projectileComponent= projectile.GetComponent<Projectile>();
if (projectileComponent == null) continue;
float spread = MathHelper.ToRadians(MathHelper.Lerp(Spread, UnskilledSpread, degreeOfFailure));
float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
rotation += spread * Rand.Range(-0.5f, 0.5f);
projectile.body.ResetDynamics();
projectile.SetTransform(TransformedBarrelPos, rotation);
projectileComponent.User = character;
projectileComponent.IgnoredBodies = new List<Body>(limbBodies);
projectile.Use(deltaTime);
projectileComponent.User = character;
projectile.body.ApplyTorque(projectile.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));
//set the rotation of the projectile again because dropping the projectile resets the rotation
projectile.SetTransform(projectile.SimPosition, rotation);
//recoil
item.body.ApplyLinearImpulse(
new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * item.body.Mass * -50.0f);
item.RemoveContained(projectile);
Rope rope = item.GetComponent<Rope>();
if (rope != null) rope.Attach(projectile);
return true;
Item[] containedSubItems = item.ContainedItems;
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...)
subItem.GetComponent<ItemContainer>()?.Item.ApplyStatusEffects(ActionType.OnUse, deltaTime);
if (projectile != null) break;
}
}
}
return true;
}
if (projectile == null) return true;
float spread = MathHelper.ToRadians(MathHelper.Lerp(Spread, UnskilledSpread, degreeOfFailure));
float rotation = (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
rotation += spread * Rand.Range(-0.5f, 0.5f);
projectile.User = character;
//add the limbs of the shooter to the list of bodies to be ignored
//so that the player can't shoot himself
projectile.IgnoredBodies = new List<Body>(limbBodies);
Vector2 projectilePos = item.SimPosition;
Vector2 sourcePos = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
Vector2 barrelPos = TransformedBarrelPos;
//make sure there's no obstacles between the base of the weapon (or the shoulder of the character) and the end of the barrel
if (Submarine.PickBody(sourcePos, barrelPos, projectile.IgnoredBodies) == null)
{
//no obstacles -> we can spawn the projectile at the barrel
projectilePos = barrelPos;
}
else if ((sourcePos - barrelPos).LengthSquared() > 0.0001f)
{
//spawn the projectile body.GetMaxExtent() away from the position where the raycast hit the obstacle
projectilePos = sourcePos - Vector2.Normalize(barrelPos - projectilePos) * Math.Max(projectile.Item.body.GetMaxExtent(), 0.1f);
}
projectile.Item.body.ResetDynamics();
projectile.Item.SetTransform(projectilePos, rotation);
projectile.Use(deltaTime);
projectile.User = character;
projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f));
//set the rotation of the projectile again because dropping the projectile resets the rotation
projectile.Item.SetTransform(projectilePos,
rotation + ((item.body.Dir == 1.0f) ? projectile.LaunchRotationRadians : projectile.LaunchRotationRadians - MathHelper.Pi));
//recoil
item.body.ApplyLinearImpulse(
new Vector2((float)Math.Cos(projectile.Item.body.Rotation), (float)Math.Sin(projectile.Item.body.Rotation)) * item.body.Mass * -50.0f);
item.RemoveContained(projectile.Item);
Rope rope = item.GetComponent<Rope>();
if (rope != null) rope.Attach(projectile.Item);
return true;
}
}
}
@@ -3,15 +3,15 @@ using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
#if CLIENT
using Barotrauma.Particles;
#endif
namespace Barotrauma.Items.Components
{
class RepairTool : ItemComponent
partial class RepairTool : ItemComponent
{
private readonly List<string> fixableEntities;
@@ -20,9 +20,7 @@ namespace Barotrauma.Items.Components
private Vector2 pickedPosition;
private Vector2 barrelPos;
private string particles;
private float activeTimer;
[Serialize(0.0f, false)]
@@ -44,25 +42,11 @@ namespace Barotrauma.Items.Components
get; set;
}
[Serialize(0.0f, false)]
public float ExtinquishAmount
public float ExtinguishAmount
{
get; set;
}
#if CLIENT
public ParticleEmitter ParticleEmitter
{
get;
private set;
}
private List<ParticleEmitter> ParticleEmitterHitStructure = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitItem = new List<ParticleEmitter>();
private List<ParticleEmitter> ParticleEmitterHitCharacter = new List<ParticleEmitter>();
#endif
[Serialize("0.0,0.0", false)]
public Vector2 BarrelPos
{
@@ -92,26 +76,24 @@ namespace Barotrauma.Items.Components
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "fixable":
fixableEntities.Add(subElement.Attribute("name").Value);
if (subElement.Attribute("name") != null)
{
DebugConsole.ThrowError("Error in RepairTool " + item.Name + " - use identifiers instead of names to configure fixable entities.");
fixableEntities.Add(subElement.Attribute("name").Value);
}
else
{
fixableEntities.Add(subElement.GetAttributeString("identifier", ""));
}
break;
#if CLIENT
case "particleemitter":
ParticleEmitter = new ParticleEmitter(subElement);
break;
case "particleemitterhititem":
ParticleEmitterHitItem.Add(new ParticleEmitter(subElement));
break;
case "particleemitterhitstructure":
ParticleEmitterHitStructure.Add(new ParticleEmitter(subElement));
break;
case "particleemitterhitcharacter":
ParticleEmitterHitCharacter.Add(new ParticleEmitter(subElement));
break;
#endif
}
}
InitProjSpecific(element);
}
partial void InitProjSpecific(XElement element);
public override void Update(float deltaTime, Camera cam)
{
activeTimer -= deltaTime;
@@ -123,7 +105,7 @@ namespace Barotrauma.Items.Components
if (character == null || character.Removed) return false;
if (!character.IsKeyDown(InputType.Aim)) return false;
float degreeOfSuccess = DegreeOfSuccess(character)/100.0f;
float degreeOfSuccess = DegreeOfSuccess(character);
if (Rand.Range(0.0f, 0.5f) > degreeOfSuccess)
{
@@ -163,32 +145,26 @@ namespace Barotrauma.Items.Components
Repair(rayStart - character.Submarine.SimPosition, rayEnd - character.Submarine.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
}
#if CLIENT
if (ParticleEmitter != null)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
ParticleEmitter.Emit(
deltaTime, item.WorldPosition + TransformedBarrelPos,
item.CurrentHull, particleAngle, -particleAngle);
}
#endif
UseProjSpecific(deltaTime);
return true;
}
partial void UseProjSpecific(float deltaTime);
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
{
Body targetBody = Submarine.PickBody(rayStart, rayEnd, ignoredBodies,
Body targetBody = Submarine.PickBody(rayStart, rayEnd, ignoredBodies,
Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair, false);
if (ExtinquishAmount > 0.0f && item.CurrentHull != null)
if (ExtinguishAmount > 0.0f && item.CurrentHull != null)
{
List<FireSource> fireSourcesInRange = new List<FireSource>();
//step along the ray in 10% intervals, collecting all fire sources in the range
for (float x = 0.0f; x <= Submarine.LastPickedFraction; x += 0.1f)
{
Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * x);
displayPos += item.CurrentHull.Submarine.Position;
if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; }
Hull hull = Hull.FindHull(displayPos, item.CurrentHull);
if (hull == null) continue;
@@ -203,52 +179,25 @@ namespace Barotrauma.Items.Components
foreach (FireSource fs in fireSourcesInRange)
{
fs.Extinguish(deltaTime, ExtinquishAmount);
fs.Extinguish(deltaTime, ExtinguishAmount);
}
}
if (targetBody == null || targetBody.UserData == null) return;
pickedPosition = Submarine.LastPickedPosition;
Structure targetStructure;
Character targetCharacter;
Limb targetLimb;
Item targetItem;
if ((targetStructure = (targetBody.UserData as Structure)) != null)
if (targetBody.UserData is Structure targetStructure)
{
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Name)) return;
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return;
if (targetStructure.IsPlatform) return;
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
if (sectionIndex < 0) return;
#if CLIENT
Vector2 progressBarPos = targetStructure.SectionPosition(sectionIndex);
if (targetStructure.Submarine != null)
{
progressBarPos += targetStructure.Submarine.DrawPosition;
}
var progressBar = user.UpdateHUDProgressBar(
targetStructure,
progressBarPos,
1.0f - targetStructure.SectionDamage(sectionIndex) / targetStructure.Health,
Color.Red, Color.Green);
if (progressBar != null) progressBar.Size = new Vector2(60.0f, 20.0f);
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetStructure.Submarine != null) particlePos += targetStructure.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitStructure)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
#endif
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
//if the next section is small enough, apply the effect to it as well
//(to make it easier to fix a small "left-over" section)
for (int i = -1; i < 2; i += 2)
@@ -263,34 +212,25 @@ namespace Barotrauma.Items.Components
}
}
}
else if ((targetCharacter = (targetBody.UserData as Character)) != null)
else if (targetBody.UserData is Character targetCharacter)
{
targetCharacter.AddDamage(CauseOfDeath.Damage, -LimbFixAmount * degreeOfSuccess, user);
#if CLIENT
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetCharacter.Submarine != null) particlePos += targetCharacter.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitCharacter)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
#endif
}
else if ((targetLimb = (targetBody.UserData as Limb)) != null)
{
targetLimb.character.AddDamage(CauseOfDeath.Damage, -LimbFixAmount * degreeOfSuccess, user);
Vector2 hitPos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetCharacter.Submarine != null) hitPos += targetCharacter.Submarine.Position;
#if CLIENT
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetLimb.character.Submarine != null) particlePos += targetLimb.character.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitCharacter)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
#endif
targetCharacter.LastDamageSource = item;
targetCharacter.AddDamage(hitPos,
new List<Affliction>() { AfflictionPrefab.Burn.Instantiate(-LimbFixAmount * degreeOfSuccess, user) }, 0.0f, false, 0.0f, user);
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
}
else if ((targetItem = (targetBody.UserData as Item)) != null)
else if (targetBody.UserData is Limb targetLimb)
{
targetLimb.character.LastDamageSource = item;
targetLimb.character.DamageLimb(targetLimb.WorldPosition, targetLimb,
new List<Affliction>() { AfflictionPrefab.Burn.Instantiate(-LimbFixAmount * degreeOfSuccess, user) }, 0.0f, false, 0.0f, user);
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
}
else if (targetBody.UserData is Item targetItem)
{
targetItem.IsHighlighted = true;
@@ -298,31 +238,27 @@ namespace Barotrauma.Items.Components
ApplyStatusEffectsOnTarget(deltaTime, ActionType.OnUse, targetItem.AllPropertyObjects);
#if CLIENT
if (item.Condition != prevCondition)
var levelResource = targetItem.GetComponent<LevelResource>();
if (levelResource != null && levelResource.IsActive &&
levelResource.HasRequiredItems(user, addMessage: false))
{
Vector2 progressBarPos = targetItem.DrawPosition;
var progressBar = user.UpdateHUDProgressBar(
targetItem,
progressBarPos,
targetItem.Condition / 100.0f,
levelResource.DeattachTimer += deltaTime;
#if CLIENT
Character.Controlled?.UpdateHUDProgressBar(
this,
targetItem.WorldPosition,
levelResource.DeattachTimer / levelResource.DeattachDuration,
Color.Red, Color.Green);
if (progressBar != null) progressBar.Size = new Vector2(60.0f, 20.0f);
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
foreach (var emitter in ParticleEmitterHitItem)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
emitter.Emit(deltaTime, particlePos, item.CurrentHull, particleAngle + MathHelper.Pi, -particleAngle + MathHelper.Pi);
}
#endif
}
#endif
FixItemProjSpecific(user, deltaTime, targetItem, prevCondition);
}
}
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter);
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition);
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
Gap leak = objective.OperateTarget as Gap;
@@ -332,17 +268,24 @@ namespace Barotrauma.Items.Components
//too far away -> consider this done and hope the AI is smart enough to move closer
if (dist > range * 5.0f) return true;
Vector2 gapDiff = leak.WorldPosition - item.WorldPosition;
if (!character.AnimController.InWater && character.AnimController is HumanoidAnimController &&
Math.Abs(gapDiff.X) < 100.0f && gapDiff.Y < 0.0f && gapDiff.Y > -150.0f)
{
((HumanoidAnimController)character.AnimController).Crouching = true;
}
//steer closer if almost in range
if (dist > range)
{
Vector2 standPos = leak.IsHorizontal ?
new Vector2(Math.Sign(item.WorldPosition.X - leak.WorldPosition.X), 0.0f)
: new Vector2(0.0f, Math.Sign(item.WorldPosition.Y - leak.WorldPosition.Y));
new Vector2(Math.Sign(-gapDiff.X), 0.0f)
: new Vector2(0.0f, Math.Sign(-gapDiff.Y) * 0.5f);
standPos = leak.WorldPosition + standPos * range;
character.AIController.SteeringManager.SteeringManual(deltaTime, (standPos - character.WorldPosition) / 1000.0f);
character.AIController.SteeringManager.SteeringManual(deltaTime, (standPos - character.WorldPosition) / 1000.0f);
}
else
{
@@ -355,7 +298,21 @@ namespace Barotrauma.Items.Components
Use(deltaTime, character);
return leak.Open <= 0.0f;
bool leakFixed = leak.Open <= 0.0f || leak.Removed;
if (leakFixed && leak.FlowTargetHull != null)
{
if (!leak.FlowTargetHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f))
{
character.Speak(TextManager.Get("DialogLeaksFixed").Replace("[roomname]", leak.FlowTargetHull.RoomName), null, 0.0f, "leaksfixed", 10.0f);
}
else
{
character.Speak(TextManager.Get("DialogLeakFixed").Replace("[roomname]", leak.FlowTargetHull.RoomName), null, 0.0f, "leakfixed", 10.0f);
}
}
return leakFixed;
}
private void ApplyStatusEffectsOnTarget(float deltaTime, ActionType actionType, List<ISerializableEntity> targets)
@@ -367,7 +324,7 @@ namespace Barotrauma.Items.Components
foreach (StatusEffect effect in statusEffects)
{
if (effect.Targets.HasFlag(StatusEffect.TargetType.UseTarget))
if (effect.HasTargetType(StatusEffect.TargetType.UseTarget))
{
effect.Apply(actionType, deltaTime, item, targets);
}
@@ -24,6 +24,10 @@ namespace Barotrauma.Items.Components
: base(item, element)
{
//throwForce = ToolBox.GetAttributeFloat(element, "throwforce", 1.0f);
if (aimPos == Vector2.Zero)
{
aimPos = new Vector2(0.6f, 0.1f);
}
}
public override bool Use(float deltaTime, Character character = null)
@@ -77,22 +81,21 @@ namespace Barotrauma.Items.Components
{
if (picker.IsKeyDown(InputType.Aim))
{
throwPos = (float)System.Math.Min(throwPos + deltaTime * 5.0f, MathHelper.Pi * 0.7f);
ac.HoldItem(deltaTime, item, handlePos, new Vector2(0.6f, -0.0f), new Vector2(-0.3f, 0.2f), false, throwPos);
throwPos = MathUtils.WrapAnglePi(System.Math.Min(throwPos + deltaTime * 5.0f, MathHelper.PiOver2));
ac.HoldItem(deltaTime, item, handlePos, aimPos, Vector2.Zero, false, throwPos);
}
else
{
ac.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, false, holdAngle);
throwPos = 0;
ac.HoldItem(deltaTime, item, handlePos, holdPos, Vector2.Zero, false, holdAngle);
}
}
else
{
throwPos -= deltaTime * 15.0f;
throwPos = MathUtils.WrapAnglePi(throwPos - deltaTime * 15.0f);
ac.HoldItem(deltaTime, item, handlePos, aimPos, Vector2.Zero, false, throwPos);
ac.HoldItem(deltaTime, item, handlePos, new Vector2(0.6f, 0.0f), new Vector2(-0.3f, 0.2f), false, throwPos);
if (throwPos < -0.0)
if (throwPos < 0)
{
Vector2 throwVector = Vector2.Normalize(picker.CursorWorldPosition - picker.WorldPosition);
//throw upwards if cursor is at the position of the character
@@ -108,6 +111,7 @@ namespace Barotrauma.Items.Components
Limb rightHand = ac.GetLimb(LimbType.RightHand);
item.body.AngularVelocity = rightHand.body.AngularVelocity;
throwPos = 0;
throwDone = true;
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, picker); //Stun grenades, flares, etc. all have their throw-related things handled in "onSecondaryUse"
throwing = false;