Renamed project folders from Subsurface to Barotrauma

This commit is contained in:
Regalis
2017-06-04 15:00:53 +03:00
parent ad03c8bf0d
commit 94c6a8ea1b
697 changed files with 157 additions and 211 deletions
@@ -0,0 +1,83 @@
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class AndComponent : ItemComponent
{
protected string output, falseOutput;
//an array to keep track of how long ago a non-zero signal was received on both inputs
protected float[] timeSinceReceived;
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
[InGameEditable, HasDefaultValue(0.0f, true)]
public float TimeFrame
{
get { return timeFrame; }
set
{
timeFrame = Math.Max(0.0f, value);
}
}
[InGameEditable, HasDefaultValue("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, HasDefaultValue("", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
public AndComponent(Item item, XElement element)
: base (item, element)
{
timeSinceReceived = new float[] { Math.Max(timeFrame*2.0f,0.1f), Math.Max(timeFrame*2.0f, 0.1f) };
//output = "1";
}
public override void Update(float deltaTime, Camera cam)
{
bool sendOutput = true;
for (int i = 0; i<timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] > timeFrame) sendOutput = false;
timeSinceReceived[i] += deltaTime;
}
string signalOut = sendOutput ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
switch (connection.Name)
{
case "signal_in1":
if (signal == "0") return;
timeSinceReceived[0] = 0.0f;
IsActive = true;
break;
case "signal_in2":
if (signal == "0") return;
timeSinceReceived[1] = 0.0f;
IsActive = true;
break;
case "set_output":
output = signal;
break;
}
}
}
}
@@ -0,0 +1,486 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class Connection
{
private static Texture2D panelTexture;
private static Sprite connector;
private static Sprite wireVertical;
//how many wires can be linked to a single connector
public const int MaxLinked = 5;
public readonly string Name;
public Wire[] Wires;
private Item item;
public readonly bool IsOutput;
private static Wire draggingConnected;
private List<StatusEffect> effects;
public readonly ushort[] wireId;
public bool IsPower
{
get;
private set;
}
public List<Connection> Recipients
{
get
{
List<Connection> recipients = new List<Connection>();
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null) continue;
Connection recipient = Wires[i].OtherConnection(this);
if (recipient != null) recipients.Add(recipient);
}
return recipients;
}
}
public Item Item
{
get { return item; }
}
public Connection(XElement element, Item item)
{
if (connector == null)
{
panelTexture = Sprite.LoadTexture("Content/Items/connectionpanel.png");
connector = new Sprite(panelTexture, new Rectangle(470, 102, 19, 43), Vector2.Zero, 0.0f);
connector.Origin = new Vector2(9.5f, 10.0f);
wireVertical = new Sprite(panelTexture, new Rectangle(408, 1, 11, 102), Vector2.Zero, 0.0f);
}
this.item = item;
//recipient = new Connection[MaxLinked];
Wires = new Wire[MaxLinked];
IsOutput = (element.Name.ToString() == "output");
Name = ToolBox.GetAttributeString(element, "name", (IsOutput) ? "output" : "input");
IsPower = Name == "power_in" || Name == "power" || Name == "power_out";
effects = new List<StatusEffect>();
wireId = new ushort[MaxLinked];
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "link":
int index = -1;
for (int i = 0; i < MaxLinked; i++)
{
if (wireId[i] < 1) index = i;
}
if (index == -1) break;
int id = ToolBox.GetAttributeInt(subElement, "w", 0);
if (id < 0) id = 0;
wireId[index] = (ushort)id;
break;
case "statuseffect":
effects.Add(StatusEffect.Load(subElement));
break;
}
}
}
public int FindEmptyIndex()
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null) return i;
}
return -1;
}
//public int FindLinkIndex(Item item)
//{
// for (int i = 0; i < MaxLinked; i++)
// {
// if (item == null && recipient[i] == null) return i;
// if (recipient[i]!=null && recipient[i].item == item) return i;
// }
// return -1;
//}
public int FindWireIndex(Item wireItem)
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null && wireItem == null) return i;
if (Wires[i] != null && Wires[i].Item == wireItem) return i;
}
return -1;
}
public void TryAddLink(Wire wire)
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null)
{
Wires[i] = wire;
return;
}
}
}
public void AddLink(int index, Wire wire)
{
Wires[index] = wire;
}
public void SendSignal(int stepsTaken, string signal, Item source, Character sender, float power)
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null) continue;
Connection recipient = Wires[i].OtherConnection(this);
if (recipient == null) continue;
if (recipient.item == this.item || recipient.item == source) continue;
foreach (ItemComponent ic in recipient.item.components)
{
ic.ReceiveSignal(stepsTaken, signal, recipient, item, sender, power);
}
foreach (StatusEffect effect in recipient.effects)
{
//effect.Apply(ActionType.OnUse, 1.0f, recipient.item, recipient.item);
recipient.item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
}
}
}
public void ClearConnections()
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null) continue;
Wires[i].RemoveConnection(this);
Wires[i] = null;
}
}
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
{
int width = 400, height = 200;
int x = GameMain.GraphicsWidth / 2 - width / 2, y = GameMain.GraphicsHeight - height;
Rectangle panelRect = new Rectangle(x, y, width, height);
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 512 - height, width, height), Color.White);
//GUI.DrawRectangle(spriteBatch, panelRect, Color.Black, true);
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
int totalWireCount = 0;
foreach (Connection c in panel.Connections)
{
totalWireCount += c.Wires.Count(w => w != null);
}
Wire equippedWire = null;
//if the Character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
for (int i = 0; i < character.SelectedItems.Length; i++)
{
Item selectedItem = character.SelectedItems[i];
if (selectedItem == null) continue;
Wire wireComponent = selectedItem.GetComponent<Wire>();
if (wireComponent != null) equippedWire = wireComponent;
}
Vector2 rightPos = new Vector2(x + width - 130, y + 50);
Vector2 leftPos = new Vector2(x + 130, y + 50);
Vector2 rightWirePos = new Vector2(x + width - 5, y + 30);
Vector2 leftWirePos = new Vector2(x + 5, y + 30);
int wireInterval = (height - 20) / Math.Max(totalWireCount, 1);
foreach (Connection c in panel.Connections)
{
//if dragging a wire, let the Inventory know so that the wire can be
//dropped or dragged from the panel to the players inventory
if (draggingConnected != null)
{
int linkIndex = c.FindWireIndex(draggingConnected.Item);
if (linkIndex > -1)
{
Inventory.draggingItem = c.Wires[linkIndex].Item;
}
}
//outputs are drawn at the right side of the panel, inputs at the left
if (c.IsOutput)
{
c.Draw(spriteBatch, panel.Item, rightPos,
new Vector2(rightPos.X - GUI.SmallFont.MeasureString(c.Name).X - 20, rightPos.Y + 3),
rightWirePos,
mouseInRect, equippedWire,
wireInterval);
rightPos.Y += 30;
rightWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
}
else
{
c.Draw(spriteBatch, panel.Item, leftPos,
new Vector2(leftPos.X + 20, leftPos.Y - 12),
leftWirePos,
mouseInRect, equippedWire,
wireInterval);
leftPos.Y += 30;
leftWirePos.Y += c.Wires.Count(w => w != null) * wireInterval;
//leftWireX -= wireInterval;
}
}
if (draggingConnected != null)
{
DrawWire(spriteBatch, draggingConnected, draggingConnected.Item, PlayerInput.MousePosition, new Vector2(x + width / 2, y + height), mouseInRect, null);
if (!PlayerInput.LeftButtonHeld())
{
if (GameMain.Client != null)
{
panel.Item.CreateClientEvent<ConnectionPanel>(panel);
}
else if (GameMain.Server != null)
{
panel.Item.CreateServerEvent<ConnectionPanel>(panel);
}
draggingConnected = null;
}
}
//if the Character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
if (equippedWire != null)
{
if (panel.Connections.Find(c => c.Wires.Contains(equippedWire)) == null)
{
DrawWire(spriteBatch, equippedWire, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
new Vector2(x + width / 2, y + height), mouseInRect, null);
if (draggingConnected == equippedWire) Inventory.draggingItem = equippedWire.Item;
}
}
//stop dragging a wire item if cursor is outside the panel
if (mouseInRect) Inventory.draggingItem = null;
spriteBatch.Draw(panelTexture, panelRect, new Rectangle(0, 0, width, height), Color.White);
}
private void Draw(SpriteBatch spriteBatch, Item item, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn, Wire equippedWire, float wireInterval)
{
//spriteBatch.DrawString(GUI.SmallFont, Name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
GUI.DrawString(spriteBatch, labelPos, Name, IsPower ? Color.Red : Color.White, Color.Black, 0, GUI.SmallFont);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)position.X - 10, (int)position.Y - 10, 20, 20), Color.White);
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(64, 256, 32, 32), Color.White);
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null || Wires[i].Hidden || draggingConnected == Wires[i]) continue;
Connection recipient = Wires[i].OtherConnection(this);
DrawWire(spriteBatch, Wires[i], (recipient == null) ? Wires[i].Item : recipient.item, position, wirePosition, mouseIn, equippedWire);
wirePosition.Y += wireInterval;
}
if (draggingConnected != null && Vector2.Distance(position, PlayerInput.MousePosition) < 13.0f)
{
spriteBatch.Draw(panelTexture, position - new Vector2(21.5f, 21.5f), new Rectangle(106, 250, 43, 43), Color.White);
if (!PlayerInput.LeftButtonHeld())
{
//find an empty cell for the new connection
int index = FindWireIndex(null);
if (index > -1 && !Wires.Contains(draggingConnected))
{
bool alreadyConnected = draggingConnected.IsConnectedTo(item);
draggingConnected.RemoveConnection(item);
if (draggingConnected.Connect(this, !alreadyConnected, true)) Wires[index] = draggingConnected;
}
}
}
int screwIndex = (position.Y % 60 < 30) ? 0 : 1;
if (Wires.Any(w => w != null && w != draggingConnected))
{
spriteBatch.Draw(panelTexture, position - new Vector2(16.0f, 16.0f), new Rectangle(screwIndex * 32, 256, 32, 32), Color.White);
}
}
private static void DrawWire(SpriteBatch spriteBatch, Wire wire, Item item, Vector2 end, Vector2 start, bool mouseIn, Wire equippedWire)
{
if (draggingConnected == wire)
{
if (!mouseIn) return;
end = PlayerInput.MousePosition;
start.X = (start.X + end.X) / 2.0f;
}
int textX = (int)start.X;
if (start.X < end.X)
textX -= 10;
else
textX += 10;
bool canDrag = equippedWire == null || equippedWire == wire;
float alpha = canDrag ? 1.0f : 0.5f;
bool mouseOn =
canDrag &&
((PlayerInput.MousePosition.X > Math.Min(start.X, end.X) &&
PlayerInput.MousePosition.X < Math.Max(start.X, end.X) &&
MathUtils.LineToPointDistance(start, end, PlayerInput.MousePosition) < 6) ||
Vector2.Distance(end, PlayerInput.MousePosition) < 20.0f ||
new Rectangle((start.X < end.X) ? textX - 100 : textX, (int)start.Y - 5, 100, 14).Contains(PlayerInput.MousePosition));
string label = wire.Locked ? item.Name + "\n(Locked)" : item.Name;
GUI.DrawString(spriteBatch,
new Vector2(start.X < end.X ? textX - GUI.SmallFont.MeasureString(label).X : textX, start.Y - 5.0f),
label,
(mouseOn ? Color.Gold : Color.White) * (wire.Locked ? 0.6f : 1.0f), Color.Black * 0.8f,
3, GUI.SmallFont);
var wireEnd = end + Vector2.Normalize(start - end) * 30.0f;
float dist = Vector2.Distance(start, wireEnd);
if (mouseOn)
{
spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(18, (int)dist)), wireVertical.SourceRect,
Color.Gold,
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above)
new Vector2(6, 0), // point in line about which to rotate
SpriteEffects.None,
0.0f);
}
spriteBatch.Draw(wireVertical.Texture, new Rectangle(wireEnd.ToPoint(), new Point(12, (int)dist)), wireVertical.SourceRect,
wire.Item.Color * alpha,
MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2, //angle of line (calulated above)
new Vector2(6, 0), // point in line about which to rotate
SpriteEffects.None,
0.0f);
connector.Draw(spriteBatch, end, Color.White, new Vector2(10.0f, 10.0f), MathUtils.VectorToAngle(end - start) + MathHelper.PiOver2);
if (draggingConnected == null && canDrag)
{
if (mouseOn)
{
ConnectionPanel.HighlightedWire = wire;
if (!wire.Locked)
{
//start dragging the wire
if (PlayerInput.LeftButtonHeld()) draggingConnected = wire;
}
}
}
}
public void Save(XElement parentElement)
{
XElement newElement = new XElement(IsOutput ? "output" : "input", new XAttribute("name", Name));
Array.Sort(Wires, delegate(Wire wire1, Wire wire2)
{
if (wire1 == null) return 1;
if (wire2 == null) return -1;
return wire1.Item.ID.CompareTo(wire2.Item.ID);
});
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null) continue;
//Connection recipient = wires[i].OtherConnection(this);
//int connectionIndex = recipient.item.Connections.FindIndex(x => x == recipient);
newElement.Add(new XElement("link",
new XAttribute("w", Wires[i].Item.ID.ToString())));
}
parentElement.Add(newElement);
}
public void ConnectLinked()
{
if (wireId == null) return;
for (int i = 0; i < MaxLinked; i++)
{
if (wireId[i] == 0) continue;
Item wireItem = MapEntity.FindEntityByID(wireId[i]) as Item;
if (wireItem == null) continue;
Wires[i] = wireItem.GetComponent<Wire>();
if (Wires[i] != null)
{
if (Wires[i].Item.body != null) Wires[i].Item.body.Enabled = false;
Wires[i].Connect(this, false, false);
}
}
}
}
}
@@ -0,0 +1,269 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Xml.Linq;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
{
public static Wire HighlightedWire;
public List<Connection> Connections;
Character user;
public ConnectionPanel(Item item, XElement element)
: base(item, element)
{
Connections = new List<Connection>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString())
{
case "input":
Connections.Add(new Connection(subElement, item));
break;
case "output":
Connections.Add(new Connection(subElement, item));
break;
}
}
IsActive = true;
}
public override void UpdateHUD(Character character)
{
if (character != Character.Controlled || character != user) return;
if (Screen.Selected != GameMain.EditMapScreen &&
character.IsKeyHit(InputType.Select) &&
character.SelectedConstruction == this.item) character.SelectedConstruction = null;
if (HighlightedWire != null)
{
HighlightedWire.Item.IsHighlighted = true;
if (HighlightedWire.Connections[0] != null && HighlightedWire.Connections[0].Item != null) HighlightedWire.Connections[0].Item.IsHighlighted = true;
if (HighlightedWire.Connections[1] != null && HighlightedWire.Connections[1].Item != null) HighlightedWire.Connections[1].Item.IsHighlighted = true;
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (character != Character.Controlled || character != user) return;
HighlightedWire = null;
Connection.DrawConnections(spriteBatch, this, character);
}
public override XElement Save(XElement parentElement)
{
XElement componentElement = base.Save(parentElement);
foreach (Connection c in Connections)
{
c.Save(componentElement);
}
return componentElement;
}
public override void OnMapLoaded()
{
foreach (Connection c in Connections)
{
c.ConnectLinked();
}
}
public override void Update(float deltaTime, Camera cam)
{
if (user != null && user.SelectedConstruction != item) user = null;
}
public override bool Select(Character picker)
{
user = picker;
IsActive = true;
return true;
}
public override bool Use(float deltaTime, Character character = null)
{
if (character == null || character!=user) return false;
var powered = item.GetComponent<Powered>();
if (powered != null)
{
if (powered.Voltage < 0.1f) return false;
}
float degreeOfSuccess = DegreeOfSuccess(character);
if (Rand.Range(0.0f, 50.0f) < degreeOfSuccess) return false;
character.SetStun(5.0f);
item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
return true;
}
public override void Load(XElement element)
{
base.Load(element);
List<Connection> loadedConnections = new List<Connection>();
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString())
{
case "input":
loadedConnections.Add(new Connection(subElement, item));
break;
case "output":
loadedConnections.Add(new Connection(subElement, item));
break;
}
}
for (int i = 0; i<loadedConnections.Count && i<Connections.Count; i++)
{
loadedConnections[i].wireId.CopyTo(Connections[i].wireId, 0);
}
}
protected override void RemoveComponentSpecific()
{
foreach (Connection c in Connections)
{
foreach (Wire wire in c.Wires)
{
if (wire == null) continue;
if (wire.OtherConnection(c) == null) //wire not connected to anything else
{
wire.Item.Drop(null);
}
else
{
wire.RemoveConnection(item);
}
}
}
}
public void ClientWrite(NetBuffer msg, object[] extraData = null)
{
foreach (Connection connection in Connections)
{
Wire[] wires = Array.FindAll(connection.Wires, w => w != null);
msg.WriteRangedInteger(0, Connection.MaxLinked, wires.Length);
for (int i = 0; i < wires.Length; i++)
{
msg.Write(wires[i].Item.ID);
}
}
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
{
int[] wireCounts = new int[Connections.Count];
Wire[,] wires = new Wire[Connections.Count, Connection.MaxLinked];
//read wire IDs for each connection
for (int i = 0; i < Connections.Count; i++)
{
wireCounts[i] = msg.ReadRangedInteger(0, Connection.MaxLinked);
for (int j = 0; j < wireCounts[i]; j++)
{
ushort wireId = msg.ReadUInt16();
Item wireItem = MapEntity.FindEntityByID(wireId) as Item;
if (wireItem == null) continue;
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent != null)
{
wires[i, j] = wireComponent;
}
}
}
item.CreateServerEvent<ConnectionPanel>(this);
//check if the character can access this connectionpanel
//and all the wires they're trying to connect
if (!item.CanClientAccess(c)) return;
foreach (Wire wire in wires)
{
if (wire != null)
{
//wire not found in any of the connections yet (client is trying to connect a new wire)
// -> we need to check if the client has access to it
if (!Connections.Any(connection => connection.Wires.Contains(wire)))
{
if (!wire.Item.CanClientAccess(c)) return;
}
}
}
Networking.GameServer.Log(item.Name + " rewired by " + c.Character.Name, ServerLog.MessageType.ItemInteraction);
//update the connections
for (int i = 0; i < Connections.Count; i++)
{
Connections[i].ClearConnections();
for (int j = 0; j < wireCounts[i]; j++)
{
if (wires[i, j] == null) continue;
Connections[i].Wires[j] = wires[i,j];
wires[i, j].Connect(Connections[i], true);
var otherConnection = Connections[i].Wires[j].OtherConnection(Connections[i]);
Networking.GameServer.Log(
item.Name + " (" + Connections[i].Name + ") -> " +
(otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"), ServerLog.MessageType.ItemInteraction);
}
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
ClientWrite(msg, extraData);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
foreach (Connection connection in Connections)
{
connection.ClearConnections();
int wireCount = msg.ReadRangedInteger(0, Connection.MaxLinked);
for (int i = 0; i < wireCount; i++)
{
ushort wireId = msg.ReadUInt16();
Item wireItem = MapEntity.FindEntityByID(wireId) as Item;
if (wireItem == null) continue;
Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) continue;
connection.Wires[i] = wireComponent;
wireComponent.Connect(connection, false);
}
}
}
}
}
@@ -0,0 +1,61 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class DelayComponent : ItemComponent
{
const int SignalQueueSize = 500;
//the output is sent if both inputs have received a signal within the timeframe
private TimeSpan delay;
private Queue<Tuple<string, DateTime>> signalQueue;
[InGameEditable, HasDefaultValue(1.0f, true)]
public float Delay
{
get { return (float)delay.TotalSeconds; }
set
{
float seconds = MathHelper.Clamp(value, 0.0f, 60.0f);
delay = new TimeSpan(0,0,0,0, (int)(seconds*1000.0f));
}
}
public DelayComponent(Item item, XElement element)
: base (item, element)
{
signalQueue = new Queue<Tuple<string, DateTime>>();
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
while (signalQueue.Any() && signalQueue.Peek().Item2 + delay <= DateTime.Now)
{
var signalOut = signalQueue.Dequeue();
item.SendSignal(0, signalOut.Item1, "signal_out", null);
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
switch (connection.Name)
{
case "signal_in":
if (signalQueue.Count >= SignalQueueSize) return;
signalQueue.Enqueue(new Tuple<string, DateTime>(signal, DateTime.Now));
break;
}
}
}
}
@@ -0,0 +1,224 @@
using Microsoft.Xna.Framework;
using Barotrauma.Lights;
using System;
using System.Xml.Linq;
using Barotrauma.Networking;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class LightComponent : Powered, IServerSerializable, IDrawableComponent
{
private Color lightColor;
private LightSource light;
private float range;
private float lightBrightness;
private float flicker;
private bool castShadows;
[Editable, HasDefaultValue(100.0f, true)]
public float Range
{
get { return range; }
set
{
range = MathHelper.Clamp(value, 0.0f, 2048.0f);
}
}
[Editable, HasDefaultValue(true, true)]
public bool CastShadows
{
get { return castShadows; }
set
{
castShadows = value;
if (light != null) light.CastShadows = value;
}
}
[Editable, HasDefaultValue(false, true)]
public bool IsOn
{
get { return IsActive; }
set
{
if (IsActive == value) return;
IsActive = value;
if (GameMain.Server != null) item.CreateServerEvent(this);
}
}
[HasDefaultValue(0.0f, false)]
public float Flicker
{
get { return flicker; }
set
{
flicker = MathHelper.Clamp(value, 0.0f, 1.0f);
}
}
[InGameEditable, HasDefaultValue("1.0,1.0,1.0,1.0", true)]
public string LightColor
{
get { return ToolBox.Vector4ToString(lightColor.ToVector4(), "0.00"); }
set
{
Vector4 newColor = ToolBox.ParseToVector4(value, false);
newColor.X = MathHelper.Clamp(newColor.X, 0.0f, 1.0f);
newColor.Y = MathHelper.Clamp(newColor.Y, 0.0f, 1.0f);
newColor.Z = MathHelper.Clamp(newColor.Z, 0.0f, 1.0f);
newColor.W = MathHelper.Clamp(newColor.W, 0.0f, 1.0f);
lightColor = new Color(newColor);
}
}
public override void Move(Vector2 amount)
{
light.Position += amount;
}
public override bool IsActive
{
get
{
return base.IsActive;
}
set
{
base.IsActive = value;
if (light == null) return;
light.Color = value ? lightColor : Color.Transparent;
if (!value) lightBrightness = 0.0f;
}
}
public LightComponent(Item item, XElement element)
: base (item, element)
{
light = new LightSource(element);
light.ParentSub = item.CurrentHull == null ? null : item.CurrentHull.Submarine;
light.Position = item.Position;
light.CastShadows = castShadows;
IsActive = IsOn;
//foreach (XElement subElement in element.Elements())
//{
// if (subElement.Name.ToString().ToLowerInvariant() != "sprite") continue;
// light.LightSprite = new Sprite(subElement);
// break;
//}
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
light.ParentSub = item.Submarine;
ApplyStatusEffects(ActionType.OnActive, deltaTime);
if (item.Container != null)
{
light.Color = Color.Transparent;
return;
}
if (item.body != null)
{
light.Position = item.Position;
light.Rotation = item.body.Dir > 0.0f ? item.body.Rotation : item.body.Rotation - MathHelper.Pi;
if (!item.body.Enabled)
{
light.Color = Color.Transparent;
return;
}
}
if (powerConsumption == 0.0f)
{
voltage = 1.0f;
}
else
{
currPowerConsumption = powerConsumption;
}
if (Rand.Range(0.0f, 1.0f) < 0.05f && voltage < Rand.Range(0.0f, minVoltage))
{
if (voltage > 0.1f) sparkSounds[Rand.Int(sparkSounds.Length)].Play(1.0f, 400.0f, item.WorldPosition);
lightBrightness = 0.0f;
}
else
{
lightBrightness = MathHelper.Lerp(lightBrightness, Math.Min(voltage, 1.0f), 0.1f);
}
light.Color = lightColor * lightBrightness * (1.0f-Rand.Range(0.0f,Flicker));
light.Range = range * (float)Math.Sqrt(lightBrightness);
voltage = 0.0f;
}
public override bool Use(float deltaTime, Character character = null)
{
return true;
}
public void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, bool editing = false)
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled))
{
light.LightSprite.Draw(spriteBatch, new Vector2(item.DrawPosition.X, -item.DrawPosition.Y), lightColor * lightBrightness, 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, item.Sprite.Depth - 0.0001f);
}
}
protected override void RemoveComponentSpecific()
{
base.RemoveComponentSpecific();
light.Remove();
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power);
switch (connection.Name)
{
case "toggle":
IsActive = !IsActive;
break;
case "set_state":
IsActive = (signal != "0");
break;
case "set_color":
LightColor = signal;
break;
}
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(IsOn);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
IsOn = msg.ReadBoolean();
}
}
}
@@ -0,0 +1,91 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class MotionSensor : ItemComponent
{
private const float UpdateInterval = 0.1f;
private string output, falseOutput;
private bool motionDetected;
private float range;
private float updateTimer;
[InGameEditable, HasDefaultValue(0.0f, true)]
public float Range
{
get { return range; }
set
{
range = MathHelper.Clamp(value, 0.0f, 500.0f);
}
}
[InGameEditable, HasDefaultValue("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, HasDefaultValue("", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
public MotionSensor(Item item, XElement element)
: base (item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
if (motionDetected)
{
item.SendSignal(1, output, "state_out", null);
}
else if (!string.IsNullOrWhiteSpace(falseOutput))
{
item.SendSignal(1, falseOutput, "state_out", null);
}
updateTimer -= deltaTime;
if (updateTimer > 0.0f) return;
motionDetected = false;
updateTimer = UpdateInterval;
if (item.body != null && item.body.Enabled)
{
if (Math.Abs(item.body.LinearVelocity.X) > 0.01f || Math.Abs(item.body.LinearVelocity.Y) > 0.1f)
{
motionDetected = true;
}
}
foreach (Character c in Character.CharacterList)
{
if (Math.Abs(c.WorldPosition.X - item.WorldPosition.X) < range &&
Math.Abs(c.WorldPosition.Y - item.WorldPosition.Y) < range)
{
if (!c.AnimController.Limbs.Any(l => l.body.FarseerBody.Awake)) continue;
motionDetected = true;
break;
}
}
}
}
}
@@ -0,0 +1,19 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class NotComponent : ItemComponent
{
public NotComponent(Item item, XElement element)
: base (item, element)
{
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
if (connection.Name != "signal_in") return;
item.SendSignal(stepsTaken, signal=="0" ? "1" : "0", "signal_out", sender);
}
}
}
@@ -0,0 +1,27 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class OrComponent : AndComponent
{
public OrComponent(Item item, XElement element)
: base (item, element)
{
}
public override void Update(float deltaTime, Camera cam)
{
bool sendOutput = false;
for (int i = 0; i<timeSinceReceived.Length; i++)
{
if (timeSinceReceived[i] <= timeFrame) sendOutput = true;
timeSinceReceived[i] += deltaTime;
}
string signalOut = sendOutput ? output : falseOutput;
if (string.IsNullOrEmpty(signalOut)) return;
item.SendSignal(0, signalOut, "signal_out", null);
}
}
}
@@ -0,0 +1,21 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class OxygenDetector : ItemComponent
{
public OxygenDetector(Item item, XElement element)
: base (item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
if (item.CurrentHull == null) return;
item.SendSignal(0, ((int)item.CurrentHull.OxygenPercentage).ToString(), "signal_out", null);
}
}
}
@@ -0,0 +1,93 @@
using System.Xml.Linq;
using System.Text.RegularExpressions;
namespace Barotrauma.Items.Components
{
class RegExFindComponent : ItemComponent
{
private string output;
private string expression;
private string receivedSignal;
private string previousReceivedSignal;
bool previousResult;
private Regex regex;
[InGameEditable, HasDefaultValue("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, HasDefaultValue("", true)]
public string Expression
{
get { return expression; }
set
{
if (expression == value) return;
expression = value;
previousReceivedSignal = "";
try
{
regex = new Regex(@expression);
}
catch
{
item.SendSignal(0, "ERROR", "signal_out", null);
return;
}
}
}
public RegExFindComponent(Item item, XElement element)
: base(item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
if (string.IsNullOrWhiteSpace(expression) || regex==null) return;
if (receivedSignal != previousReceivedSignal)
{
try
{
Match match = regex.Match(receivedSignal);
previousResult = match.Success;
previousReceivedSignal = receivedSignal;
}
catch
{
item.SendSignal(0, "ERROR", "signal_out", null);
previousResult = false;
return;
}
}
item.SendSignal(0, previousResult ? output : "0", "signal_out", null);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0.0f)
{
switch (connection.Name)
{
case "signal_in":
receivedSignal = signal;
break;
case "set_output":
output = signal;
break;
}
}
}
}
@@ -0,0 +1,108 @@
using Barotrauma.Networking;
using Lidgren.Network;
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class RelayComponent : PowerTransfer, IServerSerializable
{
private float maxPower;
[Editable, HasDefaultValue(1000.0f, true)]
public float MaxPower
{
get { return maxPower; }
set
{
maxPower = Math.Max(0.0f, value);
}
}
private bool isOn;
[Editable, HasDefaultValue(false, true)]
public bool IsOn
{
get
{
return IsActive;
}
set
{
isOn = value;
IsActive = value;
if (!IsActive)
{
currPowerConsumption = 0.0f;
}
}
}
public RelayComponent(Item item, XElement element)
: base (item, element)
{
IsActive = isOn;
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
item.SendSignal(0, IsOn ? "1" : "0", "state_out", null);
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
if (connection.IsPower && connection.Name.Contains("_out")) return;
if (item.Condition <= 0.0f) return;
if (power > maxPower) item.Condition = 0.0f;
if (connection.Name.Contains("_in"))
{
if (!IsOn) return;
string outConnection = connection.Name.Contains("power_in") ? "power_out" : "signal_out";
int connectionNumber = -1;
int.TryParse(connection.Name.Substring(connection.Name.Length - 1, 1), out connectionNumber);
if (connectionNumber > 0) outConnection += connectionNumber;
item.SendSignal(stepsTaken, signal, outConnection, sender, power);
}
else if (connection.Name == "toggle")
{
SetState(!IsOn, false);
}
else if (connection.Name == "set_state")
{
SetState(signal != "0", false);
}
}
public void SetState(bool on, bool isNetworkMessage)
{
if (GameMain.Client != null && !isNetworkMessage) return;
if (on != IsOn && GameMain.Server != null)
{
item.CreateServerEvent(this);
}
IsOn = on;
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write(isOn);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
SetState(msg.ReadBoolean(), true);
}
}
}
@@ -0,0 +1,56 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class SignalCheckComponent : ItemComponent
{
private string output, falseOutput;
private string targetSignal;
[InGameEditable, HasDefaultValue("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, HasDefaultValue("0", true)]
public string FalseOutput
{
get { return falseOutput; }
set { falseOutput = value; }
}
[InGameEditable, HasDefaultValue("", true)]
public string TargetSignal
{
get { return targetSignal; }
set { targetSignal = value; }
}
public SignalCheckComponent(Item item, XElement element)
: base(item, element)
{
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
switch (connection.Name)
{
case "signal_in":
string signalOut = (signal == targetSignal) ? output : falseOutput;
if (string.IsNullOrWhiteSpace(signalOut)) return;
item.SendSignal(stepsTaken, signalOut, "signal_out", sender);
break;
case "set_output":
output = signal;
break;
case "set_targetsignal":
targetSignal = signal;
break;
}
}
}
}
@@ -0,0 +1,18 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class WaterDetector : ItemComponent
{
public WaterDetector(Item item, XElement element)
: base (item, element)
{
IsActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
item.SendSignal(0, item.InWater ? "1" : "0", "signal_out", null);
}
}
}
@@ -0,0 +1,123 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class WifiComponent : ItemComponent
{
private static List<WifiComponent> list = new List<WifiComponent>();
private float range;
private int channel;
[HasDefaultValue(20000.0f, false)]
public float Range
{
get { return range; }
set { range = Math.Max(value, 0.0f); }
}
[InGameEditable, HasDefaultValue(1, true)]
public int Channel
{
get { return channel; }
set
{
channel = MathHelper.Clamp(value, 0, 10000);
}
}
[Editable, HasDefaultValue(false, false)]
public bool LinkToChat
{
get;
set;
}
public WifiComponent(Item item, XElement element)
: base (item, element)
{
list.Add(this);
}
public bool CanTransmit()
{
return HasRequiredContainedItems(true);
}
/*public void Transmit(string signal)
{
if (!CanTransmit()) return;
var receivers = GetReceiversInRange();
foreach (WifiComponent w in receivers)
{
var connections = w.item.Connections;
w.ReceiveSignal(1, signal, connections == null ? null : connections.Find(c => c.Name == "signal_in"), item, null);
}
}*/
private List<WifiComponent> GetReceiversInRange()
{
return list.FindAll(w => w != this && w.CanReceive(this));
}
public bool CanReceive(WifiComponent sender)
{
if (!HasRequiredContainedItems(false)) return false;
if (sender == null || sender.channel != channel) return false;
return Vector2.Distance(item.WorldPosition, sender.item.WorldPosition) <= sender.Range;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power=0.0f)
{
var senderComponent = source.GetComponent<WifiComponent>();
if (senderComponent != null && !CanReceive(senderComponent)) return;
if (LinkToChat)
{
if (item.ParentInventory != null &&
item.ParentInventory.Owner != null &&
item.ParentInventory.Owner == Character.Controlled &&
GameMain.NetworkMember != null)
{
if (senderComponent != null)
{
signal = ChatMessage.ApplyDistanceEffect(item, sender, signal, senderComponent.range);
}
GameMain.NetworkMember.AddChatMessage(signal, ChatMessageType.Radio);
}
}
if (connection == null) return;
switch (connection.Name)
{
case "signal_in":
var receivers = GetReceiversInRange();
foreach (WifiComponent wifiComp in receivers)
{
wifiComp.item.SendSignal(stepsTaken, signal, "signal_out", sender);
}
break;
}
}
protected override void RemoveComponentSpecific()
{
base.RemoveComponentSpecific();
list.Remove(this);
}
}
}
@@ -0,0 +1,746 @@
using Barotrauma.Networking;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class Wire : ItemComponent, IDrawableComponent, IServerSerializable
{
class WireSection
{
private Vector2 start;
private float angle;
private float length;
public WireSection(Vector2 start, Vector2 end)
{
this.start = start;
angle = MathUtils.VectorToAngle(end - start);
length = Vector2.Distance(start, end);
}
public void Draw(SpriteBatch spriteBatch, Color color, Vector2 offset, float depth, float width = 0.3f)
{
spriteBatch.Draw(wireSprite.Texture,
new Vector2(start.X+offset.X, -(start.Y+offset.Y)), null, color,
-angle,
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
new Vector2(length / wireSprite.Texture.Width, width),
SpriteEffects.None,
depth);
}
public static void Draw(SpriteBatch spriteBatch, Vector2 start, Vector2 end, Color color, float depth, float width = 0.3f)
{
start.Y = -start.Y;
end.Y = -end.Y;
spriteBatch.Draw(wireSprite.Texture,
start, null, color,
MathUtils.VectorToAngle(end - start),
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
new Vector2((Vector2.Distance(start, end)) / wireSprite.Texture.Width, width),
SpriteEffects.None,
depth);
}
}
const float nodeDistance = 32.0f;
const float heightFromFloor = 128.0f;
static Sprite wireSprite;
private List<Vector2> nodes;
private List<WireSection> sections;
Connection[] connections;
private Vector2 newNodePos;
private static Wire draggingWire;
private static int? selectedNodeIndex;
private static int? highlightedNodeIndex;
public bool Hidden, Locked;
public Connection[] Connections
{
get { return connections; }
}
public Wire(Item item, XElement element)
: base(item, element)
{
if (wireSprite == null)
{
wireSprite = new Sprite("Content/Items/wireHorizontal.png", new Vector2(0.5f, 0.5f));
wireSprite.Depth = 0.85f;
}
nodes = new List<Vector2>();
sections = new List<WireSection>();
connections = new Connection[2];
IsActive = false;
}
public Connection OtherConnection(Connection connection)
{
if (connection == null) return null;
if (connection == connections[0]) return connections[1];
if (connection == connections[1]) return connections[0];
return null;
}
public bool IsConnectedTo(Item item)
{
if (connections[0] != null && connections[0].Item == item) return true;
return (connections[1] != null && connections[1].Item == item);
}
public void RemoveConnection(Item item)
{
for (int i = 0; i<2; i++)
{
if (connections[i]==null || connections[i].Item!=item) continue;
for (int n = 0; n< connections[i].Wires.Length; n++)
{
if (connections[i].Wires[n] != this) continue;
connections[i].Wires[n] = null;
}
connections[i] = null;
}
}
public void RemoveConnection(Connection connection)
{
if (connection == connections[0]) connections[0] = null;
if (connection == connections[1]) connections[1] = null;
}
public bool Connect(Connection newConnection, bool addNode = true, bool sendNetworkEvent = false)
{
for (int i = 0; i < 2; i++)
{
if (connections[i] == newConnection) return false;
}
if (!connections.Any(c => c == null)) return false;
for (int i = 0; i < 2; i++)
{
if (connections[i] != null && connections[i].Item == newConnection.Item)
{
addNode = false;
break;
}
}
if (item.body != null) item.Submarine = newConnection.Item.Submarine;
for (int i = 0; i < 2; i++)
{
if (connections[i] != null) continue;
connections[i] = newConnection;
if (!addNode) break;
if (newConnection.Item.Submarine == null) continue;
if (nodes.Count > 0 && nodes[0] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break;
if (nodes.Count > 1 && nodes[nodes.Count-1] == newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition) break;
if (i == 0)
{
nodes.Insert(0, newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition);
}
else
{
nodes.Add(newConnection.Item.Position - newConnection.Item.Submarine.HiddenSubPosition);
}
break;
}
if (connections[0] != null && connections[1] != null)
{
foreach (ItemComponent ic in item.components)
{
if (ic == this) continue;
ic.Drop(null);
}
if (item.Container != null) item.Container.RemoveContained(this.item);
if (item.body != null) item.body.Enabled = false;
IsActive = false;
CleanNodes();
}
if (sendNetworkEvent)
{
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
}
//the wire is active if only one end has been connected
IsActive = connections[0] == null ^ connections[1] == null;
}
Drawable = IsActive || nodes.Any();
UpdateSections();
return true;
}
public override void Equip(Character character)
{
ClearConnections();
IsActive = true;
}
public override void Unequip(Character character)
{
ClearConnections();
IsActive = false;
}
public override void Drop(Character dropper)
{
ClearConnections();
IsActive = false;
}
public override void Update(float deltaTime, Camera cam)
{
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 ((item.Submarine != sub || sub == null) && Screen.Selected != GameMain.EditMapScreen)
{
ClearConnections();
return;
}
newNodePos = RoundNode(item.Position, item.CurrentHull) - sub.HiddenSubPosition;
}
public override bool Use(float deltaTime, Character character = null)
{
if (character == Character.Controlled && character.SelectedConstruction != null) return false;
if (newNodePos!= Vector2.Zero && nodes.Count>0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
{
nodes.Add(newNodePos);
UpdateSections();
Drawable = true;
newNodePos = Vector2.Zero;
}
return true;
}
public override void SecondaryUse(float deltaTime, Character character = null)
{
if (nodes.Count > 1)
{
nodes.RemoveAt(nodes.Count - 1);
UpdateSections();
}
Drawable = IsActive || sections.Count > 0;
}
public override bool Pick(Character picker)
{
ClearConnections();
return true;
}
public override void Move(Vector2 amount)
{
if (item.IsSelected) MoveNodes(amount);
}
public List<Vector2> GetNodes()
{
return new List<Vector2>(nodes);
}
public void SetNodes(List<Vector2> nodes)
{
this.nodes = new List<Vector2>(nodes);
UpdateSections();
}
public void MoveNodes(Vector2 amount)
{
for (int i = 0; i < nodes.Count; i++)
{
nodes[i] += amount;
}
UpdateSections();
}
public void UpdateSections()
{
sections.Clear();
for (int i = 0; i < nodes.Count-1; i++)
{
sections.Add(new WireSection(nodes[i], nodes[i + 1]));
}
Drawable = IsActive || sections.Count > 0;
}
private void ClearConnections()
{
nodes.Clear();
sections.Clear();
for (int i = 0; i < 2; i++)
{
if (connections[i] == null) continue;
int wireIndex = connections[i].FindWireIndex(item);
if (wireIndex == -1) continue;
connections[i].AddLink(wireIndex, null);
connections[i] = null;
}
Drawable = sections.Count > 0;
}
private Vector2 RoundNode(Vector2 position, Hull hull)
{
if (Screen.Selected == GameMain.EditMapScreen)
{
position.X = MathUtils.Round(position.X, Submarine.GridSize.X / 2.0f);
position.Y = MathUtils.Round(position.Y, Submarine.GridSize.Y / 2.0f);
}
else
{
position.X = MathUtils.Round(position.X, nodeDistance);
if (hull == null)
{
position.Y = MathUtils.Round(position.Y, nodeDistance);
}
else
{
position.Y -= hull.Rect.Y - hull.Rect.Height;
position.Y = Math.Max(MathUtils.Round(position.Y, nodeDistance), heightFromFloor);
position.Y += hull.Rect.Y -hull.Rect.Height;
}
}
return position;
}
private void CleanNodes()
{
for (int i = nodes.Count - 2; i > 0; i--)
{
if ((nodes[i - 1].X == nodes[i].X || nodes[i - 1].Y == nodes[i].Y) &&
(nodes[i + 1].X == nodes[i].X || nodes[i + 1].Y == nodes[i].Y))
{
if (Vector2.Distance(nodes[i - 1], nodes[i]) == Vector2.Distance(nodes[i + 1], nodes[i]))
{
nodes.RemoveAt(i);
}
}
}
bool removed;
do
{
removed = false;
for (int i = nodes.Count - 2; i > 0; i--)
{
if ((nodes[i - 1].X == nodes[i].X && nodes[i + 1].X == nodes[i].X)
|| (nodes[i - 1].Y == nodes[i].Y && nodes[i + 1].Y == nodes[i].Y))
{
nodes.RemoveAt(i);
removed = true;
}
}
} while (removed);
}
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (sections.Count == 0 && !IsActive)
{
Drawable = false;
return;
}
Vector2 drawOffset = Vector2.Zero;
if (item.Submarine != null)
{
drawOffset = item.Submarine.DrawPosition + item.Submarine.HiddenSubPosition;
}
float depth = item.IsSelected ? 0.0f : wireSprite.Depth + ((item.ID % 100) * 0.00001f);
if (item.IsHighlighted)
{
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, Color.Gold, drawOffset, depth + 0.00001f, 0.7f);
}
}
else if (item.IsSelected)
{
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, Color.Red, drawOffset, depth + 0.00001f, 0.7f);
}
}
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, item.Color, drawOffset, depth, 0.3f);
}
if (IsActive && nodes.Count > 0 && Vector2.Distance(newNodePos, nodes[nodes.Count - 1]) > nodeDistance)
{
WireSection.Draw(
spriteBatch,
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
item.Color * 0.5f,
depth,
0.3f);
}
if (!editing || !GameMain.EditMapScreen.WiringMode) return;
for (int i = 0; i < nodes.Count; i++)
{
Vector2 drawPos = nodes[i];
if (item.Submarine != null) drawPos += item.Submarine.Position + item.Submarine.HiddenSubPosition;
drawPos.Y = -drawPos.Y;
if (item.IsSelected)
{
GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-5, -5), new Vector2(10, 10), item.Color, true, 0.0f);
if (highlightedNodeIndex == i)
{
GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-10, -10), new Vector2(20, 20), Color.Red, false, 0.0f);
}
}
else
{
GUI.DrawRectangle(spriteBatch, drawPos + new Vector2(-3, -3), new Vector2(6, 6), item.Color, true, 0.0f);
}
}
}
public static void UpdateEditing(List<Wire> wires)
{
//dragging a node of some wire
if (draggingWire != null)
{
//cancel dragging
if (!PlayerInput.LeftButtonHeld())
{
draggingWire = null;
selectedNodeIndex = null;
}
//update dragging
else
{
MapEntity.DisableSelect = true;
Submarine sub = null;
if (draggingWire.connections[0] != null && draggingWire.connections[0].Item.Submarine != null) sub = draggingWire.connections[0].Item.Submarine;
if (draggingWire.connections[1] != null && draggingWire.connections[1].Item.Submarine != null) sub = draggingWire.connections[1].Item.Submarine;
Vector2 nodeWorldPos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition) - sub.HiddenSubPosition - sub.Position;// Nodes[(int)selectedNodeIndex];
nodeWorldPos.X = MathUtils.Round(nodeWorldPos.X, Submarine.GridSize.X / 2.0f);
nodeWorldPos.Y = MathUtils.Round(nodeWorldPos.Y, Submarine.GridSize.Y / 2.0f);
draggingWire.nodes[(int)selectedNodeIndex] = nodeWorldPos;
draggingWire.UpdateSections();
MapEntity.SelectEntity(draggingWire.item);
}
return;
}
//a wire has been selected -> check if we should start dragging one of the nodes
float nodeSelectDist = 10, sectionSelectDist = 5;
highlightedNodeIndex = null;
if (MapEntity.SelectedList.Count == 1 && MapEntity.SelectedList[0] is Item)
{
Wire selectedWire = ((Item)MapEntity.SelectedList[0]).GetComponent<Wire>();
if (selectedWire != null)
{
Vector2 mousePos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
if (selectedWire.item.Submarine != null) mousePos -= (selectedWire.item.Submarine.Position + selectedWire.item.Submarine.HiddenSubPosition);
//left click while holding ctrl -> check if the cursor is on a wire section,
//and add a new node if it is
if (PlayerInput.KeyDown(Keys.RightControl) || PlayerInput.KeyDown(Keys.LeftControl))
{
if (PlayerInput.LeftButtonClicked())
{
float temp = 0.0f;
int closestSectionIndex = selectedWire.GetClosestSectionIndex(mousePos, sectionSelectDist, out temp);
if (closestSectionIndex > -1)
{
selectedWire.nodes.Insert(closestSectionIndex + 1, mousePos);
selectedWire.UpdateSections();
}
}
}
else
{
//check if close enough to a node
float temp = 0.0f;
int closestIndex = selectedWire.GetClosestNodeIndex(mousePos, nodeSelectDist, out temp);
if (closestIndex > -1)
{
highlightedNodeIndex = closestIndex;
//start dragging the node
if (PlayerInput.LeftButtonHeld())
{
draggingWire = selectedWire;
selectedNodeIndex = closestIndex;
}
//remove the node
else if (PlayerInput.RightButtonClicked() && closestIndex > 0 && closestIndex < selectedWire.nodes.Count - 1)
{
selectedWire.nodes.RemoveAt(closestIndex);
selectedWire.UpdateSections();
}
}
}
}
}
//check which wire is highlighted with the cursor
Wire highlighted = null;
float closestDist = 0.0f;
foreach (Wire w in wires)
{
Vector2 mousePos = GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
if (w.item.Submarine != null) mousePos -= (w.item.Submarine.Position + w.item.Submarine.HiddenSubPosition);
float dist = 0.0f;
if (w.GetClosestNodeIndex(mousePos, highlighted == null ? nodeSelectDist : closestDist, out dist) > -1)
{
highlighted = w;
closestDist = dist;
}
if (w.GetClosestSectionIndex(mousePos, highlighted == null ? sectionSelectDist : closestDist, out dist) > -1)
{
highlighted = w;
closestDist = dist;
}
}
if (highlighted != null)
{
highlighted.item.IsHighlighted = true;
if (PlayerInput.LeftButtonClicked())
{
MapEntity.DisableSelect = true;
MapEntity.SelectEntity(highlighted.item);
}
}
}
private int GetClosestNodeIndex(Vector2 pos, float maxDist, out float closestDist)
{
closestDist = 0.0f;
int closestIndex = -1;
for (int i = 0; i < nodes.Count; i++)
{
float dist = Vector2.Distance(nodes[i], pos);
if (dist > maxDist) continue;
if (closestIndex == -1 || dist < closestDist)
{
closestIndex = i;
closestDist = dist;
}
}
return closestIndex;
}
private int GetClosestSectionIndex(Vector2 mousePos, float maxDist, out float closestDist)
{
closestDist = 0.0f;
int closestIndex = -1;
for (int i = 0; i < nodes.Count-1; i++)
{
if ((Math.Abs(nodes[i].X - nodes[i + 1].X)<5 || Math.Sign(mousePos.X - nodes[i].X) != Math.Sign(mousePos.X - nodes[i + 1].X)) &&
(Math.Abs(nodes[i].Y - nodes[i + 1].Y)<5 || Math.Sign(mousePos.Y - nodes[i].Y) != Math.Sign(mousePos.Y - nodes[i + 1].Y)))
{
float dist = MathUtils.LineToPointDistance(nodes[i], nodes[i + 1], mousePos);
if (dist > maxDist) continue;
if (closestIndex == -1 || dist < closestDist)
{
closestIndex = i;
closestDist = dist;
}
}
}
return closestIndex;
}
public override void FlipX()
{
for (int i = 0; i < nodes.Count; i++)
{
nodes[i] = new Vector2(-nodes[i].X, nodes[i].Y);
}
UpdateSections();
}
public override XElement Save(XElement parentElement)
{
XElement componentElement = base.Save(parentElement);
if (nodes == null || nodes.Count == 0) return componentElement;
string[] nodeCoords = new string[nodes.Count * 2];
for (int i = 0; i < nodes.Count; i++)
{
nodeCoords[i * 2] = nodes[i].X.ToString(CultureInfo.InvariantCulture);
nodeCoords[i * 2 + 1] = nodes[i].Y.ToString(CultureInfo.InvariantCulture);
}
componentElement.Add(new XAttribute("nodes", string.Join(";", nodeCoords)));
return componentElement;
}
public override void Load(XElement componentElement)
{
base.Load(componentElement);
string nodeString = ToolBox.GetAttributeString(componentElement, "nodes", "");
if (nodeString == "") return;
string[] nodeCoords = nodeString.Split(';');
for (int i = 0; i < nodeCoords.Length / 2; i++)
{
float x = 0.0f, y = 0.0f;
try
{
x = float.Parse(nodeCoords[i * 2], CultureInfo.InvariantCulture);
}
catch { x = 0.0f; }
try
{
y = float.Parse(nodeCoords[i * 2 + 1], CultureInfo.InvariantCulture);
}
catch { y = 0.0f; }
nodes.Add(new Vector2(x, y));
}
Drawable = nodes.Any();
}
protected override void ShallowRemoveComponentSpecific()
{
for (int i = 0; i < 2; i++)
{
if (connections[i] == null) continue;
int wireIndex = connections[i].FindWireIndex(item);
if (wireIndex > -1)
{
connections[i].AddLink(wireIndex, null);
}
}
}
protected override void RemoveComponentSpecific()
{
ClearConnections();
base.RemoveComponentSpecific();
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.Write((byte)Math.Min(nodes.Count, 255));
for (int i = 0; i < Math.Min(nodes.Count, 255); i++)
{
msg.Write(nodes[i].X);
msg.Write(nodes[i].Y);
}
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
nodes.Clear();
int nodeCount = msg.ReadByte();
Vector2[] nodePositions = new Vector2[nodeCount];
for (int i = 0; i < nodeCount; i++)
{
nodePositions[i] = new Vector2(msg.ReadFloat(), msg.ReadFloat());
}
if (nodePositions.Any(n => !MathUtils.IsValid(n))) return;
nodes = nodePositions.ToList();
UpdateSections();
Drawable = nodes.Any();
}
}
}