First commit
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class ItemContainer : ItemComponent
|
||||
{
|
||||
List<RelatedItem> containableItems;
|
||||
public ItemInventory inventory;
|
||||
|
||||
//how many items can be contained
|
||||
private int capacity;
|
||||
|
||||
private bool hideItems;
|
||||
private bool drawInventory;
|
||||
|
||||
//the position of the first item in the container
|
||||
private Vector2 itemPos;
|
||||
|
||||
//item[i].Pos = itemPos + itemInterval*i
|
||||
private Vector2 itemInterval;
|
||||
|
||||
private float itemRotation;
|
||||
|
||||
[HasDefaultValue(5, false)]
|
||||
public int Capacity
|
||||
{
|
||||
get { return capacity; }
|
||||
set { capacity = Math.Max(value, 1); }
|
||||
}
|
||||
|
||||
[HasDefaultValue(true, false)]
|
||||
public bool HideItems
|
||||
{
|
||||
get { return hideItems; }
|
||||
set { hideItems = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool DrawInventory
|
||||
{
|
||||
get { return drawInventory; }
|
||||
set { drawInventory = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(0.0f, false)]
|
||||
public float ItemRotation
|
||||
{
|
||||
get { return itemRotation; }
|
||||
set { itemRotation = value; }
|
||||
}
|
||||
|
||||
//[Initable(Vector2.Zero)]
|
||||
//private Vector2 ItemPos
|
||||
//{
|
||||
// set { itemPos = ConvertUnits.ToSimUnits(value); }
|
||||
//}
|
||||
|
||||
//[Initable(Vector2.Zero)]
|
||||
//private Vector2 ItemInterval
|
||||
//{
|
||||
// set { itemInterval = ConvertUnits.ToSimUnits(value); }
|
||||
//}
|
||||
|
||||
public ItemContainer(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
inventory = new ItemInventory(this, capacity);
|
||||
containableItems = new List<RelatedItem>();
|
||||
|
||||
itemPos = ToolBox.GetAttributeVector2(element, "ItemPos", Vector2.Zero);
|
||||
itemPos = ConvertUnits.ToSimUnits(itemPos);
|
||||
|
||||
itemInterval = ToolBox.GetAttributeVector2(element, "ItemInterval", Vector2.Zero);
|
||||
itemInterval = ConvertUnits.ToSimUnits(itemInterval);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
{
|
||||
case "containable":
|
||||
RelatedItem containable = RelatedItem.Load(subElement);
|
||||
if (containable!=null) containableItems.Add(containable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveContained(Item item)
|
||||
{
|
||||
inventory.RemoveItem(item);
|
||||
}
|
||||
|
||||
public bool CanBeContained(Item item)
|
||||
{
|
||||
return (containableItems.Find(x => x.MatchesItem(item)) != null);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
foreach (Item contained in inventory.items)
|
||||
{
|
||||
if (contained == null) continue;
|
||||
|
||||
if (contained.body!=null) contained.body.Enabled = !hideItems;
|
||||
|
||||
RelatedItem ri = containableItems.Find(x => x.MatchesItem(item));
|
||||
if (ri == null) continue;
|
||||
|
||||
foreach (StatusEffect effect in ri.statusEffects)
|
||||
{
|
||||
if (effect.Targets.HasFlag(StatusEffect.Target.This)) effect.Apply(ActionType.OnContaining, deltaTime, item);
|
||||
if (effect.Targets.HasFlag(StatusEffect.Target.Contained)) effect.Apply(ActionType.OnContaining, deltaTime, contained);
|
||||
}
|
||||
|
||||
contained.ApplyStatusEffects(ActionType.OnContained, deltaTime);
|
||||
}
|
||||
|
||||
if (hideItems) return;
|
||||
|
||||
Vector2 transformedItemPos;
|
||||
Vector2 transformedItemInterval = itemInterval;
|
||||
//float transformedItemRotation = itemRotation;
|
||||
if (item.body==null)
|
||||
{
|
||||
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
|
||||
transformedItemPos = ConvertUnits.ToSimUnits(transformedItemPos) + itemPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
|
||||
transformedItemPos = Vector2.Transform(item.body.Position + itemPos, transform);
|
||||
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
|
||||
//transformedItemRotation += item.body.Rotation;
|
||||
}
|
||||
|
||||
foreach (Item containedItem in inventory.items)
|
||||
{
|
||||
if (containedItem == null) continue;
|
||||
|
||||
Vector2 itemDist = (transformedItemPos - containedItem.body.Position);
|
||||
Vector2 force = (itemDist - containedItem.body.LinearVelocity * 0.1f) * containedItem.body.Mass * 60.0f;
|
||||
|
||||
containedItem.body.ApplyForce(force);
|
||||
|
||||
containedItem.body.SmoothRotate(itemRotation);
|
||||
|
||||
transformedItemPos += transformedItemInterval;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (!drawInventory && false) return;
|
||||
|
||||
inventory.Draw(spriteBatch);
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
//picker.SelectedConstruction = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public override bool Combine(Item item)
|
||||
{
|
||||
if (containableItems.Find(x => x.MatchesItem(item)) == null) return false;
|
||||
|
||||
if (inventory.TryPutItem(item))
|
||||
{
|
||||
isActive = true;
|
||||
if (hideItems) item.body.Enabled = false;
|
||||
|
||||
item.container = this.item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
for (int i = 0; i < itemIds.Length; i++)
|
||||
{
|
||||
Item item = MapEntity.FindEntityByID(itemIds[i]) as Item;
|
||||
if (item == null) continue;
|
||||
|
||||
inventory.TryPutItem(item, i, false);
|
||||
}
|
||||
|
||||
itemIds = null;
|
||||
}
|
||||
|
||||
public override void Load(XElement componentElement)
|
||||
{
|
||||
base.Load(componentElement);
|
||||
|
||||
string containedString = ToolBox.GetAttributeString(componentElement, "contained", "");
|
||||
|
||||
string[] itemIdStrings = containedString.Split(',');
|
||||
|
||||
itemIds = new int[itemIdStrings.Length];
|
||||
for (int i = 0; i < itemIdStrings.Length; i++)
|
||||
{
|
||||
int id = -1;
|
||||
if (!int.TryParse(itemIdStrings[i], out id)) continue;
|
||||
|
||||
itemIds[i] = id;
|
||||
}
|
||||
}
|
||||
|
||||
int[] itemIds;
|
||||
|
||||
public override XElement Save(XElement parentElement)
|
||||
{
|
||||
XElement componentElement = base.Save(parentElement);
|
||||
|
||||
string[] itemIdStrings = new string[inventory.items.Length];
|
||||
for (int i = 0; i < inventory.items.Length; i++)
|
||||
{
|
||||
itemIdStrings[i] = (inventory.items[i]==null) ? "-1" : inventory.items[i].ID.ToString();
|
||||
}
|
||||
|
||||
componentElement.Add(new XAttribute("contained", string.Join(",",itemIdStrings)));
|
||||
|
||||
return componentElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
struct LimbPos
|
||||
{
|
||||
public LimbType limbType;
|
||||
public Vector2 position;
|
||||
}
|
||||
|
||||
class Controller : ItemComponent
|
||||
{
|
||||
//where the limbs of the user should be positioned when using the controller
|
||||
List<LimbPos> limbPositions;
|
||||
|
||||
Direction dir;
|
||||
|
||||
//the x-position where the user walks to when using the controller
|
||||
float userPos;
|
||||
|
||||
Character character;
|
||||
|
||||
[HasDefaultValue(1.0f,false)]
|
||||
public float UserPos
|
||||
{
|
||||
set { userPos = value; }
|
||||
}
|
||||
|
||||
public Controller(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
limbPositions = new List<LimbPos>();
|
||||
|
||||
dir = (Direction)Enum.Parse(typeof(Direction), ToolBox.GetAttributeString(element, "direction", "None"), true);
|
||||
|
||||
//userPos = ToolBox.GetAttributeInt(element, "userpos", 1);
|
||||
|
||||
//string allowedIdString = ToolBox.GetAttributeString(element, "allowedids", "");
|
||||
//if (allowedIdString!="")
|
||||
//{
|
||||
// string[] splitIds = allowedIdString.Split(',');
|
||||
// allowedIDs = new string[splitIds.Length];
|
||||
// for (int i = 0; i<splitIds.Length; i++)
|
||||
// {
|
||||
// allowedIDs[i] = allowedIDs[i].Trim();
|
||||
// }
|
||||
//}
|
||||
|
||||
foreach (XElement el in element.Elements())
|
||||
{
|
||||
if (el.Name != "limbposition") continue;
|
||||
|
||||
LimbPos lp = new LimbPos();
|
||||
try
|
||||
{
|
||||
lp.limbType = (LimbType)Enum.Parse(typeof(LimbType), el.Attribute("limb").Value, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + element + ": " + e.Message, e);
|
||||
}
|
||||
|
||||
lp.position = ToolBox.GetAttributeVector2(el, "position", Vector2.Zero);
|
||||
|
||||
limbPositions.Add(lp);
|
||||
}
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (character == null || character.SelectedConstruction != item)
|
||||
{
|
||||
if (character != null)
|
||||
{
|
||||
character.SelectedConstruction = null;
|
||||
character.animController.anim = AnimController.Animation.None;
|
||||
character = null;
|
||||
}
|
||||
isActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, character);
|
||||
|
||||
if (userPos != 0.0f && character.animController.anim != AnimController.Animation.UsingConstruction)
|
||||
{
|
||||
Limb torso = character.animController.GetLimb(LimbType.Torso);
|
||||
float torsoX = ConvertUnits.ToDisplayUnits(torso.SimPosition.X);
|
||||
|
||||
if (Math.Abs(torsoX - item.Rect.X + userPos) > 10.0f)
|
||||
{
|
||||
character.animController.anim = AnimController.Animation.None;
|
||||
|
||||
character.animController.TargetMovement =
|
||||
new Vector2(
|
||||
Math.Min(Math.Max(item.Rect.X + userPos - torsoX, -1.0f), 1.0f),
|
||||
0.0f);
|
||||
character.animController.targetDir = (Math.Sign(torsoX - item.Rect.X + userPos) == 1) ? Direction.Right : Direction.Left;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (limbPositions.Count == 0) return;
|
||||
|
||||
character.animController.anim = AnimController.Animation.UsingConstruction;
|
||||
character.animController.ResetPullJoints();
|
||||
if (dir != 0) character.animController.targetDir = dir;
|
||||
|
||||
foreach (LimbPos lb in limbPositions)
|
||||
{
|
||||
Limb limb = character.animController.GetLimb(lb.limbType);
|
||||
if (limb == null) continue;
|
||||
|
||||
FixedMouseJoint fmj = limb.pullJoint;
|
||||
if (fmj == null) continue;
|
||||
|
||||
Vector2 position = ConvertUnits.ToSimUnits(lb.position + new Vector2(item.Rect.X, item.Rect.Y));
|
||||
fmj.Enabled = true;
|
||||
fmj.WorldAnchorB = position;
|
||||
}
|
||||
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item linkedItem = e as Item;
|
||||
if (linkedItem == null) continue;
|
||||
linkedItem.Update(cam, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Use(Character activator = null)
|
||||
{
|
||||
character = activator;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item linkedItem = e as Item;
|
||||
if (linkedItem == null) continue;
|
||||
linkedItem.Use(activator);
|
||||
}
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, character);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SecondaryUse(Character character = null)
|
||||
{
|
||||
if (character == null) return;
|
||||
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item linkedItem = e as Item;
|
||||
if (linkedItem == null) continue;
|
||||
linkedItem.SecondaryUse(character);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Pick(Character activator = null)
|
||||
{
|
||||
if (character!=null && character.SelectedConstruction == item)
|
||||
{
|
||||
character = null;
|
||||
isActive = false;
|
||||
if (activator != null) activator.animController.anim = AnimController.Animation.None;
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
character = activator;
|
||||
if (activator == null) return false;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
item.SendSignal("1", "signal_out");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Factories;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Subsurface.Lights;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Door : ItemComponent
|
||||
{
|
||||
Gap linkedGap;
|
||||
|
||||
Rectangle window;
|
||||
|
||||
ConvexHull convexHull;
|
||||
ConvexHull convexHull2;
|
||||
|
||||
Gap LinkedGap
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linkedGap != null) return linkedGap;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
linkedGap = e as Gap;
|
||||
if (linkedGap != null) return linkedGap;
|
||||
}
|
||||
linkedGap = new Gap(item.Rect);
|
||||
linkedGap.Open = openState;
|
||||
item.linkedTo.Add(linkedGap);
|
||||
return linkedGap;
|
||||
}
|
||||
}
|
||||
|
||||
bool isOpen;
|
||||
float openState;
|
||||
|
||||
[HasDefaultValue("0.0,0.0,0.0,0.0", false)]
|
||||
public string Window
|
||||
{
|
||||
get { return ToolBox.Vector4ToString(new Vector4(window.X, window.Y, window.Width, window.Height)); }
|
||||
set
|
||||
{
|
||||
Vector4 vector = ToolBox.ParseToVector4(value);
|
||||
if (vector.Z!=0.0f || vector.W !=0.0f)
|
||||
{
|
||||
window = new Rectangle((int)vector.X, (int)vector.Y, (int)vector.Z, (int)vector.W);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Editable, HasDefaultValue(false, true)]
|
||||
public bool IsOpen
|
||||
{
|
||||
get { return isOpen; }
|
||||
set
|
||||
{
|
||||
isOpen = value;
|
||||
openState = (isOpen) ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public float OpenState
|
||||
{
|
||||
get { return openState; }
|
||||
set
|
||||
{
|
||||
if (openState == value) return;
|
||||
openState = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
|
||||
|
||||
|
||||
if (window==null)
|
||||
{
|
||||
Rectangle rect = item.Rect;
|
||||
rect.Height = (int)(rect.Height * (1.0f - openState));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Rectangle rect = item.Rect;
|
||||
//rect.Height = (int)(rect.Height * (1.0f - openState));
|
||||
|
||||
Rectangle rect1 = item.Rect;
|
||||
rect1.Height = -window.Y;
|
||||
|
||||
rect1.Y += (int)(item.Rect.Height * openState);
|
||||
rect1.Height = Math.Max(rect1.Height - (rect1.Y - item.Rect.Y), 0);
|
||||
rect1.Y = Math.Min(item.Rect.Y, rect1.Y);
|
||||
|
||||
Rectangle rect2 = item.Rect;
|
||||
rect2.Y = rect2.Y + window.Y - window.Height;
|
||||
|
||||
rect2.Y += (int)(item.Rect.Height * openState);
|
||||
//rect2.Height = Math.Max(rect2.Height - (rect2.Y - item.Rect.Y), 0);
|
||||
rect2.Y = Math.Min(item.Rect.Y, rect2.Y);
|
||||
rect2.Height = rect2.Y - (item.Rect.Y - (int)(item.Rect.Height * (1.0f - openState)));
|
||||
|
||||
convexHull.SetVertices(GetConvexHullCorners(rect1));
|
||||
if (convexHull2!=null) convexHull2.SetVertices(GetConvexHullCorners(rect2));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
PhysicsBody body;
|
||||
|
||||
Sprite doorSprite;
|
||||
|
||||
public Door(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//Vector2 position = new Vector2(newRect.X, newRect.Y);
|
||||
|
||||
// isOpen = false;
|
||||
|
||||
body = new PhysicsBody(BodyFactory.CreateRectangle(Game1.world,
|
||||
ConvertUnits.ToSimUnits(Math.Max(item.Rect.Width, 1)),
|
||||
ConvertUnits.ToSimUnits(Math.Max(item.Rect.Height, 1)),
|
||||
1.5f));
|
||||
|
||||
body.BodyType = BodyType.Static;
|
||||
body.SetTransform(
|
||||
ConvertUnits.ToSimUnits(new Vector2(item.Rect.X + item.Rect.Width / 2, item.Rect.Y - item.Rect.Height / 2)),
|
||||
0.0f);
|
||||
body.Friction = 0.5f;
|
||||
|
||||
|
||||
//string spritePath = Path.GetDirectoryName(item.Prefab.ConfigFile) + "\\"+ ToolBox.GetAttributeString(element, "sprite", "");
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLower() != "sprite") continue;
|
||||
doorSprite = new Sprite(subElement, Path.GetDirectoryName(item.Prefab.ConfigFile));
|
||||
break;
|
||||
}
|
||||
|
||||
isActive = true;
|
||||
|
||||
Vector2[] corners = GetConvexHullCorners(item.Rect);
|
||||
|
||||
convexHull = new ConvexHull(corners, Color.Black);
|
||||
if (window!=null) convexHull2 = new ConvexHull(corners, Color.Black);
|
||||
|
||||
OpenState = openState;
|
||||
//powerConsumption = -100.0f;
|
||||
|
||||
//LinkedGap.Open = openState;
|
||||
}
|
||||
|
||||
private Vector2[] GetConvexHullCorners(Rectangle rect)
|
||||
{
|
||||
Vector2[] corners = new Vector2[4];
|
||||
corners[0] = new Vector2(rect.X, rect.Y - rect.Height);
|
||||
corners[1] = new Vector2(rect.X, rect.Y);
|
||||
corners[2] = new Vector2(rect.Right, rect.Y);
|
||||
corners[3] = new Vector2(rect.Right, rect.Y - rect.Height);
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
base.Move(amount);
|
||||
|
||||
body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f);
|
||||
|
||||
convexHull.Move(amount);
|
||||
}
|
||||
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
isActive = true;
|
||||
isOpen = !isOpen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
OpenState += deltaTime * ((isOpen) ? 3.0f : -3.0f);
|
||||
|
||||
item.SendSignal((isOpen) ? "1" : "0", "state_out");
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
|
||||
LinkedGap.Open = openState;
|
||||
|
||||
Color color = (item.IsSelected) ? Color.Green : Color.White;
|
||||
|
||||
//prefab.sprite.Draw(spriteBatch, new Vector2(rect.X, -rect.Y), new Vector2(rect.Width, rect.Height), color);
|
||||
|
||||
if (openState == 1.0f)
|
||||
{
|
||||
body.Enabled = false;
|
||||
convexHull.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, new Vector2(item.Rect.Center.X, -item.Rect.Y),
|
||||
new Rectangle(0, (int)(doorSprite.size.Y * openState),
|
||||
(int)doorSprite.size.X, (int)(doorSprite.size.Y * (1.0f - openState))),
|
||||
color, 0.0f, doorSprite.Origin, 1.0f, SpriteEffects.None, doorSprite.Depth);
|
||||
|
||||
convexHull.Enabled = true;
|
||||
|
||||
if (openState == 0.0f)
|
||||
{
|
||||
body.Enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
//push characters out of the doorway when the door is closing/opening
|
||||
Vector2 simPos = ConvertUnits.ToSimUnits(new Vector2(item.Rect.X, item.Rect.Y));
|
||||
Vector2 simSize = ConvertUnits.ToSimUnits(new Vector2(item.Rect.Width,
|
||||
item.Rect.Height * (1.0f - openState)));
|
||||
|
||||
foreach (Character c in Character.characterList)
|
||||
{
|
||||
int dir = Math.Sign(c.animController.limbs[0].SimPosition.X - simPos.X);
|
||||
foreach (Limb l in c.animController.limbs)
|
||||
{
|
||||
if (l.SimPosition.Y < simPos.Y || l.SimPosition.Y > simPos.Y - simSize.Y) continue;
|
||||
if (Math.Abs(l.SimPosition.X - simPos.X) > simSize.X * 2.0f) continue;
|
||||
|
||||
l.body.ApplyForce(new Vector2(dir * 10.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
Game1.world.RemoveBody(body.FarseerBody);
|
||||
|
||||
doorSprite.Remove();
|
||||
|
||||
convexHull.Remove();
|
||||
if (convexHull2 != null) convexHull2.Remove();
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
isActive = true;
|
||||
if (connection.name=="toggle")
|
||||
{
|
||||
isOpen = !isOpen;
|
||||
}
|
||||
else if (connection.name == "set_state")
|
||||
{
|
||||
isOpen = (signal!="0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Holdable : ItemComponent
|
||||
{
|
||||
//the position(s) in the item that the character grabs
|
||||
protected Vector2[] handlePos;
|
||||
|
||||
protected Character picker;
|
||||
|
||||
//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;
|
||||
private bool attached;
|
||||
private PhysicsBody body;
|
||||
|
||||
//the angle in which the character holds the item
|
||||
protected float holdAngle;
|
||||
|
||||
[HasDefaultValue(false, true)]
|
||||
public bool Attached
|
||||
{
|
||||
get { return attached; }
|
||||
set { attached = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool Aimable
|
||||
{
|
||||
get { return aimable; }
|
||||
set { aimable = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool Attachable
|
||||
{
|
||||
get { return attachable; }
|
||||
set { attachable = 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)]
|
||||
private 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]);
|
||||
}
|
||||
|
||||
//holdAngle = ToolBox.GetAttributeFloat(element, "holdangle", 0.0f);
|
||||
//holdAngle = MathHelper.ToRadians(holdAngle);
|
||||
}
|
||||
|
||||
//public override void Equip(Character picker)
|
||||
//{
|
||||
// if (picker == null) return;
|
||||
// if (picker.Inventory == null) return;
|
||||
|
||||
// this.picker = picker;
|
||||
|
||||
// for (int i = item.linkedTo.Count - 1; i >= 0; i--)
|
||||
// item.linkedTo[i].RemoveLinked((MapEntity)item);
|
||||
// item.linkedTo.Clear();
|
||||
|
||||
// System.Diagnostics.Debug.WriteLine("picked item");
|
||||
|
||||
// //this.picker = picker;
|
||||
// picker.SelectedItem = item;
|
||||
|
||||
// isActive = true;
|
||||
//}
|
||||
|
||||
public override void Drop(Character dropper)
|
||||
{
|
||||
if (picker == null)
|
||||
{
|
||||
if (dropper==null) return;
|
||||
picker = dropper;
|
||||
}
|
||||
if (picker.Inventory == null) return;
|
||||
|
||||
item.body.Enabled = true;
|
||||
isActive = false;
|
||||
|
||||
//item.Unequip();
|
||||
|
||||
picker.DeselectItem(item);
|
||||
picker.Inventory.RemoveItem(item);
|
||||
picker = null;
|
||||
}
|
||||
|
||||
public override void Equip(Character character)
|
||||
{
|
||||
picker = character;
|
||||
|
||||
if (!item.body.Enabled)
|
||||
{
|
||||
Limb rightHand = picker.animController.GetLimb(LimbType.RightHand);
|
||||
item.SetTransform(rightHand.SimPosition, 0.0f);
|
||||
}
|
||||
|
||||
if (picker.TrySelectItem(item))
|
||||
{
|
||||
item.body.Enabled = true;
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Unequip(Character character)
|
||||
{
|
||||
if (picker == null) return;
|
||||
|
||||
picker.DeselectItem(item);
|
||||
|
||||
item.body.Enabled = false;
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (!attachable) return false;
|
||||
|
||||
//if (item.body==null)
|
||||
//{
|
||||
// DebugConsole.ThrowError("Item " + item + " must have a physics body component to be attachable!");
|
||||
// return false;
|
||||
//}
|
||||
|
||||
item.body = body;
|
||||
item.body.Enabled = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (!attachable || item.body==null) return false;
|
||||
|
||||
item.Drop();
|
||||
item.body.Enabled = false;
|
||||
item.body = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//if (picker == null)// || picker.animController.selectedItem != item)
|
||||
//{
|
||||
// System.Diagnostics.Debug.WriteLine("drop");
|
||||
// //picker = null;
|
||||
// isActive = false;
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (!item.body.Enabled) return;
|
||||
if (!picker.HasSelectedItem(item)) isActive = false;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
|
||||
|
||||
if (item.body.Dir != picker.animController.Dir) Flip(item);
|
||||
|
||||
AnimController ac = picker.animController;
|
||||
|
||||
ac.HoldItem(deltaTime, cam, item, handlePos, holdPos, aimPos, 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()
|
||||
{
|
||||
if (attached) Use();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Subsurface.Networking;
|
||||
using Subsurface.Items.Components;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
struct ItemSound
|
||||
{
|
||||
public readonly byte index;
|
||||
public readonly ActionType type;
|
||||
|
||||
public readonly float range;
|
||||
|
||||
public ItemSound(int index, ActionType type, float range)
|
||||
{
|
||||
this.index = (byte)index;
|
||||
this.type = type;
|
||||
this.range = range;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The base class for components holding the different functionalities of the item
|
||||
/// </summary>
|
||||
class ItemComponent : IPropertyObject
|
||||
{
|
||||
protected Item item;
|
||||
|
||||
protected string name;
|
||||
|
||||
protected bool isActive;
|
||||
|
||||
protected bool characterUsable;
|
||||
|
||||
protected bool canBePicked;
|
||||
protected bool canBeSelected;
|
||||
|
||||
public List<StatusEffect> statusEffects;
|
||||
|
||||
protected bool updated;
|
||||
|
||||
public List<RelatedItem> requiredItems;
|
||||
|
||||
private List<ItemSound> sounds;
|
||||
|
||||
public readonly Dictionary<string, ObjectProperty> properties;
|
||||
public Dictionary<string, ObjectProperty> ObjectProperties
|
||||
{
|
||||
get { return properties; }
|
||||
}
|
||||
//has the component already been updated this frame
|
||||
public bool Updated
|
||||
{
|
||||
get { return updated; }
|
||||
set { updated = value; }
|
||||
}
|
||||
|
||||
public virtual bool IsActive
|
||||
{
|
||||
get { return isActive; }
|
||||
set { isActive = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool CanBePicked
|
||||
{
|
||||
get { return canBePicked; }
|
||||
set { canBePicked = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool CanBeSelected
|
||||
{
|
||||
get { return canBeSelected; }
|
||||
set { canBeSelected = value; }
|
||||
}
|
||||
|
||||
public Item Item
|
||||
{
|
||||
get { return item; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
[HasDefaultValue("", false)]
|
||||
public string Msg
|
||||
{
|
||||
get { return msg; }
|
||||
set { msg = value; }
|
||||
}
|
||||
|
||||
private string msg;
|
||||
|
||||
public ItemComponent(Item item, XElement element)
|
||||
{
|
||||
this.item = item;
|
||||
|
||||
properties = ObjectProperty.GetProperties(this);
|
||||
|
||||
//canBePicked = ToolBox.GetAttributeBool(element, "canbepicked", false);
|
||||
//canBeSelected = ToolBox.GetAttributeBool(element, "canbeselected", false);
|
||||
|
||||
//msg = ToolBox.GetAttributeString(element, "msg", "");
|
||||
|
||||
requiredItems = new List<RelatedItem>();
|
||||
|
||||
sounds = new List<ItemSound>();
|
||||
|
||||
statusEffects = new List<StatusEffect>();
|
||||
|
||||
//var initableProperties = ObjectProperty.GetProperties<Initable>(this);
|
||||
//foreach (ObjectProperty initableProperty in initableProperties)
|
||||
//{
|
||||
// object value = ToolBox.GetAttributeObject(element, initableProperty.Name.ToLower());
|
||||
// if (value==null)
|
||||
// {
|
||||
// foreach (var ini in initableProperty.Attributes.OfType<Initable>())
|
||||
// {
|
||||
// value = ini.defaultValue;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// initableProperty.TrySetValue(value);
|
||||
//}
|
||||
|
||||
|
||||
properties = ObjectProperty.InitProperties(this, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
{
|
||||
case "requireditem":
|
||||
RelatedItem ri = RelatedItem.Load(subElement);
|
||||
if (ri != null) requiredItems.Add(ri);
|
||||
break;
|
||||
case "statuseffect":
|
||||
statusEffects.Add(StatusEffect.Load(subElement));
|
||||
break;
|
||||
case "sound":
|
||||
string filePath = ToolBox.GetAttributeString(subElement, "path", "");
|
||||
if (filePath=="") continue;
|
||||
|
||||
int index = item.Prefab.sounds.FindIndex(x => x.FilePath == filePath);
|
||||
|
||||
ActionType type;
|
||||
|
||||
try
|
||||
{
|
||||
type = (ActionType)Enum.Parse(typeof(ActionType), ToolBox.GetAttributeString(subElement, "type", ""), true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid sound type in "+subElement+"!", e);
|
||||
break;
|
||||
}
|
||||
|
||||
float range = ToolBox.GetAttributeFloat(subElement, "range", 800.0f);
|
||||
|
||||
sounds.Add(new ItemSound(index, type, range));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//public List<ObjectProperty> GetProperties<T>()
|
||||
//{
|
||||
// List<ObjectProperty> editableProperties = new List<ObjectProperty>();
|
||||
|
||||
// foreach (var property in properties.Values)
|
||||
// {
|
||||
// if (property.Attributes.OfType<T>().Count() > 0) editableProperties.Add(property);
|
||||
// }
|
||||
|
||||
// return editableProperties;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
private int loopingSoundIndex;
|
||||
|
||||
|
||||
public void PlaySound(ActionType type, float volume, Vector2 position, bool loop=false)
|
||||
{
|
||||
|
||||
if (!loop)
|
||||
{
|
||||
List<ItemSound> matchingSounds = sounds.FindAll(x=> x.type == type);
|
||||
|
||||
if (matchingSounds.Count == 0 || item.Prefab.sounds.Count == 0) return;
|
||||
|
||||
int index = Game1.localRandom.Next(Math.Min(matchingSounds.Count,item.Prefab.sounds.Count));
|
||||
|
||||
Sound sound = item.Prefab.sounds[matchingSounds[index].index];
|
||||
|
||||
sound.Play(volume, matchingSounds[index].range, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
//todo: get rid of copypaste
|
||||
if (!Sounds.SoundManager.IsPlaying(loopingSoundIndex))
|
||||
{
|
||||
List<ItemSound> matchingSounds = sounds.FindAll(x => x.type == type);
|
||||
|
||||
if (matchingSounds.Count == 0 || item.Prefab.sounds.Count == 0) return;
|
||||
|
||||
int index = Game1.localRandom.Next(Math.Min(matchingSounds.Count, item.Prefab.sounds.Count));
|
||||
|
||||
Sound sound = item.Prefab.sounds[matchingSounds[index].index];
|
||||
|
||||
loopingSoundIndex = sound.Loop(loopingSoundIndex, volume, position, matchingSounds[index].range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Move(Vector2 amount) { }
|
||||
|
||||
/// <summary>a character has picked the item</summary>
|
||||
public virtual bool Pick(Character picker)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>a character has dropped the item</summary>
|
||||
public virtual void Drop(Character dropper) { }
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch) { }
|
||||
|
||||
public virtual void DrawHUD(SpriteBatch spriteBatch, Character character) { }
|
||||
|
||||
/// <summary>
|
||||
/// a construction has activated the item (such as a turret shooting a projectile)
|
||||
/// call the Activate-methods of the components</summary>
|
||||
/// <param name="c"> The construction which activated the item</param>
|
||||
/// <param name="modifier"> A vector that can be used to pass additional information to the components</param>
|
||||
public virtual void ItemActivate(Item item, Vector2 modifier) { }
|
||||
|
||||
//called when isActive is true and condition > 0.0f
|
||||
public virtual void Update(float deltaTime, Camera cam) { }
|
||||
|
||||
//called when isActive is true and condition == 0.0f
|
||||
public virtual void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
if (loopingSoundIndex <= 0) return;
|
||||
|
||||
if (Sounds.SoundManager.IsPlaying(loopingSoundIndex))
|
||||
{
|
||||
Sounds.SoundManager.Stop(loopingSoundIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//called when the item is equipped and left mouse button is pressed
|
||||
//returns true if the item was used succesfully (not out of ammo, reloading, etc)
|
||||
public virtual bool Use(Character character = null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//called when the item is equipped and right mouse button is pressed
|
||||
public virtual void SecondaryUse(Character character = null) { }
|
||||
|
||||
//called when the item is placed in a "limbslot"
|
||||
public virtual void Equip(Character character) { }
|
||||
|
||||
//called then the item is dropped or dragged out of a "limbslot"
|
||||
public virtual void Unequip(Character character) { }
|
||||
|
||||
public virtual bool UseOtherItem(Item item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void ReceiveSignal(string signal, Connection connection, Item sender) { }
|
||||
|
||||
public virtual bool Combine(Item item)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void Remove() { }
|
||||
|
||||
public bool HasRequiredContainedItems(bool addMessage)
|
||||
{
|
||||
if (requiredItems.Count() == 0) return true;
|
||||
|
||||
Item[] containedItems = item.ContainedItems;
|
||||
if (containedItems == null || containedItems.Count() == 0) return false;
|
||||
|
||||
foreach (RelatedItem ri in requiredItems)
|
||||
{
|
||||
if (ri.Type != RelatedItem.RelationType.Contained) continue;
|
||||
Item containedItem = Array.Find(containedItems, x => x != null && x.Condition > 0.0f && ri.MatchesItem(x));
|
||||
if (containedItem == null)
|
||||
{
|
||||
//if (addMessage && !String.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool HasRequiredEquippedItems(Character character, bool addMessage)
|
||||
{
|
||||
if (requiredItems.Count() == 0) return true;
|
||||
|
||||
foreach (RelatedItem ri in requiredItems)
|
||||
{
|
||||
if (ri.Type == RelatedItem.RelationType.Equipped)
|
||||
{
|
||||
for (int i = 0; i < character.SelectedItems.Length; i++ )
|
||||
{
|
||||
Item selectedItem = character.SelectedItems[i];
|
||||
if (selectedItem !=null && selectedItem.Condition>0.0f && ri.MatchesItem(selectedItem ))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//if (addMessage && !String.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
return false;
|
||||
}
|
||||
else if (ri.Type == RelatedItem.RelationType.Picked)
|
||||
{
|
||||
Item pickedItem = character.Inventory.items.FirstOrDefault(x => x!=null && x.Condition>0.0f && ri.MatchesItem(x));
|
||||
if (pickedItem == null)
|
||||
{
|
||||
//if (addMessage && !String.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb limb = null)
|
||||
{
|
||||
foreach (StatusEffect effect in statusEffects)
|
||||
{
|
||||
if (effect.type != type) continue;
|
||||
item.ApplyStatusEffect(effect, type, deltaTime, character, limb);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual XElement Save(XElement parentElement)
|
||||
{
|
||||
XElement componentElement = new XElement(name);
|
||||
|
||||
foreach (RelatedItem ri in requiredItems)
|
||||
{
|
||||
XElement newElement = new XElement("requireditem");
|
||||
ri.Save(newElement);
|
||||
componentElement.Add(newElement);
|
||||
}
|
||||
|
||||
ObjectProperty.SaveProperties(this, componentElement);
|
||||
|
||||
//var saveProperties = ObjectProperty.GetProperties<Saveable>(this);
|
||||
//foreach (var property in saveProperties)
|
||||
//{
|
||||
// object value = property.GetValue();
|
||||
// if (value == null) continue;
|
||||
|
||||
// bool dontSave = false;
|
||||
// foreach (var ini in property.Attributes.OfType<Initable>())
|
||||
// {
|
||||
// if (ini.defaultValue != value) continue;
|
||||
|
||||
// dontSave = true;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// if (dontSave) continue;
|
||||
|
||||
// componentElement.Add(new XAttribute(property.Name.ToLower(), value));
|
||||
//}
|
||||
|
||||
parentElement.Add(componentElement);
|
||||
return componentElement;
|
||||
}
|
||||
|
||||
public virtual void Load(XElement componentElement)
|
||||
{
|
||||
if (componentElement == null) return;
|
||||
|
||||
bool requiredItemsCleared = false;
|
||||
|
||||
foreach (XAttribute attribute in componentElement.Attributes())
|
||||
{
|
||||
ObjectProperty property = null;
|
||||
if (!properties.TryGetValue(attribute.Name.ToString().ToLower(), out property)) continue;
|
||||
|
||||
property.TrySetValue(attribute.Value);
|
||||
}
|
||||
|
||||
foreach (XElement subElement in componentElement.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
{
|
||||
case "requireditem":
|
||||
RelatedItem newRequiredItem = RelatedItem.Load(subElement);
|
||||
|
||||
if (newRequiredItem == null) continue;
|
||||
|
||||
if (!requiredItemsCleared)
|
||||
{
|
||||
requiredItems.Clear();
|
||||
requiredItemsCleared = true;
|
||||
}
|
||||
|
||||
requiredItems.Add(newRequiredItem);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnMapLoaded() { }
|
||||
|
||||
public static ItemComponent Load(XElement element, Item item, string file)
|
||||
{
|
||||
Type t;
|
||||
string type = element.Name.ToString().ToLower();
|
||||
try
|
||||
{
|
||||
// Get the type of a specified class.
|
||||
t = Type.GetType("Subsurface.Items.Components." + type + ", Subsurface", true, true);
|
||||
if (t == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the component ''" + type + "'' (" + file + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the component ''" + type + "'' (" + file + ")", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
ConstructorInfo constructor;
|
||||
try
|
||||
{
|
||||
if (!t.IsSubclassOf(typeof(ItemComponent))) return null;
|
||||
constructor = t.GetConstructor(new Type[] { typeof(Item), typeof(XElement) });
|
||||
if (constructor == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the constructor of the component ''" + type + "'' (" + file + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the constructor of the component ''" + type + "'' (" + file + ")", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
object[] lobject = new object[] { item, element };
|
||||
object component = constructor.Invoke(lobject);
|
||||
|
||||
ItemComponent ic = (ItemComponent)component;
|
||||
ic.name = element.Name.ToString();
|
||||
|
||||
return ic;
|
||||
}
|
||||
|
||||
public virtual void FillNetworkData(NetworkEventType type, NetOutgoingMessage message)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Ladder : ItemComponent
|
||||
{
|
||||
|
||||
public Ladder(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker = null)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
|
||||
picker.animController.anim = AnimController.Animation.Climbing;
|
||||
//picker.SelectedConstruction = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class MiniMap : Powered
|
||||
{
|
||||
|
||||
public MiniMap(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
voltage = 0.0f;
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
|
||||
picker.SelectedConstruction = item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
int width = 500, height = 400;
|
||||
int x = Game1.GraphicsWidth / 2 - width / 2;
|
||||
int y = Game1.GraphicsHeight / 2 - height / 2;
|
||||
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(x,y,width,height), Color.Black, true);
|
||||
|
||||
Rectangle miniMap = new Rectangle(x + 20, y + 40, width - 40, height - 60);
|
||||
|
||||
float size = Math.Min((float)miniMap.Width / (float)Map.Borders.Width, (float)miniMap.Height / (float)Map.Borders.Height);
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
Rectangle hullRect = new Rectangle(
|
||||
miniMap.X + (int)((hull.Rect.X - Map.Borders.X) * size),
|
||||
miniMap.Y - (int)((hull.Rect.Y - Map.Borders.Y) * size),
|
||||
(int)(hull.Rect.Width * size),
|
||||
(int)(hull.Rect.Height * size));
|
||||
|
||||
float waterAmount = Math.Min(hull.Volume / hull.FullVolume, 1.0f);
|
||||
|
||||
if (hullRect.Height * waterAmount > 1.0f)
|
||||
{
|
||||
Rectangle waterRect = new Rectangle(
|
||||
hullRect.X,
|
||||
(int)(hullRect.Y + hullRect.Height * (1.0f - waterAmount)),
|
||||
hullRect.Width,
|
||||
(int)(hullRect.Height * waterAmount));
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, waterRect, Color.DarkBlue, true);
|
||||
}
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, hullRect, Color.White);
|
||||
}
|
||||
|
||||
foreach (Character c in Character.characterList)
|
||||
{
|
||||
if (c.animController.CurrentHull!=null) continue;
|
||||
|
||||
Rectangle characterRect = new Rectangle(
|
||||
miniMap.X + (int)((c.Position.X - Map.Borders.X) * size),
|
||||
miniMap.Y - (int)((c.Position.Y - Map.Borders.Y) * size),
|
||||
5, 5);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, characterRect, Color.White, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class OxygenGenerator : Powered
|
||||
{
|
||||
PropertyTask powerUpTask;
|
||||
|
||||
bool running;
|
||||
|
||||
List<Vent> ventList;
|
||||
|
||||
public bool IsRunning()
|
||||
{
|
||||
return running && item.Condition>0.0f;
|
||||
}
|
||||
|
||||
public OxygenGenerator(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
isActive = true;
|
||||
|
||||
ventList = new List<Vent>();
|
||||
|
||||
item.linkedTo.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
|
||||
delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{ GetVents(); }
|
||||
);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
if (item.currentHull == null) return;
|
||||
|
||||
if (voltage < minVoltage)
|
||||
{
|
||||
running = false;
|
||||
if (powerUpTask==null || powerUpTask.IsFinished)
|
||||
{
|
||||
powerUpTask = new PropertyTask(Game1.gameSession.taskManager, item, IsRunning, 30.0f, "Turn on the oxygen generator");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
running = true;
|
||||
|
||||
float deltaOxygen = Math.Min(voltage, 1.0f) * 50000.0f;
|
||||
item.currentHull.Oxygen += deltaOxygen * deltaTime;
|
||||
|
||||
UpdateVents(deltaOxygen);
|
||||
|
||||
voltage = 0.0f;
|
||||
}
|
||||
|
||||
private void GetVents()
|
||||
{
|
||||
foreach (MapEntity entity in item.linkedTo)
|
||||
{
|
||||
Item linkedItem = entity as Item;
|
||||
if (linkedItem == null) continue;
|
||||
|
||||
Vent vent = linkedItem.GetComponent<Vent>();
|
||||
if (vent != null) ventList.Add(vent);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVents(float deltaOxygen)
|
||||
{
|
||||
if (ventList.Count == 0) return;
|
||||
|
||||
deltaOxygen = deltaOxygen / ventList.Count;
|
||||
foreach (Vent v in ventList)
|
||||
{
|
||||
v.OxygenFlow = deltaOxygen;
|
||||
v.IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Pickable : ItemComponent
|
||||
{
|
||||
protected Character picker;
|
||||
|
||||
protected LimbSlot allowedSlots;
|
||||
|
||||
public LimbSlot AllowedSlots
|
||||
{
|
||||
get { return allowedSlots; }
|
||||
}
|
||||
|
||||
public Character Picker
|
||||
{
|
||||
get { return picker; }
|
||||
}
|
||||
|
||||
public Pickable(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
string slotString = ToolBox.GetAttributeString(element, "slots", "Any");
|
||||
string[] slots = slotString.Split(',');
|
||||
foreach (string slot in slots)
|
||||
{
|
||||
allowedSlots = allowedSlots | (LimbSlot)Enum.Parse(typeof(LimbSlot), slot.Trim());
|
||||
}
|
||||
|
||||
canBePicked = true;
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
if (picker.Inventory == null) return false;
|
||||
|
||||
this.picker = picker;
|
||||
|
||||
for (int i = item.linkedTo.Count - 1; i >= 0; i--)
|
||||
item.linkedTo[i].RemoveLinked(item);
|
||||
item.linkedTo.Clear();
|
||||
|
||||
if (picker.Inventory.TryPutItem(item, allowedSlots))
|
||||
{
|
||||
if (!picker.HasSelectedItem(item) && item.body!=null) item.body.Enabled = false;
|
||||
this.picker = picker;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker, null);
|
||||
|
||||
//foreach (StatusEffect effect in item.Prefab.statusEffects)
|
||||
//{
|
||||
// effect.OnPicked(picker, null);
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Drop(Character dropper)
|
||||
{
|
||||
if (picker == null)
|
||||
{
|
||||
picker = dropper;
|
||||
|
||||
//foreach (Character c in Character.characterList)
|
||||
//{
|
||||
// if (c.Inventory == null) continue;
|
||||
// if (c.Inventory.FindIndex(item) == -1) continue;
|
||||
|
||||
// picker = c;
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
if (picker==null || picker.Inventory == null) return;
|
||||
|
||||
if (item.body!= null && !item.body.Enabled)
|
||||
{
|
||||
Limb rightHand = picker.animController.GetLimb(LimbType.RightHand);
|
||||
item.SetTransform(rightHand.SimPosition, 0.0f);
|
||||
item.body.Enabled = true;
|
||||
}
|
||||
picker.Inventory.RemoveItem(item);
|
||||
picker = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class PowerContainer : Powered
|
||||
{
|
||||
float capacity;
|
||||
|
||||
//[power/min]
|
||||
float charge;
|
||||
|
||||
//how fast the battery can be recharged
|
||||
float maxRechargeSpeed;
|
||||
|
||||
//how fast it's currently being recharged (can be changed, so that
|
||||
//charging can be slowed down or disabled if there's a shortage of power)
|
||||
float rechargeSpeed;
|
||||
|
||||
float maxOutput;
|
||||
|
||||
//public override float Charge
|
||||
//{
|
||||
// get { return charge; }
|
||||
// set { Math.Max(Math.Min(charge = value, capacity), 0.0f); }
|
||||
//}
|
||||
|
||||
[Editable, HasDefaultValue(10.0f, true)]
|
||||
public float MaxOutPut
|
||||
{
|
||||
get { return maxOutput; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(0.0f, true)]
|
||||
public float Charge
|
||||
{
|
||||
get { return charge; }
|
||||
set { charge = MathHelper.Clamp(value, 0.0f, capacity); }
|
||||
}
|
||||
|
||||
|
||||
[HasDefaultValue(10.0f, false)]
|
||||
private float Capacity
|
||||
{
|
||||
set { capacity = Math.Max(value,1.0f); }
|
||||
}
|
||||
|
||||
[HasDefaultValue(10.0f, false)]
|
||||
private float MaxInput
|
||||
{
|
||||
set { MaxInput = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(10.0f, false)]
|
||||
private float MaxOutput
|
||||
{
|
||||
set { maxOutput = value; }
|
||||
}
|
||||
|
||||
public PowerContainer(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//capacity = ToolBox.GetAttributeFloat(element, "capacity", 10.0f);
|
||||
//maxRechargeSpeed = ToolBox.GetAttributeFloat(element, "maxinput", 10.0f);
|
||||
//maxOutput = ToolBox.GetAttributeFloat(element, "maxoutput", 10.0f);
|
||||
|
||||
rechargeSpeed = maxRechargeSpeed;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
|
||||
//picker.SelectedConstruction = (picker.SelectedConstruction == item) ? null : item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
float chargeRate = (float)(Math.Sqrt(charge / capacity));
|
||||
//float gridPower = 0.0f;
|
||||
float gridLoad = 0.0f;
|
||||
|
||||
//if (item.linkedTo.Count == 0) return;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
|
||||
foreach (Connection c in item.Connections)
|
||||
{
|
||||
foreach (Connection c2 in c.Recipients)
|
||||
{
|
||||
PowerTransfer pt = c2.Item.GetComponent<PowerTransfer>();
|
||||
if (pt == null) continue;
|
||||
|
||||
gridLoad += pt.PowerLoad;
|
||||
}
|
||||
}
|
||||
|
||||
//foreach (MapEntity e in item.linkedTo)
|
||||
//{
|
||||
// Item it = e as Item;
|
||||
// if (it == null) continue;
|
||||
|
||||
// PowerTransfer pt = it.GetComponent<PowerTransfer>();
|
||||
// if (pt==null) continue;
|
||||
// //gridPower -= pt.PowerConsumption;
|
||||
// gridLoad += pt.PowerLoad;
|
||||
|
||||
// //gridPower = -jb.PowerConsumption;
|
||||
// //gridLoad = jb.load;
|
||||
// break;
|
||||
//}
|
||||
|
||||
float gridRate = voltage;
|
||||
|
||||
//recharge
|
||||
if (gridRate >= chargeRate)
|
||||
{
|
||||
if (charge >= capacity)
|
||||
{
|
||||
currPowerConsumption = 0.0f;
|
||||
charge = capacity;
|
||||
return;
|
||||
}
|
||||
|
||||
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, rechargeSpeed, 0.05f);
|
||||
charge += currPowerConsumption*voltage / 3600.0f;
|
||||
}
|
||||
//provide power to the grid
|
||||
else if (gridLoad > 0.0f)
|
||||
{
|
||||
if (charge <= 0.0f)
|
||||
{
|
||||
currPowerConsumption = 0.0f;
|
||||
charge = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
currPowerConsumption = MathHelper.Lerp(
|
||||
currPowerConsumption,
|
||||
-maxOutput * chargeRate,
|
||||
0.1f);
|
||||
|
||||
currPowerConsumption = MathHelper.Lerp(
|
||||
currPowerConsumption,
|
||||
-Math.Min(maxOutput * chargeRate, gridLoad - (gridLoad * voltage)),
|
||||
0.05f);
|
||||
|
||||
//powerConsumption = MathHelper.Lerp(
|
||||
// powerConsumption,
|
||||
// -Math.Min(maxOutput * chargeRate, gridLoad - (power)),
|
||||
// 0.1f);
|
||||
|
||||
//powerConsumption = Math.Min(powerConsumption, 0.0f);
|
||||
charge -= -currPowerConsumption / chargeRate / 3600.0f;
|
||||
}
|
||||
|
||||
voltage = 0.0f;
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
base.Draw(spriteBatch);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 4, -item.Rect.Y + 9),
|
||||
new Vector2(8, 22), Color.Black);
|
||||
|
||||
if (charge > 0)
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 3, -item.Rect.Y + 10 + (20.0f * (1.0f - charge / capacity))),
|
||||
new Vector2(6, 20 * (charge / capacity)), Color.Green, true);
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
int width = 300, height = 200;
|
||||
int x = Game1.GraphicsWidth / 2 - width / 2;
|
||||
int y = Game1.GraphicsHeight / 2 - height / 2;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
|
||||
|
||||
spriteBatch.DrawString(GUI.font,
|
||||
"Charge: " + (int)charge + "/" + (int)capacity + " (" + (int)((charge / capacity) * 100.0f) + " %)",
|
||||
new Vector2(x + 30, y + 30), Color.White);
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Recharge rate: " + (rechargeSpeed / maxRechargeSpeed), new Vector2(x + 30, y + 100), Color.White);
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 50, y + 150, 40, 40), "+", true))
|
||||
rechargeSpeed = Math.Min(rechargeSpeed + 10.0f, maxRechargeSpeed);
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 150, 40, 40), "-", true))
|
||||
rechargeSpeed = Math.Max(rechargeSpeed - 10.0f, 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class PowerTransfer : Powered
|
||||
{
|
||||
static float fullPower;
|
||||
static float fullLoad;
|
||||
|
||||
//affects how fast changes in power/load are carried over the grid
|
||||
static float inertia = 5.0f;
|
||||
|
||||
static List<Powered> connectedList = new List<Powered>();
|
||||
|
||||
private float powerLoad;
|
||||
|
||||
public float PowerLoad
|
||||
{
|
||||
get { return powerLoad; }
|
||||
}
|
||||
|
||||
public PowerTransfer(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//reset and recalculate the power generated/consumed
|
||||
//by the constructions connected to the grid
|
||||
fullPower = 0.0f;
|
||||
fullLoad = 0.0f;
|
||||
connectedList.Clear();
|
||||
|
||||
if (updated) return;
|
||||
|
||||
CheckJunctions(deltaTime);
|
||||
|
||||
foreach (Powered p in connectedList)
|
||||
{
|
||||
PowerTransfer pt = p as PowerTransfer;
|
||||
if (pt!=null)
|
||||
{
|
||||
pt.powerLoad += (fullLoad - pt.powerLoad) / inertia;
|
||||
pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia;
|
||||
pt.Item.SendSignal((fullPower / Math.Max(fullLoad,1.0f)).ToString(), "power_out");
|
||||
}
|
||||
else
|
||||
{
|
||||
//p.Power = fullPower;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
|
||||
//picker.SelectedConstruction = (picker.SelectedConstruction == item) ? null : item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//a recursive function that goes through all the junctions and adds up
|
||||
//all the generated/consumed power of the constructions connected to the grid
|
||||
private void CheckJunctions(float deltaTime)
|
||||
{
|
||||
updated = true;
|
||||
connectedList.Add(this);
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
List<Connection> connections = item.Connections;
|
||||
if (connections == null) return;
|
||||
|
||||
foreach (Connection c in connections)
|
||||
{
|
||||
foreach (Connection recipient in c.Recipients)
|
||||
{
|
||||
if (recipient == null) continue;
|
||||
|
||||
Item it = recipient.Item;
|
||||
if (it == null) continue;
|
||||
|
||||
//if (it.Updated) continue;
|
||||
|
||||
Powered powered = it.GetComponent<Powered>();
|
||||
if (powered == null || powered.Updated) continue;
|
||||
|
||||
PowerTransfer powerTransfer = powered as PowerTransfer;
|
||||
if (powerTransfer != null)
|
||||
{
|
||||
powerTransfer.CheckJunctions(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectedList.Add(powered);
|
||||
//positive power consumption = the construction requires power -> increase load
|
||||
if (powered.PowerConsumption > 0.0f)
|
||||
{
|
||||
fullLoad += powered.PowerConsumption;
|
||||
}
|
||||
else if (powered.PowerConsumption < 0.0f)
|
||||
//negative power consumption = the construction is a
|
||||
//generator/battery or another junction box
|
||||
{
|
||||
fullPower -= powered.PowerConsumption;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
int width = 300, height = 200;
|
||||
int x = Game1.GraphicsWidth / 2 - width / 2;
|
||||
int y = Game1.GraphicsHeight / 2 - height / 2;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Power: " + (int)(-currPowerConsumption), new Vector2(x + 30, y + 30), Color.White);
|
||||
spriteBatch.DrawString(GUI.font, "Load: " + (int)powerLoad, new Vector2(x + 30, y + 100), Color.White);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Powered : ItemComponent
|
||||
{
|
||||
//the amount of power CURRENTLY consumed by the item
|
||||
//negative values mean that the item is providing power to connected items
|
||||
protected float currPowerConsumption;
|
||||
|
||||
//the amount of power available for the item through connected items
|
||||
protected float voltage;
|
||||
|
||||
//the amount of power required for the item to work
|
||||
protected float minVoltage;
|
||||
|
||||
//the maximum amount of power the item can draw from connected items
|
||||
protected float powerConsumption;
|
||||
|
||||
[Editable, HasDefaultValue(0.5f, true)]
|
||||
public float MinVoltage
|
||||
{
|
||||
get { return minVoltage; }
|
||||
set { minVoltage = value; }
|
||||
}
|
||||
|
||||
[Editable, HasDefaultValue(0.0f, true)]
|
||||
public float PowerConsumption
|
||||
{
|
||||
get { return powerConsumption; }
|
||||
set { powerConsumption = value; }
|
||||
}
|
||||
|
||||
|
||||
[HasDefaultValue(false,true)]
|
||||
public override bool IsActive
|
||||
{
|
||||
get { return isActive; }
|
||||
set
|
||||
{
|
||||
isActive = value;
|
||||
if (!isActive) currPowerConsumption = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
[HasDefaultValue(0.0f, true)]
|
||||
public float CurrPowerConsumption
|
||||
{
|
||||
get {return currPowerConsumption; }
|
||||
set { currPowerConsumption = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(0.0f, true)]
|
||||
public float Voltage
|
||||
{
|
||||
get { return voltage; }
|
||||
set { voltage = Math.Max(0.0f, value); }
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
if (connection.name=="power_in")
|
||||
{
|
||||
if (!float.TryParse(signal, out voltage))
|
||||
{
|
||||
voltage = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (currPowerConsumption == 0.0f) return;
|
||||
if (voltage > minVoltage) ApplyStatusEffects(ActionType.OnActive, deltaTime);
|
||||
}
|
||||
|
||||
public Powered(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//minVoltage = ToolBox.GetAttributeFloat(element, "minvoltage", 10.0f);
|
||||
//powerConsumption = ToolBox.GetAttributeFloat(element, "powerconsumption", 15.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Projectile : ItemComponent
|
||||
{
|
||||
private float launchImpulse;
|
||||
|
||||
private bool doesStick;
|
||||
private PrismaticJoint stickJoint;
|
||||
private Body stickTarget;
|
||||
|
||||
Attack attack;
|
||||
|
||||
public List<Body> ignoredBodies;
|
||||
|
||||
[HasDefaultValue(10.0f, false)]
|
||||
public float LaunchImpulse
|
||||
{
|
||||
get { return launchImpulse; }
|
||||
set { launchImpulse = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool CharacterUsable
|
||||
{
|
||||
get { return characterUsable; }
|
||||
set { characterUsable = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(false, false)]
|
||||
public bool DoesStick
|
||||
{
|
||||
get { return doesStick; }
|
||||
set { doesStick = value; }
|
||||
}
|
||||
|
||||
public Projectile(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
ignoredBodies = new List<Body>();
|
||||
|
||||
//launchImpulse = ToolBox.GetAttributeFloat(element, "launchimpulse", 10.0f);
|
||||
//characterUsable = ToolBox.GetAttributeBool(element, "characterusable", false);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLower() != "attack") continue;
|
||||
attack = new Attack(subElement);
|
||||
}
|
||||
|
||||
//bleedingDamage = ToolBox.GetAttributeFloat(element, "bleedingdamage", 0.0f);
|
||||
//bluntDamage = ToolBox.GetAttributeFloat(element, "bluntdamage", 0.0f);
|
||||
|
||||
//doesStick = ToolBox.GetAttributeBool(element, "doesstick", false);
|
||||
}
|
||||
|
||||
//public override void ConstructionActivate(Construction c, Vector2 modifier)
|
||||
//{
|
||||
// for (int i = 0; i < item.linkedTo.Count; i++)
|
||||
// item.linkedTo[i].RemoveLinked((MapEntity)item);
|
||||
// item.linkedTo.Clear();
|
||||
|
||||
// ApplyStatusEffects(StatusEffect.Type.OnUse, 1.0f, null);
|
||||
|
||||
// Launch(modifier+Vector2.Normalize(modifier)*launchImpulse);
|
||||
|
||||
//}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (character != null && !characterUsable) return false;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, character);
|
||||
|
||||
Debug.WriteLine(item.body.Rotation);
|
||||
|
||||
Launch(new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation))*launchImpulse*item.body.Mass);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Launch(Vector2 impulse)
|
||||
{
|
||||
item.body.Enabled = true;
|
||||
item.body.ApplyLinearImpulse(impulse);
|
||||
|
||||
item.body.FarseerBody.OnCollision += OnProjectileCollision;
|
||||
item.body.FarseerBody.IsBullet = true;
|
||||
|
||||
item.body.CollisionCategories = Physics.CollisionProjectile;
|
||||
item.body.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
|
||||
|
||||
item.Drop();
|
||||
|
||||
if (stickJoint != null && doesStick)
|
||||
{
|
||||
if (stickTarget!=null) item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
||||
Game1.world.RemoveJoint(stickJoint);
|
||||
stickJoint = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (stickJoint != null)
|
||||
{
|
||||
if (stickJoint.JointTranslation < 0.01f)
|
||||
{
|
||||
if (stickTarget!=null)
|
||||
{
|
||||
item.body.FarseerBody.RestoreCollisionWith(stickTarget);
|
||||
}
|
||||
|
||||
Game1.world.RemoveJoint(stickJoint);
|
||||
stickJoint = null;
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool OnProjectileCollision(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
//doesn't collide with items
|
||||
if (f2.Body.UserData is Item) return false;
|
||||
|
||||
if (ignoredBodies.Contains(f2.Body)) return false;
|
||||
|
||||
//Structure structure = f1.Body.UserData as Structure;
|
||||
//if (structure!=null && (structure.IsPlatform || structure.StairDirection != Direction.None)) return false;
|
||||
|
||||
//Vector2 force = f1.Body.LinearVelocity * f1.Body.Mass;
|
||||
//float forceLength = force.Length();
|
||||
|
||||
//if (forceLength > 20.0f)
|
||||
//{
|
||||
// force = force / forceLength * 20.0f;
|
||||
//}
|
||||
|
||||
//f2.Body.ApplyLinearImpulse(force);
|
||||
//f1.Body.ApplyLinearImpulse(-f1.Body.LinearVelocity * f1.Body.Mass);
|
||||
|
||||
float damage = f1.Body.LinearVelocity.Length();
|
||||
|
||||
Limb limb;
|
||||
Structure structure;
|
||||
if ((limb = (f2.Body.UserData as Limb)) != null)
|
||||
{
|
||||
attack.DoDamage(limb.character, item.SimPosition, 0.0f);
|
||||
//limb.Damage += damage;
|
||||
//limb.Bleeding += bleedingDamage;
|
||||
|
||||
//if (bleedingDamage>0.0f)
|
||||
//{
|
||||
// for (int i = 0; i < 5; i++ )
|
||||
// {
|
||||
// Game1.particleManager.CreateParticle(limb.SimPosition,
|
||||
// ToolBox.VectorToAngle(-f1.Body.LinearVelocity*0.5f) + ToolBox.RandomFloat(-0.5f, 0.5f),
|
||||
// ToolBox.RandomFloat(1.0f, 3.0f), "blood");
|
||||
// }
|
||||
|
||||
// Game1.particleManager.CreateParticle(limb.SimPosition,
|
||||
// 0.0f,
|
||||
// Vector2.Zero, "waterblood");
|
||||
//}
|
||||
|
||||
//AmbientSoundManager.PlayDamageSound(DamageType.LimbBlunt, damage, limb.body.FarseerBody);
|
||||
}
|
||||
else if ((structure = (f2.Body.UserData as Structure)) != null)
|
||||
{
|
||||
attack.DoDamage(structure, item.SimPosition, 0.0f);
|
||||
|
||||
//AmbientSoundManager.PlayDamageSound(DamageType.StructureBlunt, damage, f2.Body);
|
||||
}
|
||||
|
||||
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
|
||||
|
||||
item.body.FarseerBody.IsBullet = false;
|
||||
item.body.CollisionCategories = Physics.CollisionMisc;
|
||||
item.body.CollidesWith = Physics.CollisionWall;
|
||||
|
||||
ignoredBodies.Clear();
|
||||
|
||||
if (doesStick)
|
||||
{
|
||||
Vector2 normal = contact.Manifold.LocalNormal;
|
||||
Vector2 dir = new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation));
|
||||
|
||||
if (Vector2.Dot(f1.Body.LinearVelocity, normal)<0 ) return StickToTarget(f2.Body, dir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool StickToTarget(Body targetBody, Vector2 axis)
|
||||
{
|
||||
if (stickJoint != null) return false;
|
||||
|
||||
stickJoint = new PrismaticJoint(targetBody, item.body.FarseerBody, item.body.Position, axis, true);
|
||||
stickJoint.MotorEnabled = true;
|
||||
stickJoint.MaxMotorForce = 15.0f;
|
||||
|
||||
stickJoint.LimitEnabled = true;
|
||||
stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.sprite.size.X*0.7f);
|
||||
|
||||
item.body.FarseerBody.IgnoreCollisionWith(targetBody);
|
||||
stickTarget = targetBody;
|
||||
Game1.world.AddJoint(stickJoint);
|
||||
|
||||
isActive = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Pump : Powered
|
||||
{
|
||||
float flow;
|
||||
float maxFlow;
|
||||
|
||||
bool flowIn;
|
||||
|
||||
Hull hull1, hull2;
|
||||
|
||||
[HasDefaultValue(100.0f, false)]
|
||||
private float MaxFlow
|
||||
{
|
||||
set { maxFlow = value; }
|
||||
}
|
||||
|
||||
public Pump(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//maxFlow = ToolBox.GetAttributeFloat(element, "maxflow", 100.0f);
|
||||
|
||||
item.linkedTo.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
|
||||
delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
|
||||
{ GetHulls(); }
|
||||
);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
if (voltage < minVoltage) return;
|
||||
|
||||
if (hull2 == null && hull1 == null) return;
|
||||
|
||||
float deltaVolume = flow * ((flowIn) ? 1.0f : -1.0f);
|
||||
hull1.Volume += deltaVolume;
|
||||
if (hull2 != null) hull2.Volume -= deltaVolume;
|
||||
|
||||
float powerFactor = (currPowerConsumption==0.0f) ? 1.0f : voltage;
|
||||
flow = maxFlow * powerFactor;
|
||||
|
||||
voltage = 0.0f;
|
||||
}
|
||||
|
||||
//public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
//{
|
||||
// int width = 300, height = 200;
|
||||
// int x = Game1.GraphicsWidth / 2 - width / 2;
|
||||
// int y = Game1.GraphicsHeight / 2 - height / 2;
|
||||
|
||||
// GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
|
||||
|
||||
// spriteBatch.DrawString(GUI.font, "Pumping direction: " + ((flowIn) ? "in" : "out"), new Vector2(x + 30, y + 30), Color.White);
|
||||
// if (GUI.DrawButton(spriteBatch, new Rectangle(x + 30, y + 50, 80, 40), "TOGGLE")) flowIn = !flowIn;
|
||||
|
||||
// if (GUI.DrawButton(spriteBatch, new Rectangle(x + 30, y + 150, 100, 40), (isActive) ? "TURN OFF" : "TURN ON")) IsActive = !isActive;
|
||||
|
||||
//}
|
||||
|
||||
//public override bool Pick(Character activator = null)
|
||||
//{
|
||||
// //isActive = !isActive;
|
||||
|
||||
// hull1 = null;
|
||||
// hull2 = null;
|
||||
|
||||
// foreach (MapEntity e in item.linkedTo)
|
||||
// {
|
||||
// Hull hull = e as Hull;
|
||||
// if (hull == null) continue;
|
||||
|
||||
// if (hull1 == null)
|
||||
// {
|
||||
// hull1 = hull;
|
||||
// }
|
||||
// else if (hull2 == null && hull != hull1)
|
||||
// {
|
||||
// hull2 = hull;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
private void GetHulls()
|
||||
{
|
||||
hull1 = null;
|
||||
hull2 = null;
|
||||
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Hull hull = e as Hull;
|
||||
if (hull == null) continue;
|
||||
|
||||
if (hull1 == null)
|
||||
{
|
||||
hull1 = hull;
|
||||
}
|
||||
else if (hull2 == null && hull != hull1)
|
||||
{
|
||||
hull2 = hull;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public override void OnMapLoaded()
|
||||
//{
|
||||
// hull1 = null;
|
||||
// hull2 = null;
|
||||
|
||||
// foreach (MapEntity e in item.linkedTo)
|
||||
// {
|
||||
// Hull hull = e as Hull;
|
||||
// if (hull == null) continue;
|
||||
|
||||
// if (hull1 == null)
|
||||
// {
|
||||
// hull1 = hull;
|
||||
// }
|
||||
// else if (hull2 == null && hull != hull1)
|
||||
// {
|
||||
// hull2 = hull;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
base.ReceiveSignal(signal, connection, sender);
|
||||
|
||||
if (connection.name == "toggle")
|
||||
{
|
||||
isActive = !isActive;
|
||||
}
|
||||
else if (connection.name == "set_state")
|
||||
{
|
||||
isActive = (signal != "0");
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
|
||||
{
|
||||
message.Write(flowIn);
|
||||
message.Write(isActive);
|
||||
}
|
||||
|
||||
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
|
||||
{
|
||||
flowIn = message.ReadBoolean();
|
||||
isActive = message.ReadBoolean();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class RangedWeapon : ItemComponent
|
||||
{
|
||||
private float reload;
|
||||
|
||||
private Vector2 barrelPos;
|
||||
|
||||
//[Initable(new Vector2(0.0f, 0.0f))]
|
||||
public Vector2 BarrelPos
|
||||
{
|
||||
get { return new Vector2(barrelPos.X * item.body.Dir, barrelPos.Y); }
|
||||
}
|
||||
|
||||
public Vector2 TransformedBarrelPos
|
||||
{
|
||||
get
|
||||
{
|
||||
Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation);
|
||||
return (Vector2.Transform(BarrelPos, bodyTransform) + item.body.Position);
|
||||
}
|
||||
}
|
||||
|
||||
public RangedWeapon(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
barrelPos = ToolBox.GetAttributeVector2(element, "barrelpos", Vector2.Zero);
|
||||
barrelPos = ConvertUnits.ToSimUnits(barrelPos);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
reload -= deltaTime;
|
||||
|
||||
if (reload < 0.0f)
|
||||
{
|
||||
reload = 0.0f;
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (character == null) return false;
|
||||
if (!character.SecondaryKeyDown.State || reload > 0.0f) return false;
|
||||
isActive = true;
|
||||
reload = 1.0f;
|
||||
|
||||
List<Body> limbBodies = new List<Body>();
|
||||
foreach (Limb l in character.animController.limbs)
|
||||
{
|
||||
limbBodies.Add(l.body.FarseerBody);
|
||||
}
|
||||
|
||||
Item[] containedItems = item.ContainedItems;
|
||||
if (containedItems == null || containedItems.Count()==0) return false;
|
||||
|
||||
foreach (Item projectile 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;
|
||||
|
||||
projectileComponent.ignoredBodies = limbBodies;
|
||||
|
||||
projectile.body.ResetDynamics();
|
||||
projectile.SetTransform(TransformedBarrelPos,
|
||||
(item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi);
|
||||
|
||||
projectile.Use();
|
||||
item.RemoveContained(projectile);
|
||||
|
||||
//recoil
|
||||
item.body.ApplyLinearImpulse(
|
||||
new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * item.body.Mass);
|
||||
|
||||
Rope rope = item.GetComponent<Rope>();
|
||||
if (rope != null) rope.Attach(projectile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Subsurface.Networking;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Reactor : Powered
|
||||
{
|
||||
//the rate at which the reactor is being run un
|
||||
//higher rates generate more power (and heat)
|
||||
float fissionRate;
|
||||
|
||||
//the rate at which the heat is being dissipated
|
||||
float coolingRate;
|
||||
|
||||
float temperature;
|
||||
|
||||
//is automatic temperature control on
|
||||
//(adjusts the cooling rate automatically to keep the
|
||||
//amount of power generated balanced with the load)
|
||||
bool autoTemp;
|
||||
|
||||
//the temperature after which fissionrate is automatically
|
||||
//turned down and cooling increased
|
||||
float shutDownTemp;
|
||||
|
||||
float meltDownTemp;
|
||||
|
||||
//how much power is provided to the grid per 1 temperature unit
|
||||
float powerPerTemp;
|
||||
|
||||
int graphSize = 25;
|
||||
|
||||
float graphTimer;
|
||||
|
||||
int updateGraphInterval = 500;
|
||||
|
||||
float[] fissionRateGraph;
|
||||
float[] coolingRateGraph;
|
||||
float[] tempGraph;
|
||||
|
||||
private PropertyTask powerUpTask;
|
||||
|
||||
[Editable, HasDefaultValue(9500.0f, true)]
|
||||
public float MeltDownTemp
|
||||
{
|
||||
get { return meltDownTemp; }
|
||||
set
|
||||
{
|
||||
meltDownTemp = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Editable, HasDefaultValue(1.0f, true)]
|
||||
public float PowerPerTemp
|
||||
{
|
||||
get { return powerPerTemp; }
|
||||
set
|
||||
{
|
||||
powerPerTemp = Math.Max(0.0f, value);
|
||||
}
|
||||
}
|
||||
|
||||
public float FissionRate
|
||||
{
|
||||
get { return fissionRate; }
|
||||
set { fissionRate = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public float CoolingRate
|
||||
{
|
||||
get { return coolingRate; }
|
||||
set { coolingRate = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public float Temperature
|
||||
{
|
||||
get { return temperature; }
|
||||
set { temperature = MathHelper.Clamp(value, 0.0f, 10000.0f); }
|
||||
}
|
||||
|
||||
public bool IsRunning()
|
||||
{
|
||||
return (temperature > 0.0f);
|
||||
}
|
||||
|
||||
public float ExtraCooling { get; set; }
|
||||
|
||||
public Reactor(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
fissionRateGraph = new float[graphSize];
|
||||
coolingRateGraph = new float[graphSize];
|
||||
tempGraph = new float[graphSize];
|
||||
|
||||
meltDownTemp = 9000.0f;
|
||||
|
||||
powerPerTemp = 1.0f;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
|
||||
float heat = 100 * fissionRate;
|
||||
float heatDissipation = 50 * coolingRate + ExtraCooling;
|
||||
|
||||
float deltaTemp = (((heat - heatDissipation) * 5) - temperature) / 1000.0f;
|
||||
Temperature = temperature + deltaTemp;
|
||||
|
||||
if (temperature > meltDownTemp)
|
||||
{
|
||||
MeltDown();
|
||||
return;
|
||||
}
|
||||
else if (temperature==0.0f)
|
||||
{
|
||||
if (powerUpTask==null || powerUpTask.IsFinished)
|
||||
{
|
||||
powerUpTask = new PropertyTask(Game1.gameSession.taskManager, item, IsRunning, 20.0f, "Power up the reactor");
|
||||
}
|
||||
}
|
||||
|
||||
item.Condition -= temperature*deltaTime*0.00005f;
|
||||
|
||||
if (temperature > shutDownTemp)
|
||||
{
|
||||
CoolingRate += 0.5f;
|
||||
FissionRate -= 0.5f;
|
||||
}
|
||||
else if (autoTemp)
|
||||
{
|
||||
float load = 0.0f;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item it = e as Item;
|
||||
if (it == null) continue;
|
||||
|
||||
PowerTransfer pt = it.GetComponent<PowerTransfer>();
|
||||
if (pt != null) load += pt.PowerLoad;
|
||||
}
|
||||
|
||||
fissionRate = Math.Min(load / 200.0f, shutDownTemp);
|
||||
//float target = Math.Min(targetTemp, load);
|
||||
CoolingRate = coolingRate + (temperature - Math.Min(load, shutDownTemp) + deltaTemp)*0.1f;
|
||||
}
|
||||
|
||||
//fission rate can't be lowered below a certain amount if the core is too hot
|
||||
FissionRate = Math.Max(fissionRate, heat / 200.0f);
|
||||
|
||||
//the power generated by the reactor is equal to the temperature
|
||||
currPowerConsumption = -temperature;
|
||||
|
||||
if (item.currentHull != null)
|
||||
{
|
||||
//the sound can be heard from 20 000 display units away when everything running at 100%
|
||||
item.currentHull.SoundRange += (coolingRate + fissionRate) * 100;
|
||||
}
|
||||
|
||||
UpdateGraph(deltaTime);
|
||||
|
||||
ExtraCooling = 0.0f;
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
base.UpdateBroken(deltaTime, cam);
|
||||
|
||||
Temperature -= deltaTime * 1000.0f;
|
||||
FissionRate -= deltaTime * 10.0f;
|
||||
CoolingRate -= deltaTime * 10.0f;
|
||||
|
||||
currPowerConsumption = -temperature;
|
||||
|
||||
UpdateGraph(deltaTime);
|
||||
|
||||
ExtraCooling = 0.0f;
|
||||
}
|
||||
|
||||
private void UpdateGraph(float deltaTime)
|
||||
{
|
||||
graphTimer += deltaTime * 1000.0f;
|
||||
|
||||
if (graphTimer > updateGraphInterval)
|
||||
{
|
||||
UpdateGraph(fissionRateGraph, fissionRate);
|
||||
UpdateGraph(coolingRateGraph, coolingRate);
|
||||
UpdateGraph(tempGraph, temperature);
|
||||
graphTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void MeltDown()
|
||||
{
|
||||
if (item.Condition <= 0.0f) return;
|
||||
|
||||
new RepairTask(Game1.gameSession.taskManager, item, 50.0f, "Reactor meltdown!");
|
||||
item.Condition = 0.0f;
|
||||
fissionRate = 0.0f;
|
||||
coolingRate = 0.0f;
|
||||
|
||||
new Explosion(item.SimPosition, 6.0f, 500.0f, 600.0f, 10.0f, 2.0f).Explode();
|
||||
|
||||
//List<Structure> structureList = new List<Structure>();
|
||||
|
||||
//float dist = 600.0f;
|
||||
//foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
//{
|
||||
// Structure structure = entity as Structure;
|
||||
// if (structure == null) continue;
|
||||
|
||||
// if (structure.HasBody && Vector2.Distance(structure.Position, item.Position)<dist*3.0f)
|
||||
// {
|
||||
// structureList.Add(structure);
|
||||
// }
|
||||
//}
|
||||
|
||||
//foreach (Structure structure in structureList)
|
||||
//{
|
||||
// for (int i = 0; i < structure.SectionCount; i++)
|
||||
// {
|
||||
// float damage = dist - Vector2.Distance(structure.SectionPosition(i), item.Position);
|
||||
// if (damage > 0.0f) structure.AddDamage(i, damage);
|
||||
// }
|
||||
//}
|
||||
|
||||
//if (item.currentHull!=null)
|
||||
//{
|
||||
// item.currentHull.WaveVel[item.currentHull.GetWaveIndex(item.SimPosition)] = 100.0f;
|
||||
//}
|
||||
|
||||
if (item.ContainedItems!=null)
|
||||
{
|
||||
foreach (Item containedItem in item.ContainedItems)
|
||||
{
|
||||
if (containedItem == null) continue;
|
||||
containedItem.Condition = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
if (picker == null) return false;
|
||||
|
||||
//picker.SelectedConstruction = (picker.SelectedConstruction==item) ? null : item;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
base.Draw(spriteBatch);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 6, -item.Rect.Y + 29),
|
||||
new Vector2(12, 42), Color.Black);
|
||||
|
||||
if (temperature > 0)
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(item.Rect.X + item.Rect.Width / 2 - 5, -item.Rect.Y + 30 + (40.0f * (1.0f - temperature / 10000.0f))),
|
||||
new Vector2(10, 40 * (temperature / 10000.0f)), new Color(temperature / 10000.0f, 1.0f - (temperature / 10000.0f), 0.0f, 1.0f), true);
|
||||
}
|
||||
|
||||
|
||||
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
isActive = true;
|
||||
|
||||
int width = 500, height = 420;
|
||||
int x = Game1.GraphicsWidth / 2 - width / 2;
|
||||
int y = Game1.GraphicsHeight / 2 - height / 2 - 50;
|
||||
|
||||
float xOffset = (graphTimer / (float)updateGraphInterval);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Temperature: " + (int)temperature + " C", new Vector2(x + 30, y + 30), Color.White);
|
||||
DrawGraph(tempGraph, spriteBatch, x + 30, y + 50, 10000.0f, xOffset);
|
||||
|
||||
y += 130;
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Fission rate: " + (int)fissionRate + " %", new Vector2(x + 30, y + 30), Color.White);
|
||||
DrawGraph(fissionRateGraph, spriteBatch, x + 30, y + 50, 100.0f, xOffset);
|
||||
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) FissionRate += 1.0f;
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) FissionRate -= 1.0f;
|
||||
|
||||
y += 130;
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Cooling rate: " + (int)coolingRate + " %", new Vector2(x + 30, y + 30), Color.White);
|
||||
DrawGraph(coolingRateGraph, spriteBatch, x + 30, y + 50, 100.0f, xOffset);
|
||||
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 30, 40, 40), "+", true)) CoolingRate += 1.0f;
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 280, y + 80, 40, 40), "-", true)) CoolingRate -= 1.0f;
|
||||
|
||||
y = y - 260;
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Autotemp: " + ((autoTemp) ? "ON" : "OFF"), new Vector2(x + 400, y + 30), Color.White);
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 400, y + 60, 100, 40), ((autoTemp) ? "TURN OFF" : "TURN ON"))) autoTemp = !autoTemp;
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Max temperature: " + shutDownTemp, new Vector2(x + 400, y + 150), Color.White);
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 400, y + 180, 40, 40), "+", true)) shutDownTemp += 100.0f;
|
||||
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 450, y + 180, 40, 40), "-", true)) shutDownTemp -= 100.0f;
|
||||
|
||||
item.NewComponentEvent(this, true);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void UpdateGraph<T>(IList<T> graph, T newValue)
|
||||
{
|
||||
for (int i = graph.Count - 1; i > 0; i--)
|
||||
{
|
||||
graph[i] = graph[i - 1];
|
||||
}
|
||||
graph[0] = newValue;
|
||||
}
|
||||
|
||||
static void DrawGraph(IList<float> graph, SpriteBatch spriteBatch, int x, int y, float maxVal, float xOffset)
|
||||
{
|
||||
int width = 200;
|
||||
int height = 100;
|
||||
|
||||
float lineWidth = (float)width / (float)(graph.Count - 2);
|
||||
float yScale = (float)height / maxVal;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.White);
|
||||
|
||||
Vector2 prevPoint = new Vector2(x, y + height - (graph[1] + (graph[0] - graph[1]) * xOffset) * yScale);
|
||||
|
||||
float currX = x + ((xOffset - 1.0f) * lineWidth);
|
||||
|
||||
for (int i = 1; i < graph.Count - 1; i++)
|
||||
{
|
||||
currX += lineWidth;
|
||||
|
||||
Vector2 newPoint = new Vector2(currX, y + height - graph[i] * yScale);
|
||||
|
||||
GUI.DrawLine(spriteBatch, prevPoint, newPoint, Color.White);
|
||||
|
||||
prevPoint = newPoint;
|
||||
}
|
||||
|
||||
Vector2 lastPoint = new Vector2(x + width,
|
||||
y + height - (graph[graph.Count - 1] + (graph[graph.Count - 2] - graph[graph.Count - 1]) * xOffset) * yScale);
|
||||
|
||||
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, Color.Red);
|
||||
}
|
||||
|
||||
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message)
|
||||
{
|
||||
message.Write(autoTemp);
|
||||
message.Write(temperature);
|
||||
message.Write(shutDownTemp);
|
||||
|
||||
message.Write(coolingRate);
|
||||
message.Write(fissionRate);
|
||||
}
|
||||
|
||||
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)
|
||||
{
|
||||
autoTemp = message.ReadBoolean();
|
||||
temperature = message.ReadFloat();
|
||||
shutDownTemp = message.ReadFloat();
|
||||
|
||||
coolingRate = message.ReadFloat();
|
||||
fissionRate = message.ReadFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class RepairTool : ItemComponent
|
||||
{
|
||||
List<string> fixableEntities;
|
||||
|
||||
float range;
|
||||
|
||||
Vector2 pickedPosition;
|
||||
|
||||
float structureFixAmount, limbFixAmount;
|
||||
|
||||
[HasDefaultValue(100.0f, false)]
|
||||
private float Range
|
||||
{
|
||||
set { range = ConvertUnits.ToSimUnits(value); }
|
||||
}
|
||||
|
||||
[HasDefaultValue(1.0f, false)]
|
||||
private float StructureFixAmount
|
||||
{
|
||||
set { structureFixAmount = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(1.0f, false)]
|
||||
private float LimbFixAmount
|
||||
{
|
||||
set { limbFixAmount = value; }
|
||||
}
|
||||
|
||||
public RepairTool(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
this.item = item;
|
||||
|
||||
//range = ToolBox.GetAttributeFloat(element, "range", 100.0f);
|
||||
//range = ConvertUnits.ToSimUnits(range);
|
||||
|
||||
//structureFixAmount = ToolBox.GetAttributeFloat(element, "structurefixamount", 1.0f);
|
||||
//limbFixAmount = ToolBox.GetAttributeFloat(element, "limbfixamount", -0.5f);
|
||||
|
||||
|
||||
fixableEntities = new List<string>();
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLower())
|
||||
{
|
||||
case "fixable":
|
||||
fixableEntities.Add(subElement.Attribute("name").Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//public override void Update(float deltaTime, Camera cam)
|
||||
//{
|
||||
// base.Update(deltaTime, cam);
|
||||
|
||||
//}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (character == null) return false;
|
||||
|
||||
Vector2 targetPosition = item.body.Position;
|
||||
//targetPosition = targetPosition.X, -targetPosition.Y);
|
||||
|
||||
targetPosition += new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation) * range,
|
||||
(float)Math.Sin(item.body.Rotation) * range) * item.body.Dir;
|
||||
|
||||
List<Body> ignoredBodies = new List<Body>();
|
||||
foreach (Limb limb in character.animController.limbs)
|
||||
{
|
||||
ignoredBodies.Add(limb.body.FarseerBody);
|
||||
}
|
||||
|
||||
|
||||
Body targetBody = Map.PickBody(item.body.Position, targetPosition, ignoredBodies);
|
||||
pickedPosition = Map.LastPickedPosition;
|
||||
|
||||
if (targetBody==null || targetBody.UserData==null) return false;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, character);
|
||||
|
||||
|
||||
Structure targetStructure;
|
||||
Limb targetLimb;
|
||||
Item targetItem;
|
||||
if ((targetStructure = (targetBody.UserData as Structure)) != null)
|
||||
{
|
||||
if (!fixableEntities.Contains(targetStructure.Name)) return false;
|
||||
|
||||
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
|
||||
if (sectionIndex < 0) return false;
|
||||
|
||||
targetStructure.HighLightSection(sectionIndex);
|
||||
|
||||
if (character.SecondaryKeyDown.State)
|
||||
{
|
||||
targetStructure.AddDamage(sectionIndex, -structureFixAmount);
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
}
|
||||
else if ((targetLimb = (targetBody.UserData as Limb)) != null)
|
||||
{
|
||||
if (character.SecondaryKeyDown.State)
|
||||
{
|
||||
targetLimb.Damage -= limbFixAmount;
|
||||
isActive = true;
|
||||
}
|
||||
}
|
||||
else if ((targetItem = (targetBody.UserData as Item)) !=null)
|
||||
{
|
||||
targetItem.Condition -= structureFixAmount;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!isActive) return;
|
||||
|
||||
Vector2 startPos = ConvertUnits.ToDisplayUnits(item.body.Position);
|
||||
Vector2 endPos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||
endPos = new Vector2(endPos.X + Game1.localRandom.Next(-2, 2), endPos.Y + Game1.localRandom.Next(-2, 2));
|
||||
|
||||
GUI.DrawLine(spriteBatch, startPos, endPos, Color.Orange, 0.0f);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Collision.Shapes;
|
||||
using FarseerPhysics.Common;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Joints;
|
||||
using FarseerPhysics.Factories;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Rope : ItemComponent
|
||||
{
|
||||
PhysicsBody[] ropeBodies;
|
||||
RevoluteJoint[] ropeJoints;
|
||||
|
||||
DistanceJoint gunJoint;
|
||||
|
||||
float pullForce;
|
||||
|
||||
Sprite sprite;
|
||||
|
||||
float reload;
|
||||
|
||||
float prevDir;
|
||||
|
||||
float sectionLength;
|
||||
|
||||
Item projectile;
|
||||
|
||||
Vector2 projectileAnchor;
|
||||
|
||||
private Vector2 BarrelPos
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector2 barrelPos = Vector2.Zero;
|
||||
|
||||
RangedWeapon weapon = item.GetComponent<RangedWeapon>();
|
||||
if (weapon != null) barrelPos = weapon.BarrelPos;
|
||||
|
||||
return barrelPos;
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 TransformedBarrelPos
|
||||
{
|
||||
get
|
||||
{
|
||||
Vector2 barrelPos = Vector2.Zero;
|
||||
|
||||
RangedWeapon weapon = item.GetComponent<RangedWeapon>();
|
||||
if (weapon != null) barrelPos = weapon.TransformedBarrelPos;
|
||||
|
||||
return barrelPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Rope(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
string spritePath = ToolBox.GetAttributeString(element, "sprite", "");
|
||||
if (spritePath == "") DebugConsole.ThrowError("Sprite "+spritePath+" in "+element+" not found!");
|
||||
|
||||
float length = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "length", 200.0f));
|
||||
|
||||
pullForce = ToolBox.GetAttributeFloat(element, "pullforce", 10.0f);
|
||||
|
||||
projectileAnchor = Vector2.Zero;
|
||||
projectileAnchor.X = ToolBox.GetAttributeFloat(element, "projectileanchorx", 0.0f);
|
||||
projectileAnchor.Y = ToolBox.GetAttributeFloat(element, "projectileanchory", 0.0f);
|
||||
projectileAnchor = ConvertUnits.ToSimUnits(projectileAnchor);
|
||||
|
||||
characterUsable = ToolBox.GetAttributeBool(element, "characterusable", false);
|
||||
|
||||
sprite = new Sprite(spritePath, new Vector2(0.5f,0.5f));
|
||||
sectionLength = ConvertUnits.ToSimUnits(sprite.size.X);
|
||||
|
||||
|
||||
Path ropePath = new Path();
|
||||
ropePath.Add(item.body.Position);
|
||||
ropePath.Add(item.body.Position + new Vector2(length, 0.0f));
|
||||
ropePath.Closed = false;
|
||||
|
||||
Vertices box = PolygonTools.CreateRectangle(sectionLength, 0.05f);
|
||||
PolygonShape shape = new PolygonShape(box, 5);
|
||||
|
||||
List<Body>ropeList = PathManager.EvenlyDistributeShapesAlongPath(Game1.world, ropePath, shape, BodyType.Dynamic, (int)(length/sectionLength));
|
||||
|
||||
ropeBodies = new PhysicsBody[ropeList.Count()];
|
||||
for (int i = 0; i<ropeBodies.Length; i++)
|
||||
{
|
||||
ropeList[i].Mass = 0.01f;
|
||||
ropeList[i].Enabled = false;
|
||||
//only collide with the map
|
||||
ropeList[i].CollisionCategories = Physics.CollisionMisc;
|
||||
ropeList[i].CollidesWith = Physics.CollisionWall;
|
||||
|
||||
ropeBodies[i] = new PhysicsBody(ropeList[i]);
|
||||
}
|
||||
|
||||
List<RevoluteJoint> joints = PathManager.AttachBodiesWithRevoluteJoint(Game1.world, ropeList,
|
||||
new Vector2(-sectionLength/2, 0.0f), new Vector2(sectionLength/2, 0.0f), false, false);
|
||||
|
||||
ropeJoints = new RevoluteJoint[joints.Count+1];
|
||||
//ropeJoints[0] = JointFactory.CreateRevoluteJoint(Game1.world, item.body, ropeList[0], new Vector2(0f, -0.0f));
|
||||
for (int i = 0; i < joints.Count; i++)
|
||||
{
|
||||
var distanceJoint = JointFactory.CreateDistanceJoint(Game1.world, ropeList[i], ropeList[i + 1]);
|
||||
|
||||
distanceJoint.Length = sectionLength;
|
||||
distanceJoint.DampingRatio = 1.0f;
|
||||
ropeJoints[i] = joints[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void SecondaryUse(Character character = null)
|
||||
{
|
||||
if (reload > 0.0f) return;
|
||||
|
||||
bool first = true;
|
||||
for (int i = 0; i < ropeBodies.Length - 1; i++)
|
||||
{
|
||||
if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData) continue;
|
||||
|
||||
if (first)
|
||||
{
|
||||
Vector2 dist = gunJoint.WorldAnchorA - ropeJoints[i].WorldAnchorA;
|
||||
float length = dist.Length();
|
||||
|
||||
if (gunJoint.Length < 0.011 && length*0.5f<sectionLength)
|
||||
{
|
||||
NextSection(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
gunJoint.Length = Math.Max(gunJoint.Length-0.003f,0.01f);
|
||||
gunJoint.Frequency = 30;
|
||||
gunJoint.DampingRatio = 0.05f;
|
||||
//gunJoint.MotorEnabled = true;
|
||||
//gunJoint.MotorSpeed = -150.0f;
|
||||
//ropeBodies[i + 1].ApplyForce(dist / length * pullForce);
|
||||
//ropeJoints[0].LocalAnchorA = new Vector2(ropeJoints[0].LocalAnchorA.X-0.05f,ropeJoints[0].LocalAnchorA.Y);
|
||||
//ropeBodies[i].SmoothRotate(item.body.Rotation);
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Vector2 dist = ropeBodies[i].Position - ropeBodies[i + 1].Position;
|
||||
//float length = dist.Length();
|
||||
|
||||
//ropeBodies[i + 1].ApplyForce(dist / length * pullForce * 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void NextSection(int i)
|
||||
{
|
||||
gunJoint.Length = sectionLength;
|
||||
ropeBodies[i].UserData = true;
|
||||
ropeBodies[i].Enabled = false;
|
||||
|
||||
//if (ropeJoints[0] != null) Game1.world.RemoveJoint(ropeJoints[0]);
|
||||
//ropeJoints[0] = JointFactory.CreateRevoluteJoint(Game1.world,
|
||||
// item.body.FarseerBody, ropeBodies[i + 1].FarseerBody,
|
||||
// BarrelPos, new Vector2(-sectionLength / 2, 0.0f));
|
||||
|
||||
AttachGunJoint(ropeBodies[i + 1].FarseerBody);
|
||||
|
||||
if (i == ropeBodies.Length - 2)
|
||||
{
|
||||
item.Combine(projectile);
|
||||
ropeBodies[ropeBodies.Length - 1].Enabled = false;
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (reload>0.0f) reload -= deltaTime;
|
||||
|
||||
//for (int i = 0; i < ropeBodies.Length - 1; i++)
|
||||
//{
|
||||
// if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData == true) continue;
|
||||
// ropeBodies[i].SmoothRotate(item.body.Rotation);
|
||||
//}
|
||||
|
||||
int len = 1;
|
||||
for (int i = 0; i < ropeBodies.Length - 1; i++)
|
||||
{
|
||||
if (ropeBodies[i].UserData == null || (bool)ropeBodies[i].UserData) continue;
|
||||
len++;
|
||||
}
|
||||
|
||||
if (Vector2.Distance(TransformedBarrelPos, projectile.SimPosition)>len*sectionLength)
|
||||
{
|
||||
Vector2 stopForce = projectile.SimPosition - ropeBodies[ropeBodies.Length-1].Position;
|
||||
stopForce = Vector2.Normalize(stopForce);
|
||||
|
||||
float dotProduct = Vector2.Dot(stopForce, Vector2.Normalize(projectile.body.LinearVelocity));
|
||||
|
||||
if (dotProduct<0)
|
||||
projectile.body.ApplyLinearImpulse(-stopForce*dotProduct * projectile.body.LinearVelocity.Length() * projectile.body.Mass);
|
||||
}
|
||||
|
||||
if (item.body.Dir!=prevDir)
|
||||
{
|
||||
gunJoint.LocalAnchorA =
|
||||
new Vector2(
|
||||
-gunJoint.LocalAnchorA.X,
|
||||
BarrelPos.Y);
|
||||
|
||||
prevDir = -prevDir;
|
||||
}
|
||||
|
||||
if (!projectile.body.Enabled || !item.body.Enabled)
|
||||
{
|
||||
//attempt to recontain the projectile in the launcher
|
||||
//eq automatically reload a spear into a speargun when picking the spear up
|
||||
if (!projectile.body.Enabled) item.Combine(projectile);
|
||||
|
||||
foreach (PhysicsBody b in ropeBodies)
|
||||
{
|
||||
b.Enabled = false;
|
||||
}
|
||||
foreach (var joint in ropeJoints)
|
||||
{
|
||||
if (joint != null) joint.Enabled = false;
|
||||
}
|
||||
isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
base.Draw(spriteBatch);
|
||||
|
||||
if (!isActive) return;
|
||||
|
||||
RevoluteJoint firstJoint = null;
|
||||
|
||||
for (int i = 0; i<ropeBodies.Length-1; i++)
|
||||
{
|
||||
if (!ropeBodies[i].Enabled) continue;
|
||||
|
||||
if (firstJoint==null) firstJoint = ropeJoints[i];
|
||||
|
||||
DrawSection(spriteBatch, ropeJoints[i].WorldAnchorA, ropeJoints[i+1].WorldAnchorA, i);
|
||||
}
|
||||
|
||||
if (gunJoint == null || firstJoint==null) return;
|
||||
|
||||
DrawSection(spriteBatch, gunJoint.WorldAnchorA, firstJoint.WorldAnchorA, 0);
|
||||
|
||||
}
|
||||
|
||||
private void DrawSection(SpriteBatch spriteBatch, Vector2 start, Vector2 end, int i)
|
||||
{
|
||||
start.Y = -start.Y;
|
||||
end.Y = -end.Y;
|
||||
|
||||
spriteBatch.Draw(sprite.Texture,
|
||||
ConvertUnits.ToDisplayUnits(start), null, Color.White,
|
||||
ToolBox.VectorToAngle(end - start),
|
||||
new Vector2(0.0f, sprite.size.Y / 2.0f),
|
||||
new Vector2((ConvertUnits.ToDisplayUnits(Vector2.Distance(start, end))) / sprite.Texture.Width, 1.0f),
|
||||
SpriteEffects.None,
|
||||
sprite.Depth + i*0.00001f);
|
||||
}
|
||||
|
||||
public void Attach(Item projectile)
|
||||
{
|
||||
reload = 0.5f;
|
||||
isActive = true;
|
||||
|
||||
this.projectile = projectile;
|
||||
Projectile projectileComponent = projectile.GetComponent<Projectile>();
|
||||
|
||||
foreach (PhysicsBody b in ropeBodies)
|
||||
{
|
||||
b.SetTransform(item.body.Position, 0.0f);
|
||||
b.UserData = false;
|
||||
b.Enabled = true;
|
||||
}
|
||||
|
||||
foreach (var joint in ropeJoints)
|
||||
{
|
||||
if (joint!=null) joint.Enabled = true;
|
||||
}
|
||||
|
||||
ropeBodies[ropeBodies.Length - 1].SetTransform(projectile.body.Position, projectile.body.Rotation);
|
||||
|
||||
//attach projectile to the last section of the rope
|
||||
if (ropeJoints[ropeJoints.Length-1] != null) Game1.world.RemoveJoint(ropeJoints[ropeJoints.Length-1]);
|
||||
ropeJoints[ropeJoints.Length - 1] = JointFactory.CreateRevoluteJoint(Game1.world,
|
||||
projectile.body.FarseerBody, ropeBodies[ropeBodies.Length - 1].FarseerBody,
|
||||
projectileAnchor, new Vector2(sectionLength / 2, 0.0f));
|
||||
|
||||
AttachGunJoint(ropeBodies[0].FarseerBody);
|
||||
|
||||
prevDir = item.body.Dir;
|
||||
}
|
||||
|
||||
private void AttachGunJoint(Body body)
|
||||
{
|
||||
float rotation = (item.body.Dir == -1.0f) ? item.body.Rotation - MathHelper.Pi : item.body.Rotation;
|
||||
body.SetTransform(TransformedBarrelPos, rotation);
|
||||
Vector2 axis = new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation));
|
||||
|
||||
if (gunJoint != null) Game1.world.RemoveJoint(gunJoint);
|
||||
gunJoint = new DistanceJoint(item.body.FarseerBody, body, BarrelPos,
|
||||
new Vector2(sectionLength / 2, 0.0f));
|
||||
|
||||
gunJoint.Length = sectionLength;
|
||||
|
||||
//gunJoint.LocalAnchorA = BarrelPos;
|
||||
//gunJoint.LocalAnchorB = new Vector2(sectionLength / 2, 0.0f);
|
||||
//gunJoint.UpperLimit = sectionLength;
|
||||
//gunJoint.LowerLimit = 0.0f;
|
||||
//gunJoint.LimitEnabled = true;
|
||||
//gunJoint.ReferenceAngle = 0.0f;
|
||||
|
||||
Game1.world.AddJoint(gunJoint);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class AndComponent : ItemComponent
|
||||
{
|
||||
protected string output;
|
||||
|
||||
//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.1f, 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; }
|
||||
}
|
||||
|
||||
public AndComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
timeSinceReceived = new float[] { timeFrame*2.0f, timeFrame*2.0f};
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
if (sendOutput)
|
||||
{
|
||||
item.SendSignal(output, "signal_out");
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
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,434 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
|
||||
class Connection
|
||||
{
|
||||
private static Sprite connector;
|
||||
private static Sprite wireCorner, wireVertical, wireHorizontal;
|
||||
|
||||
//how many wires can be linked to a single connector
|
||||
private const int MaxLinked = 5;
|
||||
|
||||
public readonly string name;
|
||||
|
||||
public Wire[] wires;
|
||||
|
||||
private Item item;
|
||||
|
||||
public readonly bool isOutput;
|
||||
|
||||
private static Item draggingConnected;
|
||||
|
||||
int[] wireId;
|
||||
|
||||
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)
|
||||
{
|
||||
connector = new Sprite("Content/Items/connector.png", new Vector2(0.5f, 0.5f));
|
||||
wireCorner = new Sprite("Content/Items/wireCorner.png", new Vector2(0.5f, 0.1f));
|
||||
wireVertical = new Sprite("Content/Items/wireVertical.png", new Vector2(0.5f, 0.5f));
|
||||
wireHorizontal = new Sprite("Content/Items/wireHorizontal.png", new Vector2(0.5f, 0.5f));
|
||||
}
|
||||
|
||||
this.item = item;
|
||||
|
||||
//recipient = new Connection[MaxLinked];
|
||||
wires = new Wire[MaxLinked];
|
||||
|
||||
isOutput = (element.Name.ToString() == "output");
|
||||
name = ToolBox.GetAttributeString(element, "name", (isOutput) ? "output" : "input");
|
||||
|
||||
wireId = new int[MaxLinked];
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
for (int i = 0; i < MaxLinked; i++)
|
||||
{
|
||||
if (wireId[i]<1) index = i;
|
||||
}
|
||||
if (index == -1) break;
|
||||
|
||||
wireId[index] = ToolBox.GetAttributeInt(subElement, "w", -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 AddLink(int index, Wire wire)
|
||||
{
|
||||
//linked[index] = connectedItem;
|
||||
//recipient[index] = otherConnection;
|
||||
wires[index] = wire;
|
||||
}
|
||||
|
||||
//public bool AddLink(Item connectedItem, Connection otherConnection)
|
||||
//{
|
||||
// if (linked.Contains(connectedItem)) return false;
|
||||
|
||||
// for (int i = 0; i<MaxLinked; i++)
|
||||
// {
|
||||
// if (linked[i]!=null) continue;
|
||||
|
||||
// linked[i] = connectedItem;
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
public void SendSignal(string signal, Item sender)
|
||||
{
|
||||
for (int i = 0; i<MaxLinked; i++)
|
||||
{
|
||||
if (wires[i]==null) continue;
|
||||
|
||||
Connection recipient = wires[i].OtherConnection(this);
|
||||
if (recipient == null) continue;
|
||||
|
||||
foreach (ItemComponent ic in recipient.item.components)
|
||||
{
|
||||
ic.ReceiveSignal(signal, recipient, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = Game1.GraphicsWidth/2 - width/2, y = Game1.GraphicsHeight - height;
|
||||
|
||||
Rectangle panelRect = new Rectangle(x, y, width, height);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, panelRect, Color.Black, true);
|
||||
|
||||
bool mouseInRect = panelRect.Contains(PlayerInput.MousePosition);
|
||||
|
||||
Vector2 rightPos = new Vector2(x + width - 110, y + 20);
|
||||
Vector2 leftPos = new Vector2(x + 110, y + 20);
|
||||
|
||||
float wireInterval = 10.0f;
|
||||
|
||||
float rightWireX = x+width / 2 + wireInterval;
|
||||
float leftWireX = x + width / 2 - wireInterval;
|
||||
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);
|
||||
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 + 20, rightPos.Y),
|
||||
new Vector2(rightWireX, y + height), mouseInRect);
|
||||
|
||||
rightPos.Y += 30;
|
||||
rightWireX += wireInterval;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Draw(spriteBatch, panel.Item, leftPos,
|
||||
new Vector2(leftPos.X - 100, leftPos.Y),
|
||||
new Vector2(leftWireX, y + height), mouseInRect);
|
||||
|
||||
leftPos.Y += 30;
|
||||
leftWireX -= wireInterval;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//draw a wire for all the items that are linked to this item, but not to any of the signal connections
|
||||
//foreach (MapEntity entity in panel.Item.linkedTo)
|
||||
//{
|
||||
// Item linked = entity as Item;
|
||||
// if (linked == null) continue;
|
||||
|
||||
// //if the item is already connected, don't draw it again
|
||||
// if (panel.connections.Find(c => c.linked.Contains()) != null) continue;
|
||||
|
||||
// DrawWire(spriteBatch, false, linked,
|
||||
// new Vector2(leftPos.X + (leftPos.Y - y), y + height- 50),
|
||||
// new Vector2(leftPos.X + (leftPos.Y - y), y + height), mouseInRect);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// leftPos.Y += 30.0f;
|
||||
//}
|
||||
|
||||
//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 &&
|
||||
panel.connections.Find(c => c.wires.Contains(wireComponent)) == null)
|
||||
{
|
||||
DrawWire(spriteBatch, selectedItem, selectedItem,
|
||||
new Vector2(x + width / 2, y + height - 100),
|
||||
new Vector2(x + width / 2, y + height), mouseInRect);
|
||||
|
||||
if (draggingConnected == selectedItem) Inventory.draggingItem = selectedItem;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//stop dragging a wire item if cursor is outside the panel
|
||||
if (mouseInRect) Inventory.draggingItem = null;
|
||||
|
||||
if (draggingConnected != null)
|
||||
{
|
||||
if (!PlayerInput.LeftButtonDown())
|
||||
{
|
||||
panel.Item.NewComponentEvent(panel, true);
|
||||
draggingConnected = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Draw(SpriteBatch spriteBatch, Item item, Vector2 position, Vector2 labelPos, Vector2 wirePosition, bool mouseIn)
|
||||
{
|
||||
|
||||
spriteBatch.DrawString(GUI.font, name, new Vector2(labelPos.X, labelPos.Y-10), Color.White);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)position.X-10, (int)position.Y-10, 20, 20), Color.White);
|
||||
|
||||
|
||||
for (int i = 0; i<MaxLinked; i++)
|
||||
{
|
||||
if (wires[i]==null) continue;
|
||||
|
||||
Connection recipient = wires[i].OtherConnection(this);
|
||||
|
||||
DrawWire(spriteBatch, wires[i].Item, (recipient == null) ? wires[i].Item : recipient.item, position, wirePosition, mouseIn);
|
||||
wirePosition.X += (isOutput) ? -20 : 20;
|
||||
}
|
||||
|
||||
//dragging a wire and released the mouse -> see if the wire can be connected to this connection
|
||||
if (draggingConnected != null
|
||||
&& !PlayerInput.LeftButtonDown())
|
||||
{
|
||||
//close enough to the connector -> make a new connection
|
||||
if (Vector2.Distance(position, PlayerInput.MousePosition) < 10.0f)
|
||||
{
|
||||
//find an empty cell for the new connection
|
||||
int index = FindWireIndex(null);
|
||||
|
||||
Wire wireComponent = draggingConnected.GetComponent<Wire>();
|
||||
|
||||
if (index>-1 && wireComponent!=null && !wires.Contains(wireComponent))
|
||||
{
|
||||
wires[index] = wireComponent;
|
||||
wireComponent.Connect(this);
|
||||
}
|
||||
}
|
||||
//far away -> disconnect if the wire is linked to this connector
|
||||
else
|
||||
{
|
||||
int index = FindWireIndex(draggingConnected);
|
||||
if (index>-1)
|
||||
{
|
||||
wires[index].RemoveConnection(this);
|
||||
wires[index] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static void DrawWire(SpriteBatch spriteBatch, Item wireItem, Item item, Vector2 end, Vector2 start, bool mouseIn)
|
||||
{
|
||||
if (draggingConnected == wireItem)
|
||||
{
|
||||
if (!mouseIn) return;
|
||||
end = PlayerInput.MousePosition;
|
||||
}
|
||||
else if (draggingConnected == null)
|
||||
{
|
||||
if (Vector2.Distance(end, PlayerInput.MousePosition)<20.0f)
|
||||
{
|
||||
item.IsHighlighted = true;
|
||||
//start dragging the wire
|
||||
if (PlayerInput.LeftButtonDown()) draggingConnected = wireItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int textX = (int)start.X;
|
||||
float connLength = 10.0f;
|
||||
|
||||
if (Math.Abs(end.X-start.X)<connLength*6.0f)
|
||||
{
|
||||
wireVertical.DrawTiled(spriteBatch,
|
||||
new Vector2(end.X - wireVertical.size.X / 2, end.Y + connLength),
|
||||
new Vector2(wireVertical.size.X, (float)Math.Abs(end.Y - start.Y)), Color.White);
|
||||
textX = (int)end.X;
|
||||
connector.Draw(spriteBatch, end);
|
||||
}
|
||||
else
|
||||
{
|
||||
wireVertical.DrawTiled(spriteBatch,
|
||||
new Vector2(start.X, end.Y + wireCorner.size.Y) - wireVertical.size / 2,
|
||||
new Vector2(wireVertical.size.X, (float)Math.Abs((end.Y + wireCorner.size.Y) - start.Y)), Color.White);
|
||||
|
||||
float dir = (end.X > start.X) ? -1.0f : 1.0f;
|
||||
|
||||
wireCorner.Draw(spriteBatch,
|
||||
new Vector2(start.X, end.Y), 0.0f, 1.0f,
|
||||
(end.X > start.X) ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
|
||||
|
||||
float wireStartX = start.X - wireCorner.size.X / 2 * dir;
|
||||
float wireEndX = end.X + connLength * dir;
|
||||
|
||||
wireHorizontal.DrawTiled(spriteBatch, new Vector2(Math.Min(wireStartX,wireEndX), end.Y - wireVertical.size.Y / 2),
|
||||
new Vector2(Math.Abs(wireStartX - wireEndX), wireHorizontal.size.Y), Color.White);
|
||||
|
||||
|
||||
connector.Draw(spriteBatch, end, -MathHelper.PiOver2*dir);
|
||||
}
|
||||
|
||||
spriteBatch.DrawString(GUI.font, item.Name,
|
||||
new Vector2(textX, start.Y-30),
|
||||
Color.White,
|
||||
MathHelper.PiOver2,
|
||||
GUI.font.MeasureString(item.Name)*0.5f,
|
||||
1.0f, SpriteEffects.None, 0.0f);
|
||||
}
|
||||
|
||||
public void Save(XElement parentElement)
|
||||
{
|
||||
XElement newElement = new XElement(isOutput ? "output" : "input", new XAttribute("name", name));
|
||||
|
||||
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] == null) ? "-1" : 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] == -1) continue;
|
||||
|
||||
Item wireItem = MapEntity.FindEntityByID(wireId[i]) as Item;
|
||||
|
||||
if (wireItem == null) continue;
|
||||
|
||||
wires[i] = wireItem.GetComponent<Wire>();
|
||||
|
||||
if (wires[i]!=null)
|
||||
{
|
||||
wires[i].Item.body.Enabled = false;
|
||||
wires[i].Connect(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
wireId = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class ConnectionPanel : ItemComponent
|
||||
{
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawHUD(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Character character)
|
||||
{
|
||||
if (user!=character) return;
|
||||
Connection.DrawConnections(spriteBatch, this, character);
|
||||
}
|
||||
|
||||
public override XElement Save(XElement parentElement)
|
||||
{
|
||||
XElement componentElement = base.Save(parentElement);
|
||||
|
||||
foreach (Connection c in connections)
|
||||
{
|
||||
//XElement newElement = new XElement(c.isOutput ? "output" : "input", new XAttribute("name", c.name));
|
||||
|
||||
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 Pick(Character picker)
|
||||
{
|
||||
user = picker;
|
||||
isActive = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void Load(XElement element)
|
||||
{
|
||||
base.Load(element);
|
||||
|
||||
connections.Clear();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
|
||||
{
|
||||
foreach (Connection c in connections)
|
||||
{
|
||||
int wireCount = c.wires.Length;
|
||||
for (int i = 0 ; i < wireCount; i++)
|
||||
{
|
||||
message.Write(c.wires[i]==null ? -1 : c.wires[i].Item.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("connectionpanel update");
|
||||
foreach (Connection c in connections)
|
||||
{
|
||||
int wireCount = c.wires.Length;
|
||||
c.ClearConnections();
|
||||
|
||||
for (int i = 0; i < wireCount; i++)
|
||||
{
|
||||
int wireId = message.ReadInt32();
|
||||
if (wireId == -1) continue;
|
||||
|
||||
Item wireItem = MapEntity.FindEntityByID(wireId) as Item;
|
||||
if (wireItem == null) continue;
|
||||
|
||||
Wire wireComponent = wireItem.GetComponent<Wire>();
|
||||
if (wireComponent == null) continue;
|
||||
|
||||
c.wires[i] = wireComponent;
|
||||
wireComponent.Connect(c, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class LightComponent : ItemComponent
|
||||
{
|
||||
private Color lightColor;
|
||||
|
||||
private Sprite sprite;
|
||||
|
||||
[InGameEditable, HasDefaultValue("1.0,1.0,1.0,1.0", true)]
|
||||
public string LightColor
|
||||
{
|
||||
get { return ToolBox.Vector4ToString(lightColor.ToVector4()); }
|
||||
set
|
||||
{
|
||||
lightColor = new Color(ToolBox.ParseToVector4(value));
|
||||
}
|
||||
}
|
||||
|
||||
public LightComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLower() != "sprite") continue;
|
||||
sprite = new Sprite(subElement);
|
||||
break;
|
||||
}
|
||||
|
||||
//lightColor = new Color(ToolBox.GetAttributeVector4(element, "color", Vector4.One));
|
||||
}
|
||||
|
||||
public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!isActive || sprite==null) return;
|
||||
sprite.Draw(spriteBatch, new Vector2(item.Position.X, -item.Position.Y), 0.0f, 1.0f, Microsoft.Xna.Framework.Graphics.SpriteEffects.None);
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
switch (connection.name)
|
||||
{
|
||||
case "toggle":
|
||||
isActive = !isActive;
|
||||
break;
|
||||
case "set_state":
|
||||
isActive = (signal == "0") ? false : true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class NotComponent : ItemComponent
|
||||
{
|
||||
public NotComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
if (connection.name != "signal_in") return;
|
||||
|
||||
item.SendSignal(signal=="0" ? "1" : "0", "signal_out", item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class OrComponent : AndComponent
|
||||
{
|
||||
public OrComponent(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (sendOutput)
|
||||
{
|
||||
item.SendSignal(output, "signal_out");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class OxygenDetector : ItemComponent
|
||||
{
|
||||
private Hull hull;
|
||||
|
||||
public OxygenDetector(Item item, XElement element)
|
||||
: base (item, element)
|
||||
{
|
||||
hull = Hull.FindHull(item.Position);
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
hull = Hull.FindHull(item.Position);
|
||||
}
|
||||
|
||||
public override void Move(Microsoft.Xna.Framework.Vector2 amount)
|
||||
{
|
||||
hull = Hull.FindHull(item.Position);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (hull == null) return;
|
||||
|
||||
item.SendSignal(((int)hull.OxygenPercentage).ToString(), "signal_out");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Xml.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class RegExFindComponent : ItemComponent
|
||||
{
|
||||
private string output;
|
||||
|
||||
private string expression;
|
||||
|
||||
[InGameEditable, HasDefaultValue("1", true)]
|
||||
public string Output
|
||||
{
|
||||
get { return output; }
|
||||
set { output = value; }
|
||||
}
|
||||
|
||||
[InGameEditable, HasDefaultValue("", true)]
|
||||
public string Expression
|
||||
{
|
||||
get { return expression; }
|
||||
set { expression = value; }
|
||||
}
|
||||
|
||||
public RegExFindComponent(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ReceiveSignal(string signal, Connection connection, Item sender)
|
||||
{
|
||||
switch (connection.name)
|
||||
{
|
||||
case "signal_in":
|
||||
if (string.IsNullOrWhiteSpace(expression)) return;
|
||||
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
Regex regex = new Regex(@expression);
|
||||
Match match = regex.Match(signal);
|
||||
success = match.Success;
|
||||
}
|
||||
catch
|
||||
{
|
||||
item.SendSignal("ERROR", "signal_out", item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
item.SendSignal(output, "signal_out", item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.SendSignal("0", "signal_out", item);
|
||||
}
|
||||
|
||||
break;
|
||||
case "set_output":
|
||||
output = signal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Wire : ItemComponent
|
||||
{
|
||||
const float nodeDistance = 128.0f;
|
||||
|
||||
static Sprite wireSprite;
|
||||
|
||||
List<Vector2> nodes;
|
||||
|
||||
Connection[] 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>();
|
||||
|
||||
connections = new Connection[2];
|
||||
}
|
||||
|
||||
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 void RemoveConnection(Connection connection)
|
||||
{
|
||||
if (connection == connections[0]) connections[0] = null;
|
||||
if (connection == connections[1]) connections[1] = null;
|
||||
}
|
||||
|
||||
public void Connect(Connection newConnection, bool addNode = true)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (connections[i] == newConnection) return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (connections[i] != null) continue;
|
||||
|
||||
connections[i] = newConnection;
|
||||
|
||||
if (!addNode) break;
|
||||
|
||||
if (i==0)
|
||||
{
|
||||
nodes.Insert(0, newConnection.Item.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.Add(newConnection.Item.Position);
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (connections[0]!=null && connections[1]!=null)
|
||||
{
|
||||
item.Drop(null, false);
|
||||
item.body.Enabled = false;
|
||||
|
||||
CleanNodes();
|
||||
}
|
||||
|
||||
//new Networking.NetworkEvent(item.ID, true);
|
||||
|
||||
}
|
||||
|
||||
public override void Equip(Character character)
|
||||
{
|
||||
ClearConnections();
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Unequip(Character character)
|
||||
{
|
||||
ClearConnections();
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (nodes.Count == 0) return;
|
||||
|
||||
if (Math.Abs(item.Position.X-nodes[nodes.Count-1].X)>nodeDistance)
|
||||
{
|
||||
nodes.Add(new Vector2(
|
||||
ToolBox.Round(item.Position.X, Map.gridSize.X),
|
||||
nodes[nodes.Count - 1].Y));
|
||||
|
||||
item.NewComponentEvent(this, true);
|
||||
}
|
||||
else if (Math.Abs(item.Position.Y-nodes[nodes.Count-1].Y)>nodeDistance)
|
||||
{
|
||||
nodes.Add(new Vector2(nodes[nodes.Count - 1].X,
|
||||
ToolBox.Round(item.Position.Y, Map.gridSize.Y)));
|
||||
|
||||
item.NewComponentEvent(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
//public override bool Use(Character character = null)
|
||||
//{
|
||||
// Vector2 nodePos = item.Position;
|
||||
// ToolBox.Round(nodePos.X, Map.gridSize.X);
|
||||
// ToolBox.Round(nodePos.Y, Map.gridSize.Y);
|
||||
|
||||
// nodes.Add(nodePos);
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
public override void SecondaryUse(Character character = null)
|
||||
{
|
||||
if (nodes.Count > 0)
|
||||
{
|
||||
nodes.RemoveAt(nodes.Count - 1);
|
||||
item.NewComponentEvent(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Pick(Character picker)
|
||||
{
|
||||
ClearConnections();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ClearConnections()
|
||||
{
|
||||
nodes.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;
|
||||
}
|
||||
}
|
||||
|
||||
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 override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)nodes[i].X, (int)-nodes[i].Y, 5, 5), Color.DarkGray, true, wireSprite.Depth - 0.01f);
|
||||
}
|
||||
|
||||
for (int i = 1; i<nodes.Count; i++)
|
||||
{
|
||||
DrawSection(spriteBatch, nodes[i], nodes[i - 1], i);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSection(SpriteBatch spriteBatch, Vector2 start, Vector2 end, int i)
|
||||
{
|
||||
start.Y = -start.Y;
|
||||
end.Y = -end.Y;
|
||||
|
||||
spriteBatch.Draw(wireSprite.Texture,
|
||||
start, null, Color.White,
|
||||
ToolBox.VectorToAngle(end - start),
|
||||
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
|
||||
new Vector2((Vector2.Distance(start, end)) / wireSprite.Texture.Width, 0.3f),
|
||||
SpriteEffects.None,
|
||||
wireSprite.Depth +0.1f + i * 0.00001f);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
|
||||
{
|
||||
message.Write(nodes.Count);
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
message.Write(nodes[i].X);
|
||||
message.Write(nodes[i].Y);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
|
||||
{
|
||||
nodes.Clear();
|
||||
int nodeCount = message.ReadInt32();
|
||||
for (int i = 0; i < nodeCount; i++)
|
||||
{
|
||||
nodes.Add(new Vector2(message.ReadFloat(), message.ReadFloat()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Throwable : Holdable
|
||||
{
|
||||
float throwForce;
|
||||
|
||||
float throwPos;
|
||||
|
||||
bool throwing;
|
||||
|
||||
[HasDefaultValue(1.0f, false)]
|
||||
private float ThrowForce
|
||||
{
|
||||
set { throwForce = value; }
|
||||
}
|
||||
|
||||
public Throwable(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//throwForce = ToolBox.GetAttributeFloat(element, "throwforce", 1.0f);
|
||||
}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (character == null) return false;
|
||||
if (!character.SecondaryKeyDown.State || throwing) return false;
|
||||
|
||||
throwing = true;
|
||||
|
||||
isActive = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SecondaryUse(Character character = null)
|
||||
{
|
||||
if (throwing) return;
|
||||
throwPos = 0.25f;
|
||||
}
|
||||
|
||||
public override void Drop(Character dropper)
|
||||
{
|
||||
base.Drop(dropper);
|
||||
|
||||
throwing = false;
|
||||
throwPos = 0.0f;
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (!item.body.Enabled) return;
|
||||
if (!picker.HasSelectedItem(item)) isActive = false;
|
||||
|
||||
if (!picker.SecondaryKeyDown.State && !throwing) throwPos = 0.0f;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
|
||||
|
||||
if (item.body.Dir != picker.animController.Dir) Flip(item);
|
||||
|
||||
AnimController ac = picker.animController;
|
||||
|
||||
ac.HoldItem(deltaTime, cam, item, handlePos, new Vector2(throwPos, 0.0f), Vector2.Zero, holdAngle);
|
||||
|
||||
if (!throwing) return;
|
||||
|
||||
throwPos +=0.1f;
|
||||
|
||||
Vector2 throwVector = ConvertUnits.ToSimUnits(picker.CursorPosition) - item.body.Position;
|
||||
throwVector = Vector2.Normalize(throwVector);
|
||||
|
||||
if (handlePos[0]!=Vector2.Zero)
|
||||
{
|
||||
Limb leftHand = ac.GetLimb(LimbType.LeftHand);
|
||||
leftHand.body.ApplyForce(throwVector*10.0f);
|
||||
}
|
||||
|
||||
if (handlePos[1] != Vector2.Zero)
|
||||
{
|
||||
Limb rightHand = ac.GetLimb(LimbType.RightHand);
|
||||
rightHand.body.ApplyForce(throwVector * 10.0f);
|
||||
}
|
||||
|
||||
if (throwPos>1.0f)
|
||||
{
|
||||
item.Drop();
|
||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Turret : Powered
|
||||
{
|
||||
Sprite barrelSprite;
|
||||
|
||||
Vector2 barrelPos;
|
||||
|
||||
float targetRotation;
|
||||
float rotation;
|
||||
|
||||
float reload;
|
||||
float reloadTime;
|
||||
|
||||
float minRotation;
|
||||
float maxRotation;
|
||||
|
||||
float launchImpulse;
|
||||
|
||||
Camera cam;
|
||||
|
||||
[HasDefaultValue("0,0", false)]
|
||||
public string BarrelPos
|
||||
{
|
||||
get
|
||||
{
|
||||
return ToolBox.Vector2ToString(barrelPos);
|
||||
}
|
||||
set
|
||||
{
|
||||
barrelPos = ToolBox.ParseToVector2(value);
|
||||
}
|
||||
}
|
||||
|
||||
[HasDefaultValue(0.0f, false)]
|
||||
public float LaunchImpulse
|
||||
{
|
||||
get { return launchImpulse; }
|
||||
set { launchImpulse = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue(5.0f, false)]
|
||||
public float Reload
|
||||
{
|
||||
get { return reloadTime; }
|
||||
set { reloadTime = value; }
|
||||
}
|
||||
|
||||
[HasDefaultValue("0.0,0.0", false)]
|
||||
public string RotationLimits
|
||||
{
|
||||
get
|
||||
{
|
||||
return ToolBox.Vector2ToString(barrelPos);
|
||||
}
|
||||
set
|
||||
{
|
||||
Vector2 vector = ToolBox.ParseToVector2(value);
|
||||
minRotation = MathHelper.ToRadians(vector.X);
|
||||
maxRotation = MathHelper.ToRadians(vector.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public Turret(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
isActive = true;
|
||||
|
||||
barrelSprite = new Sprite(Path.GetDirectoryName(item.Prefab.ConfigFile) + "\\" +element.Attribute("barrelsprite").Value,
|
||||
ToolBox.GetAttributeVector2(element, "origin", Vector2.Zero));
|
||||
|
||||
//barrelPos = ToolBox.GetAttributeVector2(element, "BarrelPos", Vector2.Zero);
|
||||
|
||||
//launchImpulse = ToolBox.GetAttributeFloat(element, "launchimpulse", 0.0f);
|
||||
|
||||
//minRotation = ToolBox.GetAttributeFloat(element, "MinimumRotation", 0.0f);
|
||||
//maxRotation = ToolBox.GetAttributeFloat(element, "MaximumRotation", MathHelper.TwoPi);
|
||||
|
||||
//reloadTime = ToolBox.GetAttributeFloat(element, "reload", 5.0f);
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
barrelSprite.Draw(spriteBatch, new Vector2(item.Rect.X, -item.Rect.Y) + barrelPos, rotation + MathHelper.PiOver2, 1.0f);
|
||||
|
||||
//GUI.DrawRectangle(spriteBatch,
|
||||
// new Rectangle((int)(rect.X + barrelPos.X), (int)(-rect.Y + barrelPos.Y), 10, 10),
|
||||
// Color.White, true);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
//if (character == null || character.SelectedConstruction != item)
|
||||
//{
|
||||
// character = null;
|
||||
// isActive = false;
|
||||
// return;
|
||||
//}
|
||||
|
||||
this.cam = cam;
|
||||
|
||||
if (reload>0.0f) reload -= deltaTime;
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
|
||||
|
||||
if (targetRotation < minRotation || targetRotation > maxRotation)
|
||||
{
|
||||
float diff = ToolBox.WrapAngleTwoPi(targetRotation - (minRotation + maxRotation) / 2.0f);
|
||||
targetRotation = (diff > Math.PI) ? minRotation : maxRotation;
|
||||
}
|
||||
|
||||
rotation = ToolBox.CurveAngle(rotation, targetRotation, 0.05f);
|
||||
|
||||
//if (!prefab.FocusOnSelected) return;
|
||||
|
||||
//cam.OffsetAmount = prefab.OffsetOnSelected;
|
||||
}
|
||||
|
||||
public override void SecondaryUse(Character character = null)
|
||||
{
|
||||
if (character == null) return;
|
||||
Vector2 centerPos = new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y);
|
||||
|
||||
Vector2 offset = character.CursorPosition - centerPos;
|
||||
offset.Y = -offset.Y;
|
||||
|
||||
targetRotation = ToolBox.WrapAngleTwoPi(ToolBox.VectorToAngle(offset));
|
||||
|
||||
isActive = true;
|
||||
|
||||
if (character == Character.Controlled && cam!=null)
|
||||
{
|
||||
Lights.LightManager.viewPos = centerPos;
|
||||
cam.TargetPos = new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Use(Character character = null)
|
||||
{
|
||||
if (reload > 0.0f) return false;
|
||||
|
||||
Projectile projectileComponent = null;
|
||||
|
||||
currPowerConsumption = powerConsumption;
|
||||
|
||||
float availablePower = 0.0f;
|
||||
List<PowerContainer> batteries = new List<PowerContainer>();
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item battery = e as Item;
|
||||
if (battery == null) continue;
|
||||
|
||||
PowerContainer batteryComponent = battery.GetComponent<PowerContainer>();
|
||||
if (batteryComponent == null) continue;
|
||||
|
||||
float batteryPower = Math.Min(batteryComponent.Charge, batteryComponent.MaxOutPut);
|
||||
float takePower = Math.Min(currPowerConsumption - availablePower, batteryPower);
|
||||
|
||||
batteryComponent.Charge -= takePower;
|
||||
availablePower += takePower;
|
||||
}
|
||||
|
||||
reload = reloadTime;
|
||||
|
||||
if (availablePower < currPowerConsumption) return false;
|
||||
|
||||
//search for a projectile from linked containers
|
||||
Item projectile = null;
|
||||
foreach (MapEntity e in item.linkedTo)
|
||||
{
|
||||
Item container = e as Item;
|
||||
if (container == null) continue;
|
||||
|
||||
ItemContainer containerComponent = container.GetComponent<ItemContainer>();
|
||||
if (containerComponent == null) continue;
|
||||
|
||||
for (int i = 0; i < containerComponent.inventory.items.Length; i++)
|
||||
{
|
||||
if (containerComponent.inventory.items[i] == null) continue;
|
||||
if ((projectileComponent = containerComponent.inventory.items[i].GetComponent<Projectile>()) != null)
|
||||
{
|
||||
projectile = containerComponent.inventory.items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (projectileComponent != null) break;
|
||||
}
|
||||
|
||||
if (projectile == null || projectileComponent==null) return false;
|
||||
|
||||
projectile.body.ResetDynamics();
|
||||
projectile.body.Enabled = true;
|
||||
projectile.SetTransform(item.SimPosition, rotation);
|
||||
|
||||
//if (useSounds.Count() > 0) useSounds[Game1.localRandom.Next(useSounds.Count())].Play(1.0f, 800.0f, item.body.FarseerBody);
|
||||
|
||||
projectileComponent.Use();
|
||||
item.RemoveContained(projectile);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Vent : ItemComponent
|
||||
{
|
||||
private float oxygenFlow;
|
||||
|
||||
public float OxygenFlow
|
||||
{
|
||||
get { return oxygenFlow; }
|
||||
set { oxygenFlow = Math.Max(value, 0.0f); }
|
||||
}
|
||||
|
||||
public Vent (Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
|
||||
if (item.currentHull == null) return;
|
||||
|
||||
item.currentHull.Oxygen += oxygenFlow * deltaTime;
|
||||
OxygenFlow -= deltaTime * 1000.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Subsurface.Items.Components
|
||||
{
|
||||
class Wearable : Pickable
|
||||
{
|
||||
Sprite[] sprite;
|
||||
LimbType[] limbType;
|
||||
Limb[] limb;
|
||||
|
||||
public Wearable (Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
this.item = item;
|
||||
|
||||
var sprites = element.Elements().Where(x => x.Name.ToString() == "sprite").ToList();
|
||||
int spriteCount = sprites.Count();
|
||||
sprite = new Sprite[spriteCount];
|
||||
limbType = new LimbType[spriteCount];
|
||||
limb = new Limb[spriteCount];
|
||||
|
||||
int i = 0;
|
||||
foreach (XElement subElement in sprites)
|
||||
{
|
||||
//Rectangle sourceRect = new Rectangle(
|
||||
// ToolBox.GetAttributeInt(subElement, "sourcex", 1),
|
||||
// ToolBox.GetAttributeInt(subElement, "sourcey", 1),
|
||||
// ToolBox.GetAttributeInt(subElement, "sourcewidth", 1),
|
||||
// ToolBox.GetAttributeInt(subElement, "sourceheight", 1));
|
||||
|
||||
if (subElement.Attribute("texture") == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Item ''" + item.Name + "'' doesn't have a texture specified!");
|
||||
return;
|
||||
}
|
||||
|
||||
string spritePath = subElement.Attribute("texture").Value;
|
||||
spritePath = Path.GetDirectoryName( item.Prefab.ConfigFile)+"\\"+spritePath;
|
||||
|
||||
sprite[i] = new Sprite(subElement, "", spritePath);
|
||||
//sprite[i].origin = new Vector2(sourceRect.Width / 2.0f, sourceRect.Height / 2.0f);
|
||||
|
||||
limbType[i] = (LimbType)Enum.Parse(typeof(LimbType),
|
||||
ToolBox.GetAttributeString(subElement, "limb", "Head"));
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Equip(Character character)
|
||||
{
|
||||
picker = character;
|
||||
for (int i = 0; i < sprite.Length; i++ )
|
||||
{
|
||||
Limb equipLimb = character.animController.GetLimb(limbType[i]);
|
||||
if (equipLimb == null) continue;
|
||||
|
||||
//something is already on the limb -> unequip it
|
||||
if (equipLimb.WearingItem != null && equipLimb.WearingItem != item)
|
||||
{
|
||||
equipLimb.WearingItem.Unequip(character);
|
||||
}
|
||||
|
||||
sprite[i].Depth = equipLimb.sprite.Depth - 0.001f;
|
||||
|
||||
item.body.Enabled = false;
|
||||
|
||||
isActive = true;
|
||||
|
||||
limb[i] = equipLimb;
|
||||
equipLimb.WearingItem = item;
|
||||
equipLimb.WearingItemSprite = sprite[i];
|
||||
}
|
||||
}
|
||||
|
||||
public override void Drop(Character dropper)
|
||||
{
|
||||
Unequip(picker);
|
||||
|
||||
base.Drop(dropper);
|
||||
|
||||
picker = null;
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void Unequip(Character character)
|
||||
{
|
||||
if (picker == null) return;
|
||||
for (int i = 0; i < sprite.Length; i++)
|
||||
{
|
||||
Limb equipLimb = character.animController.GetLimb(limbType[i]);
|
||||
if (equipLimb == null) continue;
|
||||
|
||||
if (equipLimb.WearingItem != item) continue;
|
||||
|
||||
limb[i] = null;
|
||||
equipLimb.WearingItem = null;
|
||||
equipLimb.WearingItemSprite = null;
|
||||
}
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
|
||||
Item[] containedItems = item.ContainedItems;
|
||||
|
||||
|
||||
for (int i = 0; i < limb.Length; i++)
|
||||
{
|
||||
if (limb[i] == null) continue;
|
||||
ApplyStatusEffects(ActionType.OnWearing, deltaTime, picker, limb[i]);
|
||||
|
||||
if (containedItems == null) continue;
|
||||
for (int j = 0; j<containedItems.Length; j++)
|
||||
{
|
||||
if (containedItems[j] == null) continue;
|
||||
containedItems[j].ApplyStatusEffects(ActionType.OnWearing, deltaTime, picker, limb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user