First commit

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