This commit is contained in:
Regalis
2015-07-31 21:05:55 +03:00
parent 23d847a4ac
commit 85b0cda4ca
181 changed files with 4455 additions and 4073 deletions
@@ -0,0 +1,273 @@
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
[HasDefaultValue(5, false)]
public int Capacity
{
get { return capacity; }
set { capacity = Math.Max(value, 1); }
}
private int capacity;
[HasDefaultValue(true, false)]
public bool HideItems
{
get { return hideItems; }
set { hideItems = value; }
}
private bool hideItems;
[HasDefaultValue(false, false)]
public bool DrawInventory
{
get { return drawInventory; }
set { drawInventory = value; }
}
private bool drawInventory;
//the position of the first item in the container
[HasDefaultValue("0.0,0.0", false)]
public string ItemPos
{
get { return ToolBox.Vector2ToString(itemPos); }
set { itemPos = ToolBox.ParseToVector2(value); }
}
private Vector2 itemPos;
//item[i].Pos = itemPos + itemInterval*i
[HasDefaultValue("0.0,0.0", false)]
public string ItemInterval
{
get { return ToolBox.Vector2ToString(itemInterval); }
set { itemInterval = ToolBox.ParseToVector2(value); }
}
private Vector2 itemInterval;
[HasDefaultValue(0.0f, false)]
public float ItemRotation
{
get { return itemRotation; }
set { itemRotation = value; }
}
private float itemRotation;
[HasDefaultValue("0.5,0.9", false)]
public string HudPos
{
get { return ToolBox.Vector2ToString(hudPos); }
set
{
hudPos = ToolBox.ParseToVector2(value);
//inventory.CenterPos = hudPos;
}
}
private Vector2 hudPos;
[HasDefaultValue(5, false)]
public int SlotsPerRow
{
get { return slotsPerRow; }
set { slotsPerRow = value; }
}
private int slotsPerRow;
public ItemContainer(Item item, XElement element)
: base (item, element)
{
inventory = new ItemInventory(this, capacity, hudPos, slotsPerRow);
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)
{
if (containableItems.Count == 0) return true;
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 || contained.Condition<=0.0f) continue;
if (contained.body!=null) contained.body.Enabled = false;
RelatedItem ri = containableItems.Find(x => x.MatchesItem(contained));
if (ri == null) continue;
foreach (StatusEffect effect in ri.statusEffects)
{
if (effect.Targets.HasFlag(StatusEffect.TargetType.This)) effect.Apply(ActionType.OnContaining, deltaTime, item, item.AllPropertyObjects);
if (effect.Targets.HasFlag(StatusEffect.TargetType.Contained)) effect.Apply(ActionType.OnContaining, deltaTime, item, contained.AllPropertyObjects);
}
contained.ApplyStatusEffects(ActionType.OnContained, deltaTime);
}
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
base.Draw(spriteBatch);
if (hideItems || (item.body!=null && !item.body.Enabled)) return;
Vector2 transformedItemPos = itemPos;
Vector2 transformedItemInterval = itemInterval;
float currentRotation = itemRotation;
//float transformedItemRotation = itemRotation;
if (item.body == null)
{
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
transformedItemPos = transformedItemPos + itemPos;
}
else
{
//item.body.Enabled = true;
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
if (item.body.Dir==-1.0f)
{
transformedItemPos.X = -transformedItemPos.X;
transformedItemInterval.X = -transformedItemInterval.X;
}
transformedItemPos = Vector2.Transform(transformedItemPos, transform);
transformedItemInterval = Vector2.Transform(transformedItemInterval, transform);
transformedItemPos += ConvertUnits.ToDisplayUnits(item.body.Position);
currentRotation += item.body.Rotation;
}
foreach (Item containedItem in inventory.items)
{
if (containedItem == null) continue;
containedItem.sprite.Draw(
spriteBatch,
new Vector2(transformedItemPos.X, -transformedItemPos.Y),
-currentRotation,
1.0f,
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
transformedItemPos += transformedItemInterval;
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (!drawInventory && false) return;
inventory.Draw(spriteBatch);
}
public override bool Pick(Character picker)
{
return (picker != null);
}
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!=null && !item.body.Enabled)) item.body.Enabled = false;
item.container = this.item;
return true;
}
return false;
}
public override void OnMapLoaded()
{
if (itemIds == null) return;
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;
}
}
}
+325
View File
@@ -0,0 +1,325 @@
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;
private float stuck;
public float Stuck
{
get { return stuck; }
set
{
if (isOpen) return;
stuck = MathHelper.Clamp(value, 0.0f, 100.0f);
if (stuck == 0.0f) isStuck = false;
if (stuck == 100.0f) isStuck = true;
}
}
private bool isStuck;
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;
}
}
private Rectangle doorRect;
public float OpenState
{
get { return openState; }
set
{
float prevValue = openState;
openState = MathHelper.Clamp(value, 0.0f, 1.0f);
if (openState == prevValue) return;
UpdateConvexHulls();
}
}
PhysicsBody body;
Sprite doorSprite;
public Door(Item item, XElement element)
: base(item, element)
{
//Vector2 position = new Vector2(newRect.X, newRect.Y);
// isOpen = false;
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLower() != "sprite") continue;
doorSprite = new Sprite(subElement, Path.GetDirectoryName(item.Prefab.ConfigFile));
break;
}
doorRect = new Rectangle(
item.Rect.Center.X - (int)(doorSprite.size.X / 2),
item.Rect.Y,
(int)doorSprite.size.X,
(int)doorSprite.size.Y);
body = new PhysicsBody(BodyFactory.CreateRectangle(Game1.World,
ConvertUnits.ToSimUnits(Math.Max(doorRect.Width, 1)),
ConvertUnits.ToSimUnits(Math.Max(doorRect.Height, 1)),
1.5f));
body.CollisionCategories = Physics.CollisionWall;
body.UserData = item;
body.BodyType = BodyType.Static;
body.SetTransform(
ConvertUnits.ToSimUnits(new Vector2(doorRect.Center.X, doorRect.Y - doorRect.Height / 2)),
0.0f);
body.Friction = 0.5f;
//string spritePath = Path.GetDirectoryName(item.Prefab.ConfigFile) + "\\"+ ToolBox.GetAttributeString(element, "sprite", "");
Vector2[] corners = GetConvexHullCorners(doorRect);
convexHull = new ConvexHull(corners, Color.Black);
if (window!=Rectangle.Empty) convexHull2 = new ConvexHull(corners, Color.Black);
UpdateConvexHulls();
isActive = true;
}
private void UpdateConvexHulls()
{
Rectangle rect = doorRect;
rect.Height = (int)(rect.Height * (1.0f - openState));
if (window.Height == 0 || window.Width == 0)
{
}
else
{
//Rectangle rect = item.Rect;
//rect.Height = (int)(rect.Height * (1.0f - openState));
rect.Height = -window.Y;
rect.Y += (int)(doorRect.Height * openState);
rect.Height = Math.Max(rect.Height - (rect.Y - doorRect.Y), 0);
rect.Y = Math.Min(doorRect.Y, rect.Y);
if (convexHull2 != null)
{
Rectangle rect2 = doorRect;
rect2.Y = rect2.Y + window.Y - window.Height;
rect2.Y += (int)(doorRect.Height * openState);
rect2.Y = Math.Min(doorRect.Y, rect2.Y);
rect2.Height = rect2.Y - (doorRect.Y - (int)(doorRect.Height * (1.0f - openState)));
//convexHull2.SetVertices(GetConvexHullCorners(rect2));
if (rect2.Height == 0)
{
convexHull2.Enabled = false;
}
else
{
convexHull2.Enabled = true;
convexHull2.SetVertices(GetConvexHullCorners(rect2));
}
}
}
if (rect.Height == 0)
{
convexHull.Enabled = false;
}
else
{
convexHull.Enabled = true;
convexHull.SetVertices(GetConvexHullCorners(rect));
}
}
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);
//LinkedGap.Move(amount);
body.SetTransform(body.Position + ConvertUnits.ToSimUnits(amount), 0.0f);
convexHull.Move(amount);
if (convexHull2 != null) convexHull2.Move(amount);
}
public override bool Pick(Character picker)
{
isOpen = !isOpen;
return true;
}
public override void Update(float deltaTime, Camera cam)
{
if (!isStuck)
{
OpenState += deltaTime * ((isOpen) ? 3.0f : -3.0f);
LinkedGap.Open = openState;
}
item.SendSignal((isOpen) ? "1" : "0", "state_out");
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
body.Enabled = false;
convexHull.Enabled = false;
linkedGap.Open = 1.0f;
if (convexHull2 != null) convexHull2.Enabled = false;
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
Color color = (item.IsSelected) ? Color.Green : Color.White;
color = color * (item.Condition / 100.0f);
color.A = 255;
//prefab.sprite.Draw(spriteBatch, new Vector2(rect.X, -rect.Y), new Vector2(rect.Width, rect.Height), color);
if (openState == 1.0f)
{
body.Enabled = false;
}
else
{
spriteBatch.Draw(doorSprite.Texture, new Vector2(item.Rect.Center.X, -item.Rect.Y),
new Rectangle(doorSprite.SourceRect.X, (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);
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);
if (linkedGap!=null) linkedGap.Remove();
doorSprite.Remove();
convexHull.Remove();
if (convexHull2 != null) convexHull2.Remove();
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
if (connection.Name=="toggle")
{
isOpen = !isOpen;
}
else if (connection.Name == "set_state")
{
isOpen = (signal!="0");
}
}
}
}
@@ -0,0 +1,234 @@
using System.Xml.Linq;
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
namespace Subsurface.Items.Components
{
class Holdable : Pickable
{
//the position(s) in the item that the character grabs
protected Vector2[] handlePos;
private List<RelatedItem> prevRequiredItems;
string prevMsg;
//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)]
public float HoldAngle
{
get { return MathHelper.ToDegrees(holdAngle); }
set { holdAngle = MathHelper.ToRadians(value); }
}
public Holdable(Item item, XElement element)
: base(item, element)
{
body = item.body;
handlePos = new Vector2[2];
for (int i = 1; i < 3; i++)
{
handlePos[i - 1] = ToolBox.GetAttributeVector2(element, "handle" + i, Vector2.Zero);
handlePos[i - 1] = ConvertUnits.ToSimUnits(handlePos[i - 1]);
}
canBePicked = true;
if (attachable)
{
prevRequiredItems = new List<RelatedItem>(requiredItems);
prevMsg = Msg;
requiredItems.Clear();
Msg = "";
}
//holdAngle = ToolBox.GetAttributeFloat(element, "holdangle", 0.0f);
//holdAngle = MathHelper.ToRadians(holdAngle);
}
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 base.Pick(picker);
}
if (!base.Pick(picker))
{
return false;
}
else
{
requiredItems.Clear();
Msg = "";
}
attached = false;
if (body!=null) item.body = body;
//item.body.Enabled = true;
return true;
}
public override bool Use(float deltaTime, Character character = null)
{
if (!attachable || item.body==null) return true;
item.Drop();
item.body.Enabled = false;
item.body = null;
requiredItems = new List<RelatedItem>(prevRequiredItems);
Msg = prevMsg;
attached = true;
return true;
}
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;
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
if (item.body.Dir != picker.AnimController.Dir) Flip(item);
AnimController ac = picker.AnimController;
//item.sprite.Depth = picker.AnimController.GetLimb(LimbType.RightHand).sprite.Depth + 0.01f;
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()
{
//prevRequiredItems = new List<RelatedItem>(requiredItems);
if (attached)
{
Use(1.0f);
}
else
{
requiredItems.Clear();
Msg = "";
}
}
}
}
@@ -0,0 +1,91 @@
using System;
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;
if (picker.Inventory.TryPutItem(item, allowedSlots))
{
if (!picker.HasSelectedItem(item) && item.body!=null) item.body.Enabled = false;
this.picker = picker;
for (int i = item.linkedTo.Count - 1; i >= 0; i--)
item.linkedTo[i].RemoveLinked(item);
item.linkedTo.Clear();
ApplyStatusEffects(ActionType.OnPicked, 1.0f, picker);
//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,125 @@
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;
[HasDefaultValue("0.0,0.0", false)]
public string BarrelPos
{
get { return ToolBox.Vector2ToString(ConvertUnits.ToDisplayUnits(barrelPos)); }
set { barrelPos = ConvertUnits.ToSimUnits(ToolBox.ParseToVector2(value)); }
}
public Vector2 TransformedBarrelPos
{
get
{
Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation);
Vector2 flippedPos = barrelPos;
if (item.body.Dir < 0.0f) flippedPos.X = -flippedPos.X;
return (Vector2.Transform(flippedPos, 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(float deltaTime, Character character = null)
{
if (character == null) return false;
if (!character.SecondaryKeyDown.State || reload > 0.0f) return false;
isActive = true;
reload = 1.0f;
bool failed = DoesUseFail(character);
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.Any()) 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;
projectile.body.ResetDynamics();
projectile.SetTransform(TransformedBarrelPos,
(item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi);
projectile.Use(deltaTime);
if (failed)
{
Vector2 modifiedVelocity = projectile.body.LinearVelocity;
modifiedVelocity.X *= Rand.Range(0.0f, 0.5f);
modifiedVelocity.Y *= Rand.Range(0.0f, 0.5f);
projectile.body.LinearVelocity = modifiedVelocity;
projectile.body.ApplyTorque(projectile.body.Mass * Rand.Range(-10.0f, 10.0f));
//recoil
//item.body.ApplyLinearImpulse(
// new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * item.body.Mass * -10.0f);
}
else
{
projectileComponent.ignoredBodies = limbBodies;
//recoil
//item.body.ApplyLinearImpulse(
// new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * -item.body.Mass);
}
item.RemoveContained(projectile);
Rope rope = item.GetComponent<Rope>();
if (rope != null) rope.Attach(projectile);
return true;
}
return false;
}
}
}
@@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using FarseerPhysics;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Subsurface.Particles;
namespace Subsurface.Items.Components
{
class RepairTool : ItemComponent
{
List<string> fixableEntities;
float range;
Vector2 pickedPosition;
Vector2 barrelPos;
float structureFixAmount, limbFixAmount;
[HasDefaultValue(0.0f, false)]
public float Range
{
get { return ConvertUnits.ToDisplayUnits(range); }
set { range = ConvertUnits.ToSimUnits(value); }
}
[HasDefaultValue(0.0f, false)]
public float StructureFixAmount
{
get { return structureFixAmount; }
set { structureFixAmount = value; }
}
[HasDefaultValue(0.0f, false)]
public float LimbFixAmount
{
get { return limbFixAmount; }
set { limbFixAmount = value; }
}
[HasDefaultValue("0.0,0.0", false)]
public string BarrelPos
{
get { return ToolBox.Vector2ToString(ConvertUnits.ToDisplayUnits(barrelPos)); }
set { barrelPos = ConvertUnits.ToSimUnits(ToolBox.ParseToVector2(value)); }
}
public Vector2 TransformedBarrelPos
{
get
{
Matrix bodyTransform = Matrix.CreateRotationZ(item.body.Rotation);
Vector2 flippedPos = barrelPos;
if (item.body.Dir < 0.0f) flippedPos.X = -flippedPos.X;
return (Vector2.Transform(flippedPos, bodyTransform) + item.body.Position);
}
}
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(float deltaTime, Character character = null)
{
if (character == null) return false;
if (!character.SecondaryKeyDown.State) return false;
if (DoesUseFail(character)) return false;
isActive = true;
Vector2 targetPosition = item.body.Position;
//targetPosition = targetPosition.X, -targetPosition.Y);
targetPosition += new Vector2(
(float)Math.Cos(item.body.Rotation),
(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 = Submarine.PickBody(TransformedBarrelPos, targetPosition, ignoredBodies);
pickedPosition = Submarine.LastPickedPosition;
if (targetBody==null || targetBody.UserData==null) return true;
//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 true;
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
if (sectionIndex < 0) return true;
targetStructure.HighLightSection(sectionIndex);
targetStructure.AddDamage(sectionIndex, -structureFixAmount);
}
else if ((targetLimb = (targetBody.UserData as Limb)) != null)
{
if (character.SecondaryKeyDown.State)
{
targetLimb.character.Health += limbFixAmount;
//isActive = true;
}
}
else if ((targetItem = (targetBody.UserData as Item)) != null)
{
//targetItem.Condition -= structureFixAmount;
targetItem.IsHighlighted = true;
foreach (StatusEffect effect in statusEffects)
{
//if (Array.IndexOf(effect.TargetNames, targetItem.Name) == -1) continue;
effect.Apply(ActionType.OnUse, deltaTime, item, targetItem.AllPropertyObjects);
//targetItem.ApplyStatusEffect(effect, ActionType.OnUse, deltaTime);
}
//ApplyStatusEffects(ActionType.OnUse, 1.0f, null, targ);
}
//if (character.SecondaryKeyDown.State)
//{
// IPropertyObject propertyObject = targetBody.UserData as IPropertyObject;
// if (propertyObject!=null) ApplyStatusEffects(ActionType.OnUse, 1.0f, item.SimPosition, propertyObject);
// //isActive = true;
//}
return true;
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
//isActive = true;
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
if (!isActive) return;
Vector2 particleSpeed = new Vector2(
(float)Math.Cos(item.body.Rotation),
(float)Math.Sin(item.body.Rotation)) *item.body.Dir * 5.0f;
Game1.ParticleManager.CreateParticle("weld", TransformedBarrelPos, particleSpeed);
//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,99 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Throwable : Holdable
{
float throwForce;
float throwPos;
bool throwing;
[HasDefaultValue(1.0f, false)]
public float ThrowForce
{
get { return throwForce; }
set { throwForce = value; }
}
public Throwable(Item item, XElement element)
: base(item, element)
{
//throwForce = ToolBox.GetAttributeFloat(element, "throwforce", 1.0f);
}
public override bool Use(float deltaTime, 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(float deltaTime, 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), aimPos, holdAngle);
if (!throwing) return;
throwPos += deltaTime*5.0f;
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);
}
}
}
}
@@ -0,0 +1,622 @@
using System;
using System.Collections.Generic;
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 System.IO;
using System.Globalization;
namespace Subsurface.Items.Components
{
class ItemSound
{
public readonly Sound Sound;
public readonly ActionType Type;
public string VolumeProperty;
public float VolumeMultiplier;
public readonly float Range;
public ItemSound(Sound sound, ActionType type, float range)
{
this.Sound = sound;
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;
public List<Skill> requiredSkills;
private List<ItemSound> sounds;
private GUIFrame guiFrame;
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; }
}
[HasDefaultValue(false, false)]
public bool DeleteOnUse
{
get;
set;
}
public Item Item
{
get { return item; }
}
public string Name
{
get { return name; }
}
protected GUIFrame GuiFrame
{
get
{
if (guiFrame==null)
{
DebugConsole.ThrowError("Error: the component "+name+" in "+item.Name+" doesn't have a guiFrame");
guiFrame = new GUIFrame(new Rectangle(0, 0, 100, 100), Color.Black);
}
return guiFrame;
}
}
[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>();
requiredSkills = new List<Skill>();
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":
case "requireditems":
RelatedItem ri = RelatedItem.Load(subElement);
if (ri != null) requiredItems.Add(ri);
break;
case "requiredskill":
case "requiredskills":
string skillName = ToolBox.GetAttributeString(subElement, "name", "");
requiredSkills.Add(new Skill(skillName, ToolBox.GetAttributeInt(subElement, "level", 0)));
break;
case "statuseffect":
statusEffects.Add(StatusEffect.Load(subElement));
break;
case "guiframe":
Vector4 rect = ToolBox.GetAttributeVector4(subElement, "rect", Vector4.One);
rect.X *= Game1.GraphicsWidth;
rect.Y *= Game1.GraphicsHeight;
rect.Z *= Game1.GraphicsWidth;
rect.W *= Game1.GraphicsHeight;
Vector4 color = ToolBox.GetAttributeVector4(subElement, "color", Vector4.One);
Alignment alignment = Alignment.Center;
try
{
alignment = (Alignment)Enum.Parse(typeof(Alignment),
ToolBox.GetAttributeString(subElement, "alignment", "Center"), true);
}
catch
{
DebugConsole.ThrowError("Error in " + element + "! ''" + element.Attribute("type").Value + "'' is not a valid alignment");
}
guiFrame = new GUIFrame(
new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Z, (int)rect.W),
new Color(color.X, color.Y, color.Z, color.W), alignment, GUI.style);
//guiFrame.Alpha = color.W;
break;
case "sound":
string filePath = ToolBox.GetAttributeString(subElement, "file", "");
if (filePath=="") continue;
if (!filePath.Contains("\\")) filePath = Path.GetDirectoryName(item.Prefab.ConfigFile)+"\\"+filePath;
//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;
}
Sound sound = Sound.Load(filePath);
float range = ToolBox.GetAttributeFloat(subElement, "range", 800.0f);
ItemSound itemSound = new ItemSound(sound, type, range);
itemSound.VolumeProperty = ToolBox.GetAttributeString(subElement, "volume", "");
itemSound.VolumeMultiplier = ToolBox.GetAttributeFloat(subElement, "volumemultiplier", 1.0f);
sounds.Add(itemSound);
break;
}
}
}
private ItemSound loopingSound;
private int loopingSoundIndex;
public void PlaySound(ActionType type, Vector2 position, bool loop=false)
{
ItemSound itemSound = null;
if (!loop || !Sounds.SoundManager.IsPlaying(loopingSoundIndex))
{
List<ItemSound> matchingSounds = sounds.FindAll(x => x.Type == type);
if (matchingSounds.Count == 0) return;
int index = Rand.Int(matchingSounds.Count);
itemSound = matchingSounds[index];
if (loop) loopingSound = itemSound;
}
if (loop)
{
loopingSoundIndex = loopingSound.Sound.Loop(loopingSoundIndex, GetSoundVolume(loopingSound), position, loopingSound.Range);
}
else
{
itemSound.Sound.Play(GetSoundVolume(itemSound), itemSound.Range, position);
}
}
private float GetSoundVolume(ItemSound sound)
{
if (sound.VolumeProperty == "") return 1.0f;
ObjectProperty op = null;
if (properties.TryGetValue(sound.VolumeProperty.ToLower(), out op))
{
float newVolume = 0.0f;
float.TryParse(op.GetValue().ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out newVolume);
newVolume *= sound.VolumeMultiplier;
return MathHelper.Clamp(newVolume, 0.0f, 1.0f);
}
return 0.0f;
}
public virtual void Move(Vector2 amount) { }
/// <summary>a character has picked the item</summary>
public virtual bool Pick(Character picker)
{
return false;
}
public virtual bool Select(Character character)
{
return CanBeSelected;
}
/// <summary>a character has dropped the item</summary>
public virtual void Drop(Character dropper) { }
public virtual void Draw(SpriteBatch spriteBatch, bool editing = false) { }
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(float deltaTime, Character character = null)
{
return false;
}
//called when the item is equipped and right mouse button is pressed
public virtual void SecondaryUse(float deltaTime, 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, float power = 0.0f)
{
switch (connection.Name)
{
case "activate":
case "use":
item.Use(1.0f);
break;
}
}
public virtual bool Combine(Item item)
{
return false;
}
public virtual void Remove()
{
if (loopingSound!=null)
{
Sounds.SoundManager.Stop(loopingSoundIndex);
}
}
public bool HasRequiredSkills(Character character)
{
Skill temp;
return HasRequiredSkills(character, out temp);
}
public bool HasRequiredSkills(Character character, out Skill insufficientSkill)
{
foreach (Skill skill in requiredSkills)
{
int characterLevel = character.GetSkillLevel(skill.Name);
if (characterLevel < skill.Level)
{
insufficientSkill = skill;
return false;
}
}
insufficientSkill = null;
return true;
}
protected bool DoesUseFail(Character character)
{
foreach (Skill skill in requiredSkills)
{
int characterLevel = character.GetSkillLevel(skill.Name);
if (characterLevel > skill.Level) continue;
if (Rand.Int(characterLevel) - skill.Level < 0)
{
item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character);
//Item.ApplyStatusEffects();
return true;
}
}
return false;
}
public bool HasRequiredContainedItems(bool addMessage)
{
List<RelatedItem> requiredContained = requiredItems.FindAll(ri=> ri.Type == RelatedItem.RelationType.Contained);
if (!requiredContained.Any()) return true;
Item[] containedItems = item.ContainedItems;
if (containedItems == null || !containedItems.Any()) return false;
foreach (RelatedItem ri in requiredContained)
{
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 HasRequiredItems(Character character, bool addMessage)
{
if (!requiredItems.Any()) return true;
foreach (RelatedItem ri in requiredItems)
{
if (!ri.Type.HasFlag(RelatedItem.RelationType.Equipped) && !ri.Type.HasFlag(RelatedItem.RelationType.Picked)) continue;
bool hasItem = false;
if (ri.Type.HasFlag(RelatedItem.RelationType.Equipped))
{
if (character.SelectedItems.FirstOrDefault(it => it != null && it.Condition > 0.0f && ri.MatchesItem(it)) != null) hasItem = true;
}
if (!hasItem && ri.Type.HasFlag(RelatedItem.RelationType.Picked))
{
if (character.Inventory.items.FirstOrDefault(x => x!=null && x.Condition>0.0f && ri.MatchesItem(x))!=null) hasItem = true;
}
if (!hasItem)
{
if (addMessage && !string.IsNullOrEmpty(ri.Msg)) GUI.AddMessage(ri.Msg, Color.Red);
return false;
}
}
return true;
}
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null)
{
foreach (StatusEffect effect in statusEffects)
{
if (effect.type != type) continue;
item.ApplyStatusEffect(effect, type, deltaTime, character);
}
}
public void ApplyStatusEffects(ActionType type, float deltaTime, IPropertyObject target)
{
foreach (StatusEffect effect in statusEffects)
{
if (effect.type != type) continue;
effect.Apply(type, deltaTime, item, target);
}
}
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;
foreach (XAttribute attribute in componentElement.Attributes())
{
ObjectProperty property = null;
if (!properties.TryGetValue(attribute.Name.ToString().ToLower(), out property)) continue;
property.TrySetValue(attribute.Value);
}
List<RelatedItem> prevRequiredItems = new List<RelatedItem>(requiredItems);
requiredItems.Clear();
foreach (XElement subElement in componentElement.Elements())
{
switch (subElement.Name.ToString().ToLower())
{
case "requireditem":
RelatedItem newRequiredItem = RelatedItem.Load(subElement);
if (newRequiredItem == null) continue;
var prevRequiredItem = prevRequiredItems.Find(ri => ri.JoinedNames == newRequiredItem.JoinedNames);
if (prevRequiredItem!=null)
{
newRequiredItem.statusEffects = prevRequiredItem.statusEffects;
newRequiredItem.Msg = prevRequiredItem.Msg;
}
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!=typeof(ItemComponent) && !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)
{
}
}
}
+103
View File
@@ -0,0 +1,103 @@
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 Label : ItemComponent
{
GUITextBox textBox;
private string text;
[HasDefaultValue("", true)]
public string Text
{
get { return text; }
set
{
text = value;
}
}
public Label(Item item, XElement element)
: base(item, element)
{
}
public override bool Select(Character character)
{
if (textBox == null)
{
textBox = new GUITextBox(Rectangle.Empty, GUI.style, GuiFrame);
textBox.Wrap = true;
textBox.OnTextChanged = TextChanged;
textBox.LimitText = true;
GUIButton button = new GUIButton(new Rectangle(0,0,100,15), "OK", null, Alignment.BottomRight, GUI.style, GuiFrame);
button.OnClicked = Close;
}
textBox.Text = text;
textBox.Select();
return base.Select(character);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
//isActive = true;
GuiFrame.Update((float)Physics.step);
GuiFrame.Draw(spriteBatch);
//int width = 300, height = 300;
//int x = Game1.GraphicsWidth / 2 - width / 2;
//int y = Game1.GraphicsHeight / 2 - height / 2 - 50;
//GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
if (!textBox.Selected) character.SelectedConstruction = null;
}
private bool TextChanged(GUITextBox textBox, string text)
{
this.text = text;
item.NewComponentEvent(this, true);
return true;
}
private bool Close(GUIButton button, object obj)
{
textBox.Deselect();
return true;
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
message.Write(Text);
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
{
string newText = "";
try
{
newText = message.ReadString();
}
catch
{
return;
}
Text = newText;
}
}
}
@@ -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 Select(Character character = null)
{
if (character == null) return false;
character.AnimController.Anim = AnimController.Animation.Climbing;
//picker.SelectedConstruction = item;
return true;
}
}
}
@@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using FarseerPhysics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
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;
Camera cam;
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);
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)
{
this.cam = 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);
//}
item.SendSignal(ToolBox.Vector2ToString(character.CursorPosition), "position_out");
}
public override bool Use(float deltaTime, Character activator = null)
{
//character = activator;
//foreach (MapEntity e in item.linkedTo)
//{
// Item linkedItem = e as Item;
// if (linkedItem == null) continue;
// linkedItem.Use(deltaTime, activator);
//}
item.SendSignal("1", "trigger_out");
ApplyStatusEffects(ActionType.OnUse, 1.0f, activator);
return true;
}
public override void SecondaryUse(float deltaTime, Character character = null)
{
if (character == null) return;
foreach (Connection c in item.Connections)
{
if (c.Name != "position_out") continue;
foreach (Connection c2 in c.Recipients)
{
if (c2 == null || c2.Item==null || !c2.Item.Prefab.FocusOnSelected) continue;
Vector2 centerPos = c2.Item.Position;
if (character == Character.Controlled && cam != null)
{
Lights.LightManager.ViewPos = centerPos;
cam.TargetPos = c2.Item.Position;
}
break;
}
}
//foreach (MapEntity e in item.linkedTo)
//{
// Item linkedItem = e as Item;
// if (linkedItem == null) continue;
// linkedItem.SecondaryUse(deltaTime, character);
//}
}
public override bool Pick(Character picker)
{
item.SendSignal("1", "signal_out");
return true;
}
public override bool Select(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,122 @@
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 Engine : Powered
{
float force;
float targetForce;
float maxForce;
float powerPerForce;
[Editable, HasDefaultValue(1.0f, true)]
public float PowerPerForce
{
get { return powerPerForce; }
set
{
powerPerForce = Math.Max(0.0f, value);
}
}
[Editable, HasDefaultValue(2000.0f, true)]
public float MaxForce
{
get { return maxForce; }
set
{
maxForce = Math.Max(0.0f, value);
}
}
public float Force
{
get { return force;}
set { force = MathHelper.Clamp(value, -100.0f, 100.0f); }
}
public Engine(Item item, XElement element)
: base(item, element)
{
isActive = true;
}
public float CurrentVolume
{
get { return Math.Abs((force / 100.0f) * (voltage / minVoltage)); }
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
currPowerConsumption = Math.Abs(targetForce) * powerPerForce;
Force = MathHelper.Lerp(force, (voltage < minVoltage) ? 0.0f : targetForce, 0.1f);
if (Force != 0.0f)
{
Vector2 currForce = new Vector2((force / 100.0f) * maxForce * (voltage / minVoltage), 0.0f);
Submarine.Loaded.ApplyForce(currForce);
for (int i = 0; i < 5; i++)
{
Game1.ParticleManager.CreateParticle("bubbles", item.SimPosition,
-currForce/500.0f + new Vector2(Rand.Range(-1.0f, 1.0f), Rand.Range(-0.5f, 0.5f)));
}
}
voltage = 0.0f;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
//isActive = true;
GuiFrame.Draw(spriteBatch);
//int width = 300, height = 300;
//int x = Game1.GraphicsWidth / 2 - width / 2;
//int y = Game1.GraphicsHeight / 2 - height / 2 - 50;
//GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
spriteBatch.DrawString(GUI.Font, "Force: " + (int)(targetForce) + " %", new Vector2(GuiFrame.Rect.X + 30, GuiFrame.Rect.Y + 30), Color.White);
if (GUI.DrawButton(spriteBatch, new Rectangle(GuiFrame.Rect.X + 280, GuiFrame.Rect.Y + 30, 40, 40), "+", true)) targetForce += 1.0f;
if (GUI.DrawButton(spriteBatch, new Rectangle(GuiFrame.Rect.X + 280, GuiFrame.Rect.Y + 80, 40, 40), "-", true)) targetForce -= 1.0f;
item.NewComponentEvent(this, true);
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
force = MathHelper.Lerp(force, 0.0f, 0.1f);
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
base.ReceiveSignal(signal, connection, sender, power);
if (connection.Name == "set_force")
{
float tempForce;
if (float.TryParse(signal, NumberStyles.Float, CultureInfo.InvariantCulture, out tempForce))
{
targetForce = tempForce;
targetForce = MathHelper.Clamp(targetForce, -100.0f, 100.0f);
}
}
}
}
}
@@ -0,0 +1,213 @@
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 FabricableItem
{
//public static List<FabricableItem> list = new List<FabricableItem>();
//public readonly string[] FabricatorTags;
public readonly ItemPrefab TargetItem;
public readonly List<ItemPrefab> RequiredItems;
public readonly float RequiredTime;
//ListOrSomething requiredLevels
public FabricableItem(XElement element)
{
string name = ToolBox.GetAttributeString(element, "name", "").ToLower();
TargetItem = ItemPrefab.list.Find(ip => ip.Name.ToLower() == name) as ItemPrefab;
if (TargetItem == null)
{
DebugConsole.ThrowError("Error in Fabricable Item! Item ''" + element.Name + "'' not found.");
return;
}
RequiredItems = new List<ItemPrefab>();
string[] requiredItemNames = ToolBox.GetAttributeString(element, "requireditems", "").Split(',');
foreach (string requiredItemName in requiredItemNames)
{
ItemPrefab requiredItem = ItemPrefab.list.Find(ip => ip.Name.ToLower() == requiredItemName.Trim().ToLower()) as ItemPrefab;
if (requiredItem == null) continue;
RequiredItems.Add(requiredItem);
}
RequiredTime = ToolBox.GetAttributeFloat(element, "requiredtime", 1.0f);
}
}
class Fabricator : ItemComponent
{
List<FabricableItem> fabricableItems;
GUIListBox itemList;
GUIFrame selectedItemFrame;
FabricableItem fabricatedItem;
float timeUntilReady;
public Fabricator(Item item, XElement element)
: base(item, element)
{
fabricableItems = new List<FabricableItem>();
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString() != "fabricableitem") continue;
FabricableItem fabricableItem = new FabricableItem(subElement);
if (fabricableItem.TargetItem != null) fabricableItems.Add(fabricableItem);
}
int width = 400, height = 300;
itemList = new GUIListBox(new Rectangle(Game1.GraphicsWidth / 2 - width / 2, Game1.GraphicsHeight / 2 - height / 2, width, height), Color.White * 0.7f);
itemList.OnSelected = SelectItem;
//structureList.CheckSelected = MapEntityPrefab.GetSelected;
foreach (FabricableItem fi in fabricableItems)
{
Color color = ((itemList.CountChildren % 2) == 0) ? Color.White : Color.LightGray;
//GUIFrame frame = new GUIFrame(new Rectangle(0, 0, 0, 50), Color.Transparent, itemList);
//frame.UserData = fi;
//frame.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
//frame.Color = color;
//frame.HoverColor = Color.Gold * 0.2f;
//frame.SelectedColor = Color.Gold * 0.5f;
GUITextBlock textBlock = new GUITextBlock(
new Rectangle(0, 0, 0, 25), fi.TargetItem.Name,
color, Color.Black,
Alignment.Left, Alignment.Left, null, itemList);
textBlock.UserData = fi;
textBlock.Padding = new Vector4(5.0f, 5.0f, 5.0f, 5.0f);
//if (fi.TargetItem.sprite != null)
//{
// GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), fi.TargetItem.sprite, Alignment.Left, frame);
// img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
//}
}
}
private bool SelectItem(object obj)
{
FabricableItem targetItem = obj as FabricableItem;
if (targetItem == null) return false;
int width = 200, height = 150;
selectedItemFrame = new GUIFrame(new Rectangle(Game1.GraphicsWidth / 2 - width / 2, itemList.Rect.Bottom+20, width, height), Color.Black*0.8f);
//selectedItemFrame.Padding = GUI.style.smallPadding;
if (targetItem.TargetItem.sprite != null)
{
GUIImage img = new GUIImage(new Rectangle(0, 0, 40, 40), targetItem.TargetItem.sprite, Alignment.CenterX, selectedItemFrame);
img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
string text = targetItem.TargetItem.Name + "\n";
text += "Required items:\n";
foreach (ItemPrefab ip in targetItem.RequiredItems)
{
text += " - " + ip.Name + "\n";
}
text += "Required time: "+targetItem.RequiredTime+" s";
GUITextBlock textBlock = new GUITextBlock(
new Rectangle(0, 0, 0, 25),
text,
Color.Transparent, Color.White,
Alignment.CenterX | Alignment.CenterY,
Alignment.Left, null,
selectedItemFrame);
GUIButton button = new GUIButton(new Rectangle(0,0,100,20), "Create", Color.White, Alignment.CenterX | Alignment.Bottom, GUI.style, selectedItemFrame);
button.OnClicked = StartFabricating;
button.UserData = targetItem;
}
return true;
}
public override bool Pick(Character picker)
{
return (picker != null);
}
private bool StartFabricating(GUIButton button, object obj)
{
GUIComponent listElement = itemList.GetChild(obj);
listElement.Color = Color.Green;
itemList.Enabled = false;
fabricatedItem = obj as FabricableItem;
isActive = true;
timeUntilReady = fabricatedItem.RequiredTime;
return true;
}
public override void Update(float deltaTime, Camera cam)
{
timeUntilReady -= deltaTime;
if (timeUntilReady > 0.0f) return;
ItemContainer container = item.GetComponent<ItemContainer>();
foreach (ItemPrefab ip in fabricatedItem.RequiredItems)
{
var requiredItem = Array.Find(container.inventory.items, it => it != null && it.Prefab == ip);
container.inventory.RemoveItem(requiredItem);
}
new Item(fabricatedItem.TargetItem, item.Position);
isActive = false;
fabricatedItem = null;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
FabricableItem targetItem = itemList.SelectedData as FabricableItem;
if (targetItem != null)
{
selectedItemFrame.GetChild<GUIButton>().Enabled = true;
ItemContainer container = item.GetComponent<ItemContainer>();
foreach (ItemPrefab ip in targetItem.RequiredItems)
{
if (Array.Find(container.inventory.items, it => it != null && it.Prefab == ip) != null) continue;
selectedItemFrame.GetChild<GUIButton>().Enabled = false;
break;
}
}
itemList.Update(0.016f);
itemList.Draw(spriteBatch);
if (selectedItemFrame != null)
{
selectedItemFrame.Update(0.016f);
selectedItemFrame.Draw(spriteBatch);
}
}
}
}
@@ -0,0 +1,84 @@
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 = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
//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)Submarine.Borders.Width, (float)miniMap.Height / (float)Submarine.Borders.Height);
foreach (Hull hull in Hull.hullList)
{
Rectangle hullRect = new Rectangle(
miniMap.X + (int)((hull.Rect.X - Submarine.Borders.X) * size),
miniMap.Y - (int)((hull.Rect.Y - Submarine.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 - Submarine.Borders.X) * size),
miniMap.Y - (int)((c.Position.Y - Submarine.Borders.Y) * size),
5, 5);
GUI.DrawRectangle(spriteBatch, characterRect, Color.White, true);
}
}
}
}
@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class OxygenGenerator : Powered
{
PropertyTask powerUpTask;
float powerDownTimer;
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 += 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)
{
powerDownTimer += deltaTime;
running = false;
if ((powerUpTask==null || powerUpTask.IsFinished) && powerDownTimer>5.0f)
{
powerUpTask = new PropertyTask(item, IsRunning, 50.0f, "Turn on the oxygen generator");
}
return;
}
else
{
powerDownTimer = 0.0f;
}
running = true;
float deltaOxygen = Math.Min(voltage, 1.0f) * 50000.0f;
item.CurrentHull.Oxygen += deltaOxygen * deltaTime;
UpdateVents(deltaOxygen);
voltage = 0.0f;
}
public override void UpdateBroken(float deltaTime, Camera cam)
{
powerDownTimer += deltaTime;
}
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,181 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Specialized;
using System.Globalization;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Pump : Powered
{
float flowPercentage;
float maxFlow;
float? targetLevel;
Hull hull1, hull2;
[HasDefaultValue(0.0f, true)]
private float FlowPercentage
{
get { return flowPercentage; }
set
{
if (float.IsNaN(flowPercentage)) return;
flowPercentage = MathHelper.Clamp(value,-100.0f,100.0f);
}
}
[HasDefaultValue(100.0f, false)]
public float MaxFlow
{
get { return maxFlow; }
set { maxFlow = value; }
}
public Pump(Item item, XElement element)
: base(item, element)
{
item.linkedTo.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{ GetHulls(); };
}
public override void Update(float deltaTime, Camera cam)
{
if (targetLevel != null)
{
float hullPercentage = 0.0f;
if (hull1 != null) hullPercentage = (hull1.Volume / hull1.FullVolume) * 100.0f;
flowPercentage = ((float)targetLevel - hullPercentage);
}
currPowerConsumption = powerConsumption * Math.Abs(flowPercentage / 100.0f);
if (voltage < minVoltage) return;
if (hull2 == null && hull1 == null) return;
float powerFactor = (currPowerConsumption==0.0f) ? 1.0f : voltage;
//flowPercentage = maxFlow * powerFactor;
float deltaVolume = 0.0f;
deltaVolume = (flowPercentage/100.0f) * maxFlow * powerFactor;
hull1.Volume += deltaVolume;
if (hull1.Volume > hull1.FullVolume) hull1.Pressure += 0.5f;
if (hull2 != null)
{
hull2.Volume -= deltaVolume;
if (hull2.Volume > hull1.FullVolume) hull2.Pressure += 0.5f;
}
voltage = 0.0f;
}
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 DrawHUD(SpriteBatch spriteBatch, Character character)
{
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 20, y + 20, 100, 40), ((isActive) ? "TURN OFF" : "TURN ON")))
{
targetLevel = null;
isActive = !isActive;
if (!isActive) currPowerConsumption = 0.0f;
}
spriteBatch.DrawString(GUI.Font, "Flow percentage: " + (int)flowPercentage + " %", new Vector2(x + 20, y + 80), Color.White);
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 200, y + 70, 40, 40), "+", true)) FlowPercentage += 1.0f;
if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 70, 40, 40), "-", true)) FlowPercentage -= 1.0f;
item.NewComponentEvent(this, true);
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
base.ReceiveSignal(signal, connection, sender, power);
if (connection.Name == "toggle")
{
isActive = !isActive;
}
else if (connection.Name == "set_active")
{
isActive = (signal != "0");
}
else if (connection.Name == "set_speed")
{
float tempSpeed;
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out tempSpeed))
{
flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f);
}
}
else if (connection.Name == "set_targetlevel")
{
float tempTarget;
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out tempTarget))
{
targetLevel = MathHelper.Clamp(tempTarget, 0.0f, 100.0f);
}
}
if (!isActive) currPowerConsumption = 0.0f;
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
message.Write(flowPercentage);
message.Write(isActive);
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
{
float newFlow = 0.0f;
bool newActive;
try
{
newFlow = message.ReadFloat();
newActive = message.ReadBoolean();
}
catch { return; }
FlowPercentage = newFlow;
isActive = newActive;
}
}
}
@@ -0,0 +1,221 @@
using FarseerPhysics;
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 Radar : Powered
{
private float range;
private float pingState;
private Sprite pingCircle, screenOverlay;
[HasDefaultValue(0.0f, false)]
public float Range
{
get { return ConvertUnits.ToDisplayUnits(range); }
set { range = ConvertUnits.ToSimUnits(value); }
}
public Radar(Item item, XElement element)
: base(item, element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLower())
{
case "pingcircle":
pingCircle = new Sprite(subElement);
break;
case "screenoverlay":
screenOverlay = new Sprite(subElement);
break;
}
}
//renderTarget = new RenderTarget2D(Game1.CurrGraphicsDevice, GuiFrame.Rect.Width, GuiFrame.Rect.Height);
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
if (voltage>=minVoltage)
{
pingState = (pingState + deltaTime * 0.5f);
if (pingState>1.0f)
{
item.Use(deltaTime, null);
pingState = 0.0f;
}
}
else
{
pingState = 0.0f;
}
}
public override bool Use(float deltaTime, Character character = null)
{
return (pingState > 1.0f);
}
public override void DrawHUD(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Character character)
{
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
if (voltage < minVoltage) return;
if (GUI.DrawButton(spriteBatch, new Rectangle(x+20, y+20, 200, 30), "Activate Radar")) isActive = !isActive;
int radius = GuiFrame.Rect.Height / 2 - 10;
DrawRadar(spriteBatch, new Rectangle((int)GuiFrame.Center.X - radius, (int)GuiFrame.Center.Y - radius, radius * 2, radius * 2));
//voltage = 0.0f;
}
private void DrawRadar(SpriteBatch spriteBatch, Rectangle rect)
{
Vector2 center = new Vector2(rect.Center.X, rect.Center.Y);
//lineEnd += new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Math.Min(width, height) / 2.0f;
//GUI.DrawLine(spriteBatch, GuiFrame.Center, lineEnd, Color.Green);
if (!isActive) return;
if (pingCircle!=null)
{
pingCircle.Draw(spriteBatch, center, Color.White * (1.0f-pingState), 0.0f, (rect.Width/pingCircle.size.X)*pingState);
}
float radius = pingCircle.size.X / 2.0f;
float simScale = 1.5f;
float displayScale = 0.015f;
if (Level.Loaded != null)
{
List<Vector2[]> edges = Level.Loaded.GetCellEdges(-Level.Loaded.Position, 7);
Vector2 offset = Vector2.Zero;
for (int i = 0; i < edges.Count; i++)
{
GUI.DrawLine(spriteBatch,
center + (edges[i][0] - offset) * displayScale,
center + (edges[i][1] - offset) * displayScale, Color.White);
}
for (int i = 0; i < Submarine.Loaded.HullVertices.Count; i++)
{
Vector2 start = Submarine.Loaded.HullVertices[i] * simScale;
start.Y = -start.Y;
Vector2 end = Submarine.Loaded.HullVertices[(i + 1) % Submarine.Loaded.HullVertices.Count] * simScale;
end.Y = -end.Y;
GUI.DrawLine(spriteBatch, center + start, center + end, Color.White);
}
}
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.CurrentHull != null) continue;
Vector2 pos = c.Position * displayScale;
if (c.SimPosition != Vector2.Zero && pos.Length() < radius)
{
int width = (int)MathHelper.Clamp(c.Mass / 20, 1, 10);
pos.Y = -pos.Y;
pos += center;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X - width / 2, (int)pos.Y - width / 2, width, width), Color.White, true);
}
}
if (screenOverlay!=null)
{
screenOverlay.Draw(spriteBatch, center, 0.0f, rect.Width/screenOverlay.size.X);
}
//if (Level.Loaded != null)
//{
// for (int i = 0; i < 2; i++)
// {
// Vector2 targetPos = (i == 0) ? Level.Loaded.StartPosition : Level.Loaded.EndPosition;
// targetPos += Level.Loaded.Position;
// float dist = targetPos.Length();
// targetPos.Y = -targetPos.Y;
// Vector2 markerPos = Vector2.Normalize(targetPos) * (rect.Width * 0.55f);
// markerPos += center;
// GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X, (int)markerPos.Y, 5, 5), Color.LightGreen);
// string label;
// if (Game1.GameSession.Map!=null)
// {
// label = (i == 0) ? Game1.GameSession.Map.CurrentLocation.Name : Game1.GameSession.Map.SelectedLocation.Name;
// }
// else
// {
// label = (i == 0) ? "Start" : "End";
// }
// spriteBatch.DrawString(GUI.SmallFont, label, new Vector2(markerPos.X + 10, markerPos.Y), Color.LightGreen);
// spriteBatch.DrawString(GUI.SmallFont, (int)(dist / 80.0f) + " m", new Vector2(markerPos.X + 10, markerPos.Y + 15), Color.LightGreen);
// }
DrawMarker(spriteBatch,
(Game1.GameSession.Map == null) ? "Start" : Game1.GameSession.Map.CurrentLocation.Name,
(Level.Loaded.StartPosition + Level.Loaded.Position), displayScale, center, (rect.Width * 0.55f));
DrawMarker(spriteBatch,
(Game1.GameSession.Map == null) ? "End" : Game1.GameSession.Map.SelectedLocation.Name,
(Level.Loaded.EndPosition + Level.Loaded.Position), displayScale, center, (rect.Width * 0.55f));
if (Game1.GameSession.Quest != null)
{
var quest = Game1.GameSession.Quest;
if (!string.IsNullOrWhiteSpace(quest.RadarLabel))
{
DrawMarker(spriteBatch,
quest.RadarLabel,
quest.RadarPosition, displayScale, center, (rect.Width * 0.55f));
}
}
}
private void DrawMarker(SpriteBatch spriteBatch, string label, Vector2 position, float scale, Vector2 center, float radius)
{
//position += Level.Loaded.Position;
float dist = position.Length();
position *= scale;
position.Y = -position.Y;
Vector2 markerPos = (dist*scale>radius) ? Vector2.Normalize(position) * radius : position;
markerPos += center;
GUI.DrawRectangle(spriteBatch, new Rectangle((int)markerPos.X, (int)markerPos.Y, 5, 5), Color.LightGreen);
spriteBatch.DrawString(GUI.SmallFont, label, new Vector2(markerPos.X + 10, markerPos.Y), Color.LightGreen);
spriteBatch.DrawString(GUI.SmallFont, (int)(dist / 80.0f) + " m", new Vector2(markerPos.X + 10, markerPos.Y + 15), Color.LightGreen);
}
}
}
@@ -0,0 +1,393 @@
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;
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 float AvailableFuel { 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;
shutDownTemp = 500.0f;
powerPerTemp = 1.0f;
isActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
//ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
fissionRate = Math.Min(fissionRate, AvailableFuel);
float heat = 100 * fissionRate * (AvailableFuel/2000.0f);
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(item, IsRunning, 50.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;
List<Connection> connections = item.Connections;
if (connections!=null && connections.Count>0)
{
foreach (Connection connection in connections)
{
foreach (Connection recipient in connection.Recipients)
{
Item it = recipient.Item as Item;
if (it == null) continue;
PowerTransfer pt = it.GetComponent<PowerTransfer>();
if (pt != null) load += 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) 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*powerPerTemp;
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;
AvailableFuel = 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(item, 60.0f, "Reactor meltdown!");
item.Condition = 0.0f;
//fissionRate = 0.0f;
//coolingRate = 0.0f;
//PlaySound(ActionType.OnFailure, item.Position);
//item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, null);
//new Explosion(item.SimPosition, 6.0f, 500.0f, 600.0f, 10.0f, 2.0f).Explode();
if (item.ContainedItems!=null)
{
foreach (Item containedItem in item.ContainedItems)
{
if (containedItem == null) continue;
containedItem.Condition = 0.0f;
}
}
}
public override bool Pick(Character picker)
{
return (picker != null);
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
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 = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
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, "Automatic Temperature Control: " + ((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, "Shutdown 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 + width, y + height - (graph[1] + (graph[0] - graph[1]) * xOffset) * yScale);
float currX = x + width - ((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,
y + height - (graph[graph.Count - 1] + (graph[graph.Count - 2] - graph[graph.Count - 1]) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, Color.White);
}
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)
{
bool newAutoTemp;
float newTemperature, newShutDownTemp;
float newCoolingRate, newFissionRate;
try
{
newAutoTemp = message.ReadBoolean();
newTemperature = message.ReadFloat();
newShutDownTemp = message.ReadFloat();
newCoolingRate = message.ReadFloat();
newFissionRate = message.ReadFloat();
}
catch { return; }
autoTemp = newAutoTemp;
Temperature = newTemperature;
shutDownTemp = newShutDownTemp;
CoolingRate = newCoolingRate;
FissionRate = newFissionRate;
}
}
}
@@ -0,0 +1,180 @@
using FarseerPhysics;
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 Steering : ItemComponent
{
private Vector2 currVelocity;
private Vector2 targetVelocity;
private bool autoPilot;
private SteeringPath steeringPath;
private static PathFinder pathFinder;
bool AutoPilot
{
get { return autoPilot; }
set
{
if (value == autoPilot) return;
autoPilot = value;
if (autoPilot)
{
if (pathFinder==null) pathFinder = new PathFinder(WayPoint.WayPointList, false);
steeringPath = pathFinder.FindPath(
ConvertUnits.ToSimUnits(Level.Loaded.Position),
ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
}
}
}
private Vector2 TargetVelocity
{
get { return targetVelocity;}
set
{
if (float.IsNaN(value.X) || float.IsNaN(value.Y))
{
return;
}
targetVelocity.X = MathHelper.Clamp(value.X, -100.0f, 100.0f);
targetVelocity.Y = MathHelper.Clamp(value.Y, -100.0f, 100.0f);
}
}
public Steering(Item item, XElement element)
: base(item, element)
{
isActive = true;
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
if (autoPilot)
{
//if (steeringPath==null)
//{
// PathFinder pathFinder = new PathFinder(WayPoint.WayPointList, false);
// steeringPath = pathFinder.FindPath(
// ConvertUnits.ToSimUnits(Level.Loaded.StartPosition),
// ConvertUnits.ToSimUnits(Level.Loaded.EndPosition));
//}
steeringPath.GetNode(Vector2.Zero, 20.0f);
if (steeringPath.CurrentNode!=null)
{
float prediction = 10.0f;
Vector2 futurePosition = Submarine.Loaded.Speed * prediction;
Vector2 targetSpeed = (steeringPath.CurrentNode.Position - futurePosition);
//float dist = targetSpeed.Length();
targetSpeed = Vector2.Normalize(targetSpeed);
TargetVelocity = targetSpeed*100.0f;
}
}
item.SendSignal(targetVelocity.X.ToString(CultureInfo.InvariantCulture), "velocity_x_out");
item.SendSignal((-targetVelocity.Y).ToString(CultureInfo.InvariantCulture), "velocity_y_out");
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
Rectangle velRect = new Rectangle(x + 20, y + 20, width - 40, height - 40);
GUI.DrawRectangle(spriteBatch, velRect, Color.White, false);
if (GUI.DrawButton(spriteBatch, new Rectangle(x + width - 150, y + height - 30, 150, 30), "Autopilot"))
{
AutoPilot = !AutoPilot;
item.NewComponentEvent(this, true);
}
GUI.DrawLine(spriteBatch,
new Vector2(velRect.Center.X,velRect.Center.Y),
new Vector2(velRect.Center.X + currVelocity.X, velRect.Center.Y - currVelocity.Y),
Color.Gray);
Vector2 targetVelPos = new Vector2(velRect.Center.X + targetVelocity.X, velRect.Center.Y - targetVelocity.Y);
GUI.DrawLine(spriteBatch,
new Vector2(velRect.Center.X, velRect.Center.Y),
targetVelPos,
Color.LightGray);
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X - 5, (int)targetVelPos.Y - 5, 10, 10), Color.White);
if (Vector2.Distance(PlayerInput.MousePosition, new Vector2(velRect.Center.X, velRect.Center.Y)) < 200.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle((int)targetVelPos.X -10, (int)targetVelPos.Y - 10, 20, 20), Color.Red);
if (PlayerInput.LeftButtonDown())
{
targetVelocity = PlayerInput.MousePosition - new Vector2(velRect.Center.X, velRect.Center.Y);
targetVelocity.Y = -targetVelocity.Y;
item.NewComponentEvent(this, true);
}
}
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
if (connection.Name == "velocity_in")
{
currVelocity = ToolBox.ParseToVector2(signal, false);
}
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
message.Write(targetVelocity.X);
message.Write(targetVelocity.Y);
message.Write(autoPilot);
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
{
Vector2 newTargetVelocity = Vector2.Zero;
bool newAutoPilot = false;
try
{
newTargetVelocity = new Vector2(message.ReadFloat(), message.ReadFloat());
newAutoPilot = message.ReadBoolean();
}
catch
{
return;
}
TargetVelocity = newTargetVelocity;
AutoPilot = newAutoPilot;
}
}
}
@@ -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,233 @@
using System;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Subsurface.Items.Components
{
class PowerContainer : Powered
{
//[power/min]
float capacity;
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;
[Editable, HasDefaultValue(10.0f, true)]
public float MaxOutPut
{
set { maxOutput = value; }
get { return maxOutput; }
}
[HasDefaultValue(0.0f, true)]
public float Charge
{
get { return charge; }
set
{
if (float.IsNaN(value)) return;
charge = MathHelper.Clamp(value, 0.0f, capacity);
}
}
[HasDefaultValue(10.0f, false), Editable]
public float Capacity
{
get { return capacity; }
set { capacity = Math.Max(value, 1.0f); }
}
[HasDefaultValue(10.0f, false), Editable]
public float RechargeSpeed
{
get { return rechargeSpeed; }
set
{
if (float.IsNaN(value)) return;
rechargeSpeed = MathHelper.Clamp(value, 0.0f, maxRechargeSpeed);
}
}
[HasDefaultValue(10.0f, false), Editable]
public float MaxRechargeSpeed
{
get { return maxRechargeSpeed; }
set { maxRechargeSpeed = Math.Max(value, 1.0f); }
}
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);
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, bool editing)
{
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))
{
item.NewComponentEvent(this, 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);
item.NewComponentEvent(this, true);
}
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
message.Write(rechargeSpeed);
message.Write(charge);
}
public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message)
{
float newRechargeSpeed = 0.0f;
float newCharge = 0.0f;
try
{
newRechargeSpeed = message.ReadFloat();
newCharge = message.ReadFloat();
}
catch { }
RechargeSpeed = newRechargeSpeed;
Charge = newCharge;
}
}
}
@@ -0,0 +1,145 @@
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Globalization;
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("", "power", fullPower / Math.Max(fullLoad, 1.0f));
if (-pt.currPowerConsumption > Math.Max(pt.powerLoad * 2.0f, 200.0f)) pt.item.Condition -= deltaTime*10.0f;
}
}
}
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.CurrPowerConsumption > 0.0f)
{
fullLoad += powered.CurrPowerConsumption;
}
else if (powered.CurrPowerConsumption < 0.0f)
//negative power consumption = the construction is a
//generator/battery or another junction box
{
fullPower -= powered.CurrPowerConsumption;
}
}
}
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
int width = GuiFrame.Rect.Width, height = GuiFrame.Rect.Height;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
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);
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power)
{
base.ReceiveSignal(signal, connection, sender, power);
if (connection.Name == "signal")
{
connection.SendSignal(signal, sender, 0.0f);
}
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Globalization;
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;
//current voltage of the item (load / power)
protected float voltage;
//the minimum voltage required for the item to work
protected float minVoltage;
//the maximum amount of power the item can draw from connected items
protected float powerConsumption;
private bool powerOnSoundPlayed;
private static Sound powerOnSound;
[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, float power)
{
if (currPowerConsumption == 0.0f) voltage = 0.0f;
if (connection.Name == "power_in" || connection.Name == "power") voltage = power;
}
public override void Update(float deltaTime, Camera cam)
{
if (currPowerConsumption == 0.0f) return;
if (voltage > minVoltage)
{
if (!powerOnSoundPlayed)
{
powerOnSound.Play(1.0f, 600.0f, item.Position);
powerOnSoundPlayed = true;
}
ApplyStatusEffects(ActionType.OnActive, deltaTime);
}
else if (voltage < 0.1f)
{
powerOnSoundPlayed = false;
}
}
public Powered(Item item, XElement element)
: base(item, element)
{
if (powerOnSound==null)
{
powerOnSound = Sound.Load("Content/Items/Electricity/powerOn.ogg");
}
}
}
}
@@ -0,0 +1,221 @@
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(float deltaTime, 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();
AttackResult attackResult = new AttackResult(0.0f, 0.0f);
if (attack!=null)
{
Limb limb;
Structure structure;
if ((limb = (f2.Body.UserData as Limb)) != null)
{
attackResult = attack.DoDamage(limb.character, item.SimPosition, 1.0f);
}
else if ((structure = (f2.Body.UserData as Structure)) != null)
{
attackResult = attack.DoDamage(structure, item.SimPosition, 1.0f);
}
}
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
item.body.FarseerBody.IsBullet = false;
item.body.CollisionCategories = Physics.CollisionMisc;
item.body.CollidesWith = Physics.CollisionWall;
ignoredBodies.Clear();
if (attackResult.HitArmor)
{
item.body.LinearVelocity *= 0.5f;
}
else 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 = 30.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;
}
}
}
+335
View File
@@ -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(float deltaTime, 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.01f,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, bool editing)
{
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,
MathUtils.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,76 @@
using System;
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, float power=0.0f)
{
switch (connection.Name)
{
case "signal_in1":
if (signal == "0") return;
timeSinceReceived[0] = 0.0f;
isActive = true;
break;
case "signal_in2":
if (signal == "0") return;
timeSinceReceived[1] = 0.0f;
isActive = true;
break;
case "set_output":
output = signal;
break;
}
}
}
}
@@ -0,0 +1,470 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
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;
private List<StatusEffect> effects;
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");
effects = new List<StatusEffect>();
wireId = new int[MaxLinked];
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLower())
{
case "link":
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);
break;
case "statuseffect":
effects.Add(StatusEffect.Load(subElement));
break;
}
}
}
public int FindEmptyIndex()
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i]==null) return i;
}
return -1;
}
//public int FindLinkIndex(Item item)
//{
// for (int i = 0; i < MaxLinked; i++)
// {
// if (item == null && recipient[i] == null) return i;
// if (recipient[i]!=null && recipient[i].item == item) return i;
// }
// return -1;
//}
public int FindWireIndex(Item wireItem)
{
for (int i = 0; i < MaxLinked; i++)
{
if (Wires[i] == null && wireItem == null) return i;
if (Wires[i] != null && Wires[i].Item == wireItem) return i;
}
return -1;
}
public void 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, float power)
{
for (int i = 0; i<MaxLinked; i++)
{
if (Wires[i]==null) continue;
Connection recipient = Wires[i].OtherConnection(this);
if (recipient == null) continue;
if (recipient.item == this.item || recipient.item == sender) continue;
foreach (ItemComponent ic in recipient.item.components)
{
ic.ReceiveSignal(signal, recipient, sender, power);
}
foreach (StatusEffect effect in recipient.effects)
{
//effect.Apply(ActionType.OnUse, 1.0f, recipient.item, recipient.item);
recipient.item.ApplyStatusEffect(effect, ActionType.OnUse, 1.0f);
}
}
}
public void ClearConnections()
{
for (int i = 0; i<MaxLinked; i++)
{
if (Wires[i] == null) continue;
Wires[i].RemoveConnection(this);
Wires[i] = null;
}
}
public static void DrawConnections(SpriteBatch spriteBatch, ConnectionPanel panel, Character character)
{
int width = 400, height = 200;
int x = 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);
Wire equippedWire = null;
//if the character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
for (int i = 0; i < character.SelectedItems.Length; i++)
{
Item selectedItem = character.SelectedItems[i];
if (selectedItem == null) continue;
Wire wireComponent = selectedItem.GetComponent<Wire>();
if (wireComponent != null) equippedWire = wireComponent;
}
Vector2 rightPos = new Vector2(x + width - 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, equippedWire != null);
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, equippedWire != null);
leftPos.Y += 30;
leftWireX -= wireInterval;
}
}
//if the character using the panel has a wire item equipped
//and the wire hasn't been connected yet, draw it on the panel
if (equippedWire!=null)
{
if (panel.connections.Find(c => c.Wires.Contains(equippedWire)) == null)
{
DrawWire(spriteBatch, equippedWire.Item, equippedWire.Item,
new Vector2(x + width / 2, y + height - 100),
new Vector2(x + width / 2, y + height), mouseInRect, false);
if (draggingConnected == equippedWire.Item) Inventory.draggingItem = equippedWire.Item;
//break;
}
}
//for (int i = 0; i < character.SelectedItems.Length; i++ )
//{
// Item selectedItem = character.SelectedItems[i];
// if (selectedItem == null) continue;
// Wire wireComponent = selectedItem.GetComponent<Wire>();
//}
//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, bool wireEquipped)
{
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, wireEquipped);
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].Item.SetTransform(item.SimPosition, 0.0f);
Wires[index].Item.Drop();
Wires[index].Item.body.Enabled = true;
Wires[index] = null;
}
}
}
}
private static void DrawWire(SpriteBatch spriteBatch, Item wireItem, Item item, Vector2 end, Vector2 start, bool mouseIn, bool wireEquipped)
{
if (draggingConnected == wireItem)
{
if (!mouseIn) return;
end = PlayerInput.MousePosition;
}
bool mouseOn = false;
int textX = (int)start.X;
float connLength = 10.0f;
float alpha = wireEquipped ? 0.5f : 1.0f;
//Color color = (wireEquipped) ? wireItem.Color * 0.5f : wireItem.Color;
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)), wireItem.Color * alpha);
textX = (int)end.X;
connector.Draw(spriteBatch, end, Color.White*alpha);
}
else
{
Vector2 pos = new Vector2(start.X, end.Y + wireCorner.size.Y+1) - wireVertical.size / 2;
Vector2 size = new Vector2(wireVertical.size.X, (float)Math.Abs((end.Y + wireCorner.size.Y) - start.Y));
wireVertical.DrawTiled(spriteBatch, pos, size, wireItem.Color * alpha);
Rectangle rect = new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
if (!wireEquipped && rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
float dir = (end.X > start.X) ? -1.0f : 1.0f;
wireCorner.Draw(spriteBatch,
new Vector2(start.X, end.Y-1), wireItem.Color * alpha, 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;
pos = new Vector2(Math.Min(wireStartX,wireEndX), end.Y - wireVertical.size.Y / 2);
size = new Vector2(Math.Abs(wireStartX - wireEndX), wireHorizontal.size.Y);
wireHorizontal.DrawTiled(spriteBatch, pos, size, wireItem.Color * alpha);
rect = new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
if (!wireEquipped && rect.Contains(PlayerInput.MousePosition)) mouseOn = true;
connector.Draw(spriteBatch, end, Color.White*alpha, -MathHelper.PiOver2 * dir);
}
if (draggingConnected == null && !wireEquipped)
{
if (mouseOn || Vector2.Distance(end, PlayerInput.MousePosition)<20.0f)
{
item.IsHighlighted = true;
//start dragging the wire
if (PlayerInput.LeftButtonDown()) draggingConnected = wireItem;
}
}
spriteBatch.DrawString(GUI.Font, item.Name,
new Vector2(textX, start.Y-30),
(mouseOn && !wireEquipped) ? Color.Gold : 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));
Array.Sort(Wires, delegate(Wire wire1, Wire wire2)
{
if (wire1 == null) return 1;
if (wire2 == null) return -1;
return wire1.Item.ID.CompareTo(wire2.Item.ID);
});
for (int i = 0; i < MaxLinked; i++ )
{
if (Wires[i] == null) continue;
//Connection recipient = wires[i].OtherConnection(this);
//int connectionIndex = recipient.item.Connections.FindIndex(x => x == recipient);
newElement.Add(new XElement("link",
new XAttribute("w", Wires[i].Item.ID.ToString())));
}
parentElement.Add(newElement);
}
public void ConnectLinked()
{
if (wireId == null) return;
for (int i = 0; i < MaxLinked; i++)
{
if (wireId[i] == -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, true);
}
}
wireId = null;
}
}
}
@@ -0,0 +1,143 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
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;
}
}
isActive = true;
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (character != Character.Controlled || character != user) return;
Connection.DrawConnections(spriteBatch, this, character);
}
public override XElement Save(XElement parentElement)
{
XElement componentElement = base.Save(parentElement);
foreach (Connection c in connections)
{
c.Save(componentElement);
}
return componentElement;
}
public override void OnMapLoaded()
{
foreach (Connection c in connections)
{
c.ConnectLinked();
}
}
public override void Update(float deltaTime, Camera cam)
{
if (user != null && user.SelectedConstruction != item) user = null;
}
public override bool Select(Character picker)
{
user = picker;
isActive = true;
return true;
}
public override 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 Remove()
{
base.Remove();
}
public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message)
{
foreach (Connection c in connections)
{
Wire[] wires = Array.FindAll(c.Wires, w => w != null);
message.Write((byte)wires.Length);
for (int i = 0 ; i < c.Wires.Length; i++)
{
if (c.Wires[i] == null) continue;
message.Write(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();
try
{
byte wireCount = message.ReadByte();
for (int i = 0; i < wireCount; i++)
{
int wireId = message.ReadInt32();
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);
}
}
catch { }
}
}
}
}
@@ -0,0 +1,149 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Subsurface.Lights;
using System;
using System.IO;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class LightComponent : Powered
{
static Sound[] sparkSounds;
private Color lightColor;
//private Sprite sprite;
LightSource light;
float range;
float lightBrightness;
[Editable, HasDefaultValue(100.0f, true)]
public float Range
{
get { return range; }
set
{
range = MathHelper.Clamp(value, 0.0f, 2048.0f);
}
}
[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 override void Move(Vector2 amount)
{
light.Position += amount;
}
public LightComponent(Item item, XElement element)
: base (item, element)
{
if (sparkSounds==null)
{
sparkSounds = new Sound[4];
string dir = Path.GetDirectoryName(item.Prefab.ConfigFile)+"\\";
for (int i = 0; i<4; i++)
{
sparkSounds[i] = Sound.Load(dir+"zap"+(i+1)+".ogg");
}
}
//foreach (XElement subElement in element.Elements())
//{
// if (subElement.Name.ToString().ToLower() != "sprite") continue;
// sprite = new Sprite(subElement);
// break;
//}
light = new LightSource(item.Position, 100.0f, Color.White);
isActive = true;
//lightColor = new Color(ToolBox.GetAttributeVector4(element, "color", Vector4.One));
}
public override void Update(float deltaTime, Camera cam)
{
base.Update(deltaTime, cam);
if (item.body != null)
{
light.Position = ConvertUnits.ToDisplayUnits(item.body.Position);
}
Pickable pickable = item.GetComponent<Pickable>();
if (item.container!= null || (pickable!=null && pickable.Picker!=null))
{
light.Color = Color.Transparent;
return;
}
if (powerConsumption == 0.0f)
{
voltage = 1.0f;
}
else
{
currPowerConsumption = powerConsumption;
}
if (Rand.Range(0.0f, 1.0f) < 0.05f && voltage < Rand.Range(0.0f, minVoltage))
{
if (voltage > 0.1f) sparkSounds[Rand.Int(sparkSounds.Length)].Play(1.0f, 400.0f, item.Position);
lightBrightness = 0.0f;
}
else
{
lightBrightness = MathHelper.Lerp(lightBrightness, Math.Min(voltage, 1.0f), 0.1f);
}
light.Color = lightColor * lightBrightness;
light.Range = range * (float)Math.Sqrt(lightBrightness);
voltage = 0.0f;
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
if (!isActive)
{
light.Color = Color.Transparent;
}
}
public override void Remove()
{
base.Remove();
light.Remove();
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
base.ReceiveSignal(signal, connection, sender, power);
switch (connection.Name)
{
case "toggle":
isActive = !isActive;
break;
case "set_state":
isActive = (signal != "0");
break;
}
}
}
}
@@ -0,0 +1,19 @@
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, float power=0.0f)
{
if (connection.Name != "signal_in") return;
item.SendSignal(signal=="0" ? "1" : "0", "signal_out");
}
}
}
@@ -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,36 @@
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,60 @@
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, float power = 0.0f)
{
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");
return;
}
item.SendSignal(success ? output : "0", "signal_out");
break;
case "set_output":
output = signal;
break;
}
}
}
}
@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class SignalCheckComponent : ItemComponent
{
private string output;
private string targetSignal;
[InGameEditable, HasDefaultValue("1", true)]
public string Output
{
get { return output; }
set { output = value; }
}
[InGameEditable, HasDefaultValue("", true)]
public string TargetSignal
{
get { return targetSignal; }
set { targetSignal = value; }
}
public SignalCheckComponent(Item item, XElement element)
: base(item, element)
{
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f)
{
switch (connection.Name)
{
case "signal_in":
item.SendSignal((signal == targetSignal) ? output : "0", "signal_out");
break;
case "set_output":
output = signal;
break;
case "set_targetsignal":
targetSignal = signal;
break;
}
}
}
}
@@ -0,0 +1,417 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
namespace Subsurface.Items.Components
{
class Wire : ItemComponent
{
const float nodeDistance = 32.0f;
const float heightFromFloor = 128.0f;
static Sprite wireSprite;
public List<Vector2> Nodes;
Connection[] connections;
private Vector2 newNodePos;
private static int? selectedNodeIndex;
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 override void Move(Vector2 amount)
{
amount = FarseerPhysics.ConvertUnits.ToDisplayUnits(amount);
//for (int i = 0; i<Nodes.Count; i++)
//{
// Nodes[i] += amount;
//}
}
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, bool loading = false)
{
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)
{
//List<Vector2> prevNodes = new List<Vector2>(Nodes);
foreach (ItemComponent ic in item.components)
{
if (ic == this) continue;
ic.Drop(null);
}
if (item.container != null) item.container.RemoveContained(this.item);
item.body.Enabled = false;
isActive = false;
//Nodes = prevNodes;
CleanNodes();
}
if (!loading) Item.NewComponentEvent(this, true);
}
public override void Equip(Character character)
{
ClearConnections();
isActive = true;
}
public override void Unequip(Character character)
{
ClearConnections();
isActive = false;
}
public override void Drop(Character dropper)
{
ClearConnections();
isActive = false;
}
public override void Update(float deltaTime, Camera cam)
{
if (Nodes.Count == 0) return;
item.FindHull();
Vector2 position = item.Position;
position.X = MathUtils.Round(item.Position.X, nodeDistance);
if (item.CurrentHull == null)
{
position.Y = MathUtils.Round(item.Position.Y, nodeDistance);
}
else
{
position.Y -= item.CurrentHull.Rect.Y - item.CurrentHull.Rect.Height;
position.Y = Math.Max(MathUtils.Round(position.Y, nodeDistance), heightFromFloor);
position.Y += item.CurrentHull.Rect.Y - item.CurrentHull.Rect.Height;
}
newNodePos = RoundNode(item.Position, item.CurrentHull);
//if (Vector2.Distance(position, nodes[nodes.Count - 1]) > nodeDistance*10)
//{
// nodes.Add(position);
// item.NewComponentEvent(this, true);
//}
//else if (Math.Abs(position.Y - nodes[nodes.Count - 1].Y) > nodeDistance)
//{
// nodes.Add(new Vector2(nodes[nodes.Count - 1].X,
// position.Y));
// item.NewComponentEvent(this, true);
//}
}
public override bool Use(float deltaTime, Character character = null)
{
if (character == Character.Controlled && character.SelectedConstruction != null) return false;
if (newNodePos!= Vector2.Zero && Nodes.Count>0 && Vector2.Distance(newNodePos, Nodes[Nodes.Count - 1]) > nodeDistance)
{
Nodes.Add(newNodePos);
newNodePos = Vector2.Zero;
}
return true;
}
public override void SecondaryUse(float deltaTime, Character character = null)
{
if (Nodes.Count > 1)
{
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 Vector2 RoundNode(Vector2 position, Hull hull)
{
position.X = MathUtils.Round(position.X, nodeDistance);
if (hull == null)
{
position.Y = MathUtils.Round(position.Y, nodeDistance);
}
else
{
position.Y -= hull.Rect.Y - hull.Rect.Height;
position.Y = Math.Max(MathUtils.Round(position.Y, nodeDistance), heightFromFloor);
position.Y += hull.Rect.Y -hull.Rect.Height;
}
return position;
}
private void CleanNodes()
{
for (int i = Nodes.Count - 2; i > 0; i--)
{
if ((Nodes[i - 1].X == Nodes[i].X || Nodes[i - 1].Y == Nodes[i].Y) &&
(Nodes[i + 1].X == Nodes[i].X || Nodes[i + 1].Y == Nodes[i].Y))
{
if (Vector2.Distance(Nodes[i - 1], Nodes[i]) == Vector2.Distance(Nodes[i + 1], Nodes[i]))
{
Nodes.RemoveAt(i);
}
}
}
bool removed;
do
{
removed = false;
for (int i = Nodes.Count - 2; i > 0; i--)
{
if ((Nodes[i - 1].X == Nodes[i].X && Nodes[i + 1].X == Nodes[i].X)
|| (Nodes[i - 1].Y == Nodes[i].Y && Nodes[i + 1].Y == Nodes[i].Y))
{
Nodes.RemoveAt(i);
removed = true;
}
}
} while (removed);
}
public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, bool editing)
{
if (Nodes.Count == 0) return;
//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, item.Color);
}
if (isActive && Vector2.Distance(newNodePos, Nodes[Nodes.Count - 1]) > nodeDistance)
{
DrawSection(spriteBatch, Nodes[Nodes.Count - 1], newNodePos, Nodes.Count, item.Color * 0.5f);
//nodes.Add(newNodePos);
}
if (!editing) return;
for (int i = 1; i < Nodes.Count; i++)
{
GUI.DrawRectangle(spriteBatch, new Rectangle((int)Nodes[i].X - 3, (int)-Nodes[i].Y -3, 6, 6), Color.Red, true, 0.0f);
if (Vector2.Distance(Game1.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), Nodes[i]) < 20.0f)
{
GUI.DrawRectangle(spriteBatch, new Rectangle((int)Nodes[i].X - 10, (int)-Nodes[i].Y - 10, 20, 20), Color.Red, false, 0.0f);
if (selectedNodeIndex==null && selectedNodeIndex>0 && selectedNodeIndex<Nodes.Count-1)
{
if ( PlayerInput.LeftButtonDown())
{
MapEntity.SelectEntity(item);
selectedNodeIndex = i;
}
else
{
Nodes.RemoveAt(i);
break;
}
}
}
}
if (PlayerInput.LeftButtonDown())
{
if (selectedNodeIndex!=null && item.IsSelected)
{
MapEntity.DisableSelect = true;
Nodes[(int)selectedNodeIndex] = Game1.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
Vector2 pos = Nodes[(int)selectedNodeIndex];
Nodes[(int)selectedNodeIndex] = RoundNode(Nodes[(int)selectedNodeIndex], Hull.FindHull(Nodes[(int)selectedNodeIndex]));
MapEntity.SelectEntity(item);
}
}
else
{
//if (selectedNodeIndex != null) MapEntity.SelectEntity(item); ;
selectedNodeIndex = null;
}
}
private void DrawSection(SpriteBatch spriteBatch, Vector2 start, Vector2 end, int i, Color color)
{
start.Y = -start.Y;
end.Y = -end.Y;
spriteBatch.Draw(wireSprite.Texture,
start, null, color,
MathUtils.VectorToAngle(end - start),
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
new Vector2((Vector2.Distance(start, end)) / wireSprite.Texture.Width, 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,212 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FarseerPhysics;
namespace Subsurface.Items.Components
{
class Turret : Powered
{
Sprite barrelSprite;
Vector2 barrelPos;
float rotation, targetRotation;
float reload, reloadTime;
float minRotation, 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", true), Editable]
public string RotationLimits
{
get
{
Vector2 limits = new Vector2(minRotation, maxRotation);
limits.X = MathHelper.ToDegrees(limits.X);
limits.Y = MathHelper.ToDegrees(limits.Y);
return ToolBox.Vector2ToString(limits);
}
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));
}
public override void Draw(SpriteBatch spriteBatch, bool editing)
{
barrelSprite.Draw(spriteBatch, new Vector2(item.Rect.X, -item.Rect.Y) + barrelPos, rotation + MathHelper.PiOver2, 1.0f);
}
public override void Update(float deltaTime, Camera cam)
{
this.cam = cam;
if (reload>0.0f) reload -= deltaTime;
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
if (targetRotation < minRotation || targetRotation > maxRotation)
{
float diff = MathUtils.WrapAngleTwoPi(targetRotation - (minRotation + maxRotation) / 2.0f);
targetRotation = (diff > Math.PI) ? minRotation : maxRotation;
}
rotation = MathUtils.CurveAngle(rotation, targetRotation, 0.05f);
}
//public override void SecondaryUse(float deltaTime, Character character = null)
//{
// if (character == null) return;
// Vector2 centerPos = new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y);
// 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(float deltaTime, 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 (Connection c in item.Connections)
{
foreach (Connection c2 in c.Recipients)
{
if (c2 == null || c2.Item == null) continue;
PowerContainer batteryComponent = c2.Item.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(ConvertUnits.ToSimUnits(new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y)), -rotation);
//if (useSounds.Count() > 0) useSounds[Game1.localRandom.Next(useSounds.Count())].Play(1.0f, 800.0f, item.body.FarseerBody);
projectileComponent.Use(deltaTime);
item.RemoveContained(projectile);
return true;
}
public override void ReceiveSignal(string signal, Connection connection, Item sender, float power)
{
switch (connection.Name)
{
case "position_in":
Vector2 receivedPos = ToolBox.ParseToVector2(signal, false);
Vector2 centerPos = new Vector2(item.Rect.X + barrelPos.X, item.Rect.Y - barrelPos.Y);
Vector2 offset = receivedPos - centerPos;
offset.Y = -offset.Y;
targetRotation = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(offset));
isActive = true;
break;
case "trigger_in":
item.Use((float)Physics.step, null);
break;
}
}
}
}
@@ -0,0 +1,129 @@
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
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;
ApplyStatusEffects(ActionType.OnWearing, deltaTime, picker);
if (containedItems == null) return;
for (int j = 0; j<containedItems.Length; j++)
{
if (containedItems[j] == null) continue;
containedItems[j].ApplyStatusEffects(ActionType.OnWearing, deltaTime, picker);
}
}
}
}