Files
LuaCsForBarotraumaEP/Barotrauma/Source/Items/Components/Holdable/Holdable.cs
Joonas Rikkonen de00eb2ab4 Some fixes to attachable items (buttons, signal items, etc):
- Syncing the attached/detached state of the items. This should fix the "received a position update for an item with no physics body " errors: midround-joining clients didn't get notified if an item had been detached, causing the error to appear every time it receives a position update.
- Detached items can be picked up just like any other item, instead of having to use a wrench and wait for the item to "detach".
- Wires can't be connected to items with a physics body (such as detached buttons).
2017-06-21 20:45:33 +03:00

361 lines
9.8 KiB
C#

using System.Xml.Linq;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using Barotrauma.Networking;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class Holdable : Pickable, IServerSerializable
{
//the position(s) in the item that the Character grabs
protected Vector2[] handlePos;
private InputType prevPickKey;
private string prevMsg;
//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 bool attachable, attached, attachedByDefault;
private PhysicsBody body;
//the angle in which the Character holds the item
protected float holdAngle;
[HasDefaultValue(false, true)]
public bool Attached
{
get { return attached && item.ParentInventory == null; }
set { attached = value; }
}
[HasDefaultValue(false, false)]
public bool ControlPose
{
get;
set;
}
[HasDefaultValue(false, false)]
public bool Attachable
{
get { return attachable; }
set { attachable = value; }
}
[HasDefaultValue(false, false)]
public bool AttachedByDefault
{
get { return attachedByDefault; }
set { attachedByDefault = value; }
}
[HasDefaultValue("0.0,0.0", false)]
public string HoldPos
{
get { return ToolBox.Vector2ToString(ConvertUnits.ToDisplayUnits(holdPos)); }
set { holdPos = ConvertUnits.ToSimUnits(ToolBox.ParseToVector2(value)); }
}
[HasDefaultValue("0.0,0.0", false)]
public string AimPos
{
get { return ToolBox.Vector2ToString(ConvertUnits.ToDisplayUnits(aimPos)); }
set { aimPos = ConvertUnits.ToSimUnits(ToolBox.ParseToVector2(value)); }
}
[HasDefaultValue(0.0f, false)]
public float HoldAngle
{
get { return MathHelper.ToDegrees(holdAngle); }
set { holdAngle = MathHelper.ToRadians(value); }
}
public Holdable(Item item, XElement element)
: base(item, element)
{
body = item.body;
handlePos = new Vector2[2];
for (int i = 1; i < 3; i++)
{
handlePos[i - 1] = ToolBox.GetAttributeVector2(element, "handle" + i, Vector2.Zero);
handlePos[i - 1] = ConvertUnits.ToSimUnits(handlePos[i - 1]);
}
canBePicked = true;
if (attachable)
{
prevMsg = Msg;
prevPickKey = PickKey;
DeattachFromWall();
}
if ((Screen.Selected == GameMain.EditMapScreen)) Use(1.0f);
}
public override void Drop(Character dropper)
{
DropConnectedWires(dropper);
if (attachable)
{
DeattachFromWall();
if (body != null)
{
item.body = body;
}
}
if (item.body != null) item.body.Enabled = true;
IsActive = false;
if (picker == null)
{
if (dropper == null) return;
picker = dropper;
}
if (picker.Inventory == null) return;
item.Submarine = picker.Submarine;
if (item.body != null)
{
item.body.ResetDynamics();
item.SetTransform(picker.SimPosition, 0.0f);
}
picker.DeselectItem(item);
picker.Inventory.RemoveItem(item);
picker = null;
}
public override void Equip(Character character)
{
picker = character;
if (character != null) item.Submarine = character.Submarine;
if (item.body == null)
{
if (body != null)
{
item.body = body;
}
else
{
return;
}
}
if (!item.body.Enabled)
{
Limb rightHand = picker.AnimController.GetLimb(LimbType.RightHand);
item.SetTransform(rightHand.SimPosition, 0.0f);
}
bool alreadySelected = character.HasSelectedItem(item);
if (picker.TrySelectItem(item))
{
item.body.Enabled = true;
IsActive = true;
if (!alreadySelected) Networking.GameServer.Log(character.Name + " equipped " + item.Name, Networking.ServerLog.MessageType.ItemInteraction);
}
}
public override void Unequip(Character character)
{
if (picker == null) return;
picker.DeselectItem(item);
Networking.GameServer.Log(character.Name + " unequipped " + item.Name, Networking.ServerLog.MessageType.ItemInteraction);
item.body.Enabled = false;
IsActive = false;
}
public override bool Pick(Character picker)
{
if (!attachable)
{
return base.Pick(picker);
}
if (Attached)
{
return base.Pick(picker);
}
else
{
//not attached -> pick the item instantly, ignoring picking time
return OnPicked(picker);
}
}
protected override bool OnPicked(Character picker)
{
if (base.OnPicked(picker))
{
DeattachFromWall();
if (GameMain.Server != null && attachable)
{
item.CreateServerEvent(this);
}
return true;
}
return false;
}
private void AttachToWall()
{
if (!attachable) return;
var containedItems = item.ContainedItems;
if (containedItems != null)
{
foreach (Item contained in containedItems)
{
if (contained.body == null) continue;
contained.SetTransform(item.SimPosition, contained.body.Rotation);
}
}
item.body.Enabled = false;
item.body = null;
Msg = prevMsg;
PickKey = prevPickKey;
attached = true;
}
private void DeattachFromWall()
{
if (!attachable) return;
attached = false;
//make the item pickable with the default pick key and with no specific tools/items when it's deattached
requiredItems.Clear();
Msg = "";
PickKey = InputType.Select;
}
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body == null) return true;
if (character != null)
{
if (!character.IsKeyDown(InputType.Aim)) return false;
if (character != null && GameMain.Server != null)
{
item.CreateServerEvent(this);
}
item.Drop();
}
AttachToWall();
return true;
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
Update(deltaTime, cam);
}
public override void Update(float deltaTime, Camera cam)
{
if (item.body == null || !item.body.Enabled) return;
if (picker == null || !picker.HasSelectedItem(item))
{
IsActive = false;
return;
}
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) Flip(item);
item.Submarine = picker.Submarine;
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim), holdAngle);
}
protected void Flip(Item item)
{
handlePos[0].X = -handlePos[0].X;
handlePos[1].X = -handlePos[1].X;
item.body.Dir = -item.body.Dir;
}
public override void OnMapLoaded()
{
//prevRequiredItems = new List<RelatedItem>(requiredItems);
if (!attachable) return;
if (Attached)
{
Use(1.0f);
}
else
{
if (item.ParentInventory != null)
{
if (body != null)
{
item.body = body;
body.Enabled = false;
}
}
attached = false;
DeattachFromWall();
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(Attached);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
bool isAttached = msg.ReadBoolean();
if (isAttached)
{
item.Drop();
AttachToWall();
}
else
{
DropConnectedWires(null);
if (body != null)
{
item.body = body;
item.body.Enabled = true;
}
IsActive = false;
DeattachFromWall();
}
}
}
}