First commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
using System.Collections.Generic;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Subsurface.Networking;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class Entity
|
||||
{
|
||||
public static Dictionary<int, Entity> dictionary = new Dictionary<int, Entity>();
|
||||
|
||||
private int id;
|
||||
|
||||
protected AITarget aiTarget;
|
||||
//protected float soundRange;
|
||||
//protected float sightRange;
|
||||
|
||||
public int ID
|
||||
{
|
||||
get { return id; }
|
||||
set
|
||||
{
|
||||
dictionary.Remove(id);
|
||||
//if there's already an entity with the same ID, give it the old ID of this one
|
||||
Entity existingEntity;
|
||||
if (dictionary.TryGetValue(value, out existingEntity))
|
||||
{
|
||||
dictionary.Remove(value);
|
||||
dictionary.Add(id, existingEntity);
|
||||
existingEntity.id = id;
|
||||
}
|
||||
|
||||
id = value;
|
||||
dictionary.Add(id, this);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Vector2 SimPosition
|
||||
{
|
||||
get { return Vector2.Zero; }
|
||||
}
|
||||
|
||||
public Entity()
|
||||
{
|
||||
//give an unique ID
|
||||
bool IDfound;
|
||||
id = 0;
|
||||
do
|
||||
{
|
||||
id += 1;
|
||||
IDfound = dictionary.ContainsKey(id);
|
||||
} while (IDfound);
|
||||
|
||||
dictionary.Add(id, this);
|
||||
}
|
||||
|
||||
public virtual void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) { }
|
||||
public virtual void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Find an entity based on the ID
|
||||
/// </summary>
|
||||
public static Entity FindEntityByID(int ID)
|
||||
{
|
||||
Entity matchingEntity;
|
||||
dictionary.TryGetValue(ID, out matchingEntity);
|
||||
|
||||
return matchingEntity;
|
||||
}
|
||||
|
||||
public static void RemoveAll()
|
||||
{
|
||||
List<Entity> list = new List<Entity>(dictionary.Values);
|
||||
foreach (Entity e in list)
|
||||
{
|
||||
e.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Remove()
|
||||
{
|
||||
dictionary.Remove(this.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class Explosion
|
||||
{
|
||||
Vector2 position;
|
||||
|
||||
|
||||
float range;
|
||||
float damage;
|
||||
float structureDamage;
|
||||
float stun;
|
||||
|
||||
float force;
|
||||
|
||||
public Explosion(Vector2 position, float range, float damage, float structureDamage, float stun=0.0f, float force=0.0f)
|
||||
{
|
||||
this.position = position;
|
||||
this.range = Math.Max(range,1.0f);
|
||||
this.damage = damage;
|
||||
this.structureDamage = structureDamage;
|
||||
this.stun = stun;
|
||||
this.force = force;
|
||||
}
|
||||
|
||||
public Explosion(XElement element)
|
||||
{
|
||||
range = Math.Max(ToolBox.GetAttributeFloat(element, "range", 1.0f),1.0f);
|
||||
damage = ToolBox.GetAttributeFloat(element, "damage", 0.0f);
|
||||
structureDamage = ToolBox.GetAttributeFloat(element, "structuredamage", 0.0f);
|
||||
stun = ToolBox.GetAttributeFloat(element, "stun", 0.0f);
|
||||
|
||||
force = ToolBox.GetAttributeFloat(element, "force", 0.0f);
|
||||
}
|
||||
|
||||
public void Explode()
|
||||
{
|
||||
Explode(position);
|
||||
}
|
||||
|
||||
public void Explode(Vector2 position)
|
||||
{
|
||||
for (int i = 0; i<range*10; i++)
|
||||
{
|
||||
Game1.particleManager.CreateParticle(position,
|
||||
ToolBox.RandomFloat(0.0f,3.14f),
|
||||
Vector2.Normalize(new Vector2(ToolBox.RandomFloat(-1.0f, 1.0f), ToolBox.RandomFloat(-1.0f, 1.0f))) * ToolBox.RandomFloat(3.0f,4.0f),
|
||||
"explosionfire");
|
||||
}
|
||||
|
||||
Vector2 displayPosition = ConvertUnits.ToDisplayUnits(position);
|
||||
float displayRange = ConvertUnits.ToDisplayUnits(range);
|
||||
|
||||
if (structureDamage>0.0f)
|
||||
{
|
||||
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 &&
|
||||
!structure.IsPlatform &&
|
||||
Vector2.Distance(structure.Position, displayPosition) < dist*3.0f)
|
||||
{
|
||||
structureList.Add(structure);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Structure structure in structureList)
|
||||
{
|
||||
for (int i = 0; i < structure.SectionCount; i++)
|
||||
{
|
||||
float distFactor = 1.0f - (Vector2.Distance(structure.SectionPosition(i), displayPosition) / displayRange);
|
||||
if (distFactor > 0.0f) structure.AddDamage(i, structureDamage*distFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Character c in Character.characterList)
|
||||
{
|
||||
float dist = Vector2.Distance(c.SimPosition, position);
|
||||
|
||||
if (dist > range) continue;
|
||||
|
||||
float distFactor = 1.0f - dist / range;
|
||||
|
||||
foreach (Limb limb in c.animController.limbs)
|
||||
{
|
||||
distFactor = 1.0f - Vector2.Distance(limb.SimPosition, position)/range;
|
||||
|
||||
c.AddDamage(limb.SimPosition, damage * distFactor, 0.0f, stun * distFactor);
|
||||
|
||||
if (force>0.0f)
|
||||
{
|
||||
limb.body.ApplyLinearImpulse(Vector2.Normalize(limb.SimPosition-position)*distFactor*force);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class Gap : MapEntity
|
||||
{
|
||||
public bool isHorizontal;
|
||||
|
||||
//private Sound waterSound;
|
||||
|
||||
//a value between 0.0f-1.0f (0.0 = closed, 1.0f = open)
|
||||
float open;
|
||||
|
||||
//the forces of the water flow which are exerted on physics bodies
|
||||
Vector2 flowForce;
|
||||
|
||||
Hull flowTargetHull;
|
||||
|
||||
float higherSurface;
|
||||
float lowerSurface;
|
||||
|
||||
private int soundIndex;
|
||||
|
||||
float soundVolume;
|
||||
|
||||
public float Open
|
||||
{
|
||||
get { return open; }
|
||||
set { open = MathHelper.Clamp(value, 0.0f, 1.0f); }
|
||||
}
|
||||
|
||||
public Vector2 FlowForce
|
||||
{
|
||||
get { return flowForce*soundVolume; }
|
||||
}
|
||||
|
||||
public Hull FlowTargetHull
|
||||
{
|
||||
get { return flowTargetHull; }
|
||||
}
|
||||
|
||||
public Gap(Rectangle newRect)
|
||||
{
|
||||
rect = newRect;
|
||||
linkedTo = new ObservableCollection<MapEntity>();
|
||||
|
||||
//waterSound = new Sound("waterstream", 0.0f);
|
||||
|
||||
flowForce = Vector2.Zero;
|
||||
|
||||
isHorizontal = (rect.Width < rect.Height);
|
||||
|
||||
open = 1.0f;
|
||||
|
||||
FindHulls();
|
||||
|
||||
mapEntityList.Add(this);
|
||||
}
|
||||
|
||||
public Gap(Rectangle newRect, bool isHorizontal)
|
||||
{
|
||||
rect = newRect;
|
||||
linkedTo = new ObservableCollection<MapEntity>();
|
||||
|
||||
flowForce = Vector2.Zero;
|
||||
|
||||
this.isHorizontal = isHorizontal;
|
||||
|
||||
open = 1.0f;
|
||||
|
||||
FindHulls();
|
||||
|
||||
mapEntityList.Add(this);
|
||||
}
|
||||
|
||||
public static void UpdateHulls()
|
||||
{
|
||||
foreach (MapEntity entity in mapEntityList)
|
||||
{
|
||||
Gap g = entity as Gap;
|
||||
if (g != null) g.FindHulls();
|
||||
}
|
||||
}
|
||||
|
||||
private void FindHulls()
|
||||
{
|
||||
Hull hull1 = null, hull2 = null;
|
||||
|
||||
linkedTo.Clear();
|
||||
|
||||
foreach (Hull h in Hull.hullList)
|
||||
{
|
||||
if (!Map.RectsOverlap(h.Rect, rect)) continue;
|
||||
|
||||
//if the gap is inside the hull completely, ignore it
|
||||
if (rect.X > h.Rect.X && rect.X + rect.Width < h.Rect.X+h.Rect.Width &&
|
||||
rect.Y < h.Rect.Y && rect.Y - rect.Height > h.Rect.Y - h.Rect.Height) continue;
|
||||
|
||||
if (hull1 == null)
|
||||
{
|
||||
hull1 = h;
|
||||
}
|
||||
else
|
||||
{
|
||||
hull2 = h;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hull1 == null && hull2 == null) return;
|
||||
|
||||
if (hull1 != null && hull2 != null)
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
//make sure that water1 is the lefthand room
|
||||
//or that water2 is null if the gap doesn't lead to another room
|
||||
if (hull1.Rect.X < hull2.Rect.X)
|
||||
{
|
||||
linkedTo.Add(hull1);
|
||||
linkedTo.Add(hull2);
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedTo.Add(hull2);
|
||||
linkedTo.Add(hull1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//make sure that water1 is the room on the top
|
||||
//or that water2 is null if the gap doesn't lead to another room
|
||||
if (hull1.Rect.Y > hull2.Rect.Y)
|
||||
{
|
||||
linkedTo.Add(hull1);
|
||||
linkedTo.Add(hull2);
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedTo.Add(hull2);
|
||||
linkedTo.Add(hull1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedTo.Add(hull1);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch sb, bool editing)
|
||||
{
|
||||
//if (linkedTo[0] != null)
|
||||
// GUI.DrawLine(sb, new Vector2(Position.X, Position.Y),
|
||||
// new Vector2(linkedTo[0].Position.X, linkedTo[0].Position.Y), Color.Blue);
|
||||
|
||||
//if (linkedTo.Count > 1 && linkedTo[1] != null)
|
||||
// GUI.DrawLine(sb, new Vector2(Position.X, Position.Y),
|
||||
// new Vector2(linkedTo[1].Position.X, linkedTo[1].Position.Y), Color.Blue);
|
||||
|
||||
|
||||
//GUI.DrawLine(sb, new Vector2(Position.X, -Position.Y), new Vector2(Position.X, -Position.Y)+new Vector2(flowForce.X, -flowForce.Y), Color.LightBlue);
|
||||
|
||||
if (!editing) return;
|
||||
|
||||
Color clr = (open == 0.0f) ? Color.Red : Color.Cyan;
|
||||
|
||||
GUI.DrawRectangle(sb, new Rectangle(rect.X, -rect.Y, rect.Width, rect.Height), clr);
|
||||
|
||||
if (isSelected && editing)
|
||||
{
|
||||
GUI.DrawRectangle(sb,
|
||||
new Vector2(rect.X - 5, -rect.Y - 5),
|
||||
new Vector2(rect.Width + 10, rect.Height + 10),
|
||||
Color.Red);
|
||||
}
|
||||
|
||||
//HUD.DrawLine(sb, new Vector2(position.X, -position.Y),
|
||||
// isHorizontal ? new Vector2(position.X, -position.Y + size) : new Vector2(position.X + size, -position.Y),
|
||||
// clr);
|
||||
}
|
||||
|
||||
public override void Update(Camera cam, float deltaTime)
|
||||
{
|
||||
|
||||
soundVolume = soundVolume + ((flowForce.Length() < 100.0f) ? -deltaTime * 0.5f : deltaTime * 0.5f);
|
||||
soundVolume = MathHelper.Clamp(soundVolume, 0.0f, 1.0f);
|
||||
|
||||
//if (soundVolume < 0.01f)
|
||||
//{
|
||||
// if (soundIndex > -1)
|
||||
// {
|
||||
// Sound.Stop(soundIndex);
|
||||
// soundIndex = -1;
|
||||
// }
|
||||
|
||||
//}
|
||||
//else
|
||||
{
|
||||
int index = (int)Math.Floor(flowForce.Length() / 100.0f);
|
||||
index = Math.Min(index,2);
|
||||
|
||||
soundIndex = AmbientSoundManager.flowSounds[index].Loop(soundIndex, soundVolume, Position, 2000.0f);
|
||||
//soundVolume = Math.Max(0.0f, soundVolume-deltaTime);
|
||||
//Sound.UpdatePosition(soundIndex, Position, 2000.0f);
|
||||
}
|
||||
|
||||
flowForce = Vector2.Zero;
|
||||
|
||||
if (open == 0.0f) return;
|
||||
|
||||
UpdateOxygen();
|
||||
|
||||
|
||||
if (linkedTo.Count == 1)
|
||||
{
|
||||
//gap leading from a room to outside
|
||||
UpdateRoomToOut(deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
//gap leading from a room to another
|
||||
UpdateRoomToRoom(deltaTime);
|
||||
}
|
||||
|
||||
if (FlowForce.Length() > 150.0f && flowTargetHull!=null && flowTargetHull.Volume < flowTargetHull.FullVolume)
|
||||
{
|
||||
//UpdateFlowForce();
|
||||
|
||||
Vector2 pos = SimPosition;
|
||||
if (isHorizontal)
|
||||
{
|
||||
pos.Y = ConvertUnits.ToSimUnits(MathHelper.Clamp(lowerSurface, rect.Y-rect.Height, rect.Y));
|
||||
|
||||
Game1.particleManager.CreateParticle(new Vector2(pos.X, pos.Y - ToolBox.RandomFloat(0.0f, 0.1f)),
|
||||
0.0f, new Vector2(flowForce.X * ToolBox.RandomFloat(0.005f, 0.007f), flowForce.Y * ToolBox.RandomFloat(0.005f, 0.007f)), "watersplash");
|
||||
|
||||
pos.Y = ConvertUnits.ToSimUnits(ToolBox.RandomFloat(lowerSurface, rect.Y - rect.Height));
|
||||
Game1.particleManager.CreateParticle(pos, 0.0f, flowForce / 200.0f, "bubbles");
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.Y += Math.Sign(flowForce.Y) * ConvertUnits.ToSimUnits(rect.Height / 2.0f);
|
||||
for (int i = 0; i < rect.Width; i += (int)ToolBox.RandomFloat(20, 50))
|
||||
{
|
||||
pos.X = ConvertUnits.ToSimUnits(ToolBox.RandomFloat(rect.X, rect.X+rect.Width));
|
||||
Game1.particleManager.CreateParticle(pos,
|
||||
0.0f, new Vector2(flowForce.X * ToolBox.RandomFloat(0.005f, 0.008f), flowForce.Y * ToolBox.RandomFloat(0.005f, 0.008f)), "watersplash");
|
||||
|
||||
Game1.particleManager.CreateParticle(pos, ToolBox.VectorToAngle(flowForce), flowForce / 200.0f, "bubbles");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void UpdateRoomToRoom(float deltaTime)
|
||||
{
|
||||
if (linkedTo.Count < 2) return;
|
||||
Hull hull1 = (Hull)linkedTo[0];
|
||||
Hull hull2 = (Hull)linkedTo[1];
|
||||
|
||||
if (hull1.Volume == 0.0 && hull2.Volume == 0.0) return;
|
||||
|
||||
float size = (isHorizontal) ? rect.Height : rect.Width;
|
||||
|
||||
//a variable affecting the water flow through the gap
|
||||
//the larger the gap is, the faster the water flows
|
||||
float sizeModifier = size / 100.0f * open;
|
||||
|
||||
//horizontal gap (such as a regular door)
|
||||
if (isHorizontal)
|
||||
{
|
||||
//higherSurface = Math.Min(hull1.Surface,hull2.Surface);
|
||||
float delta=0.0f;
|
||||
//water level is above the lower boundary of the gap
|
||||
if (Math.Max(hull1.Surface+hull1.WaveY[hull1.WaveY.Length - 1], hull2.Surface+hull2.WaveY[0]) > rect.Y - size)
|
||||
{
|
||||
|
||||
int dir = (hull1.Pressure > hull2.Pressure) ? 1 : -1;
|
||||
|
||||
//water flowing from the righthand room to the lefthand room
|
||||
if (dir == -1)
|
||||
{
|
||||
if (!(hull2.Volume > 0.0f)) return;
|
||||
lowerSurface = hull1.Surface - hull1.WaveY[hull1.WaveY.Length - 1];
|
||||
//delta = Math.Min((room2.water.pressure - room1.water.pressure) * sizeModifier, Math.Min(room2.water.Volume, room2.Volume));
|
||||
//delta = Math.Min(delta, room1.Volume - room1.water.Volume + Water.MaxCompress);
|
||||
|
||||
flowTargetHull = hull1;
|
||||
|
||||
//make sure not to move more than what the room contains
|
||||
delta = Math.Min((hull2.Pressure - hull1.Pressure) * sizeModifier, Math.Min(hull2.Volume, hull2.FullVolume));
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull1.FullVolume + Hull.MaxCompress - (hull1.Volume));
|
||||
hull1.Volume += delta;
|
||||
hull2.Volume -= delta;
|
||||
if (hull1.Volume > hull1.FullVolume)
|
||||
hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure) / 2);
|
||||
|
||||
flowForce = new Vector2(-delta, 0.0f);
|
||||
}
|
||||
else if (dir == 1)
|
||||
{
|
||||
if (!(hull1.Volume > 0.0f)) return;
|
||||
lowerSurface = hull2.Surface - hull2.WaveY[1];
|
||||
|
||||
flowTargetHull = hull2;
|
||||
|
||||
//make sure not to move more than what the room contains
|
||||
delta = Math.Min((hull1.Pressure - hull2.Pressure) * sizeModifier, Math.Min(hull1.Volume, hull1.FullVolume));
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull2.FullVolume + Hull.MaxCompress - (hull2.Volume));
|
||||
hull1.Volume -= delta;
|
||||
hull2.Volume += delta;
|
||||
if (hull2.Volume > hull2.FullVolume)
|
||||
hull2.Pressure = Math.Max(hull2.Pressure, (hull1.Pressure + hull2.Pressure) / 2);
|
||||
|
||||
flowForce = new Vector2(delta, 0.0f);
|
||||
}
|
||||
|
||||
if (delta>100.0f)
|
||||
{
|
||||
float avg = (hull1.Surface + hull2.Surface) / 2.0f;
|
||||
//float avgVel = (hull2.WaveVel[1] + hull1.WaveVel[hull1.WaveY.Length - 2]) / 2.0f;
|
||||
|
||||
if (hull1.Volume < hull1.FullVolume - Hull.MaxCompress &&
|
||||
hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1] < rect.Y)
|
||||
{
|
||||
hull1.WaveVel[hull1.WaveY.Length - 1] = (avg-(hull1.Surface + hull1.WaveY[hull1.WaveY.Length - 1]))*0.1f;
|
||||
hull1.WaveVel[hull1.WaveY.Length - 2] = hull1.WaveVel[hull1.WaveY.Length - 1];
|
||||
}
|
||||
|
||||
if (hull2.Volume < hull2.FullVolume - Hull.MaxCompress &&
|
||||
hull2.Surface + hull2.WaveY[0] < rect.Y)
|
||||
{
|
||||
hull2.WaveVel[0] = (avg - (hull2.Surface + hull2.WaveY[0])) * 0.1f;
|
||||
hull2.WaveVel[1] = hull2.WaveVel[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//lower room is full of water
|
||||
if (hull2.Pressure > hull1.Pressure)
|
||||
{
|
||||
float delta = Math.Min(hull2.Volume - hull2.FullVolume + Hull.MaxCompress / 2.0f, deltaTime * 5000f * sizeModifier);
|
||||
delta = Math.Max(delta, 0.0f);
|
||||
hull1.Volume += delta;
|
||||
hull2.Volume -= delta;
|
||||
|
||||
flowTargetHull = hull1;
|
||||
|
||||
//delta = (water2.Pressure - water1.Pressure) * 0.1f;
|
||||
//if (delta > 0.1f)
|
||||
//{
|
||||
// int posX = (int)((rect.X + size / 2.0f - water1.Rect.X) / Hull.WaveWidth);
|
||||
// //water1.WaveY[posX] = delta;
|
||||
// water1.WaveVel[posX] = delta * 0.01f;
|
||||
//}
|
||||
if (hull1.Volume > hull1.FullVolume)
|
||||
{
|
||||
hull1.Pressure = Math.Max(hull1.Pressure, (hull1.Pressure + hull2.Pressure) / 2);
|
||||
}
|
||||
|
||||
flowForce = new Vector2(0.0f, delta);
|
||||
|
||||
}
|
||||
//there's water in the upper room, drop to lower
|
||||
else if (hull1.Volume > 0)
|
||||
{
|
||||
flowTargetHull = hull2;
|
||||
|
||||
//make sure the amount of water moved isn't more than what the room contains
|
||||
float delta = Math.Min(hull1.Volume, deltaTime * 10000f * sizeModifier);
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, (hull2.FullVolume + Math.Max(hull1.Volume - hull1.FullVolume, 0.0f)) - hull2.Volume + Hull.MaxCompress / 4.0f);
|
||||
|
||||
hull1.Volume -= delta;
|
||||
hull2.Volume += delta;
|
||||
|
||||
if (hull2.Volume > hull2.FullVolume)
|
||||
{
|
||||
hull2.Pressure = Math.Max(hull2.Pressure, (hull1.Pressure + hull2.Pressure) / 2);
|
||||
}
|
||||
|
||||
flowForce = new Vector2(0.0f,-delta);
|
||||
|
||||
//if (water2.Volume < water2.FullVolume - Hull.MaxCompress)
|
||||
//{
|
||||
// int posX = (int)((rect.X + size / 2.0f - water1.Rect.X) / Hull.WaveWidth);
|
||||
// //water1.WaveY[posX] = -delta;
|
||||
// if (posX > -1 && posX < water2.WaveVel.Length)
|
||||
// water1.WaveVel[posX] = -delta * 0.01f;
|
||||
|
||||
// posX = (int)((rect.X + size / 2.0f - water2.Rect.X) / Hull.WaveWidth);
|
||||
// //water2.WaveY[posX] = delta;
|
||||
// if (posX > -1 && posX<water2.WaveVel.Length)
|
||||
// water2.WaveVel[posX] = delta * 0.01f;
|
||||
//}
|
||||
}
|
||||
}
|
||||
if (open > 0.0f)
|
||||
{
|
||||
if (hull1.Volume>hull1.FullVolume && hull2.Volume>hull2.FullVolume)
|
||||
{
|
||||
float avgLethality = (hull1.LethalPressure + hull2.LethalPressure) / 2.0f;
|
||||
hull1.LethalPressure = avgLethality;
|
||||
hull2.LethalPressure = avgLethality;
|
||||
}
|
||||
else
|
||||
{
|
||||
hull1.LethalPressure = 0.0f;
|
||||
hull2.LethalPressure = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void UpdateRoomToOut(float deltaTime)
|
||||
{
|
||||
if (linkedTo.Count != 1) return;
|
||||
|
||||
float size = (isHorizontal) ? rect.Height : rect.Width;
|
||||
|
||||
Hull hull1 = (Hull)linkedTo[0];
|
||||
|
||||
//a variable affecting the water flow through the gap
|
||||
//the larger the gap is, the faster the water flows
|
||||
float sizeModifier = size * open;
|
||||
|
||||
float delta = Hull.MaxCompress * sizeModifier * deltaTime;
|
||||
|
||||
//make sure not to place more water to the target room than it can hold
|
||||
delta = Math.Min(delta, hull1.FullVolume + Hull.MaxCompress - hull1.Volume);
|
||||
hull1.Volume += delta;
|
||||
|
||||
if (hull1.Volume > hull1.FullVolume) hull1.Pressure += 0.5f;
|
||||
|
||||
flowTargetHull = hull1;
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
//water flowing from right to left
|
||||
if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
|
||||
{
|
||||
flowForce = new Vector2(-delta, 0.0f);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
flowForce = new Vector2(delta, 0.0f);
|
||||
}
|
||||
|
||||
higherSurface = hull1.Surface;
|
||||
lowerSurface = rect.Y;
|
||||
|
||||
if (hull1.Volume < hull1.FullVolume - Hull.MaxCompress &&
|
||||
hull1.Surface > -rect.Y)
|
||||
{
|
||||
float vel = (rect.Y + hull1.Surface) * 0.03f;
|
||||
|
||||
if (rect.X > hull1.Rect.X + hull1.Rect.Width / 2.0f)
|
||||
{
|
||||
hull1.WaveVel[hull1.WaveY.Length - 1] += vel;
|
||||
hull1.WaveVel[hull1.WaveY.Length - 2] += vel;
|
||||
}
|
||||
else
|
||||
{
|
||||
hull1.WaveVel[0] += vel;
|
||||
hull1.WaveVel[1] += vel;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rect.Y > hull1.Rect.Y - hull1.Rect.Height / 2.0f)
|
||||
{
|
||||
flowForce = new Vector2(0.0f, -delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
flowForce = new Vector2(0.0f,delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOxygen()
|
||||
{
|
||||
if (linkedTo.Count < 2) return;
|
||||
Hull hull1 = (Hull)linkedTo[0];
|
||||
Hull hull2 = (Hull)linkedTo[1];
|
||||
|
||||
float totalOxygen = hull1.Oxygen + hull2.Oxygen;
|
||||
float totalVolume = (hull1.FullVolume + hull2.FullVolume);
|
||||
|
||||
hull1.Oxygen += Math.Sign(totalOxygen*hull1.FullVolume/(totalVolume) - hull1.Oxygen) * Hull.OxygenDistributionSpeed;
|
||||
hull2.Oxygen += Math.Sign(totalOxygen*hull2.FullVolume/(totalVolume) - hull2.Oxygen) * Hull.OxygenDistributionSpeed;
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
if (soundIndex > -1) Sounds.SoundManager.Stop(soundIndex);
|
||||
}
|
||||
|
||||
public override XElement Save(XDocument doc)
|
||||
{
|
||||
XElement element = new XElement("Gap");
|
||||
|
||||
element.Add(new XAttribute("ID", ID),
|
||||
new XAttribute("x", rect.X),
|
||||
new XAttribute("y", rect.Y),
|
||||
new XAttribute("width", rect.Width),
|
||||
new XAttribute("height", rect.Height));
|
||||
|
||||
//if (linkedTo != null)
|
||||
//{
|
||||
// int i = 0;
|
||||
// foreach (Entity e in linkedTo)
|
||||
// {
|
||||
// if (e == null) continue;
|
||||
// element.Add(new XAttribute("linkedto" + i, e.ID));
|
||||
// i += 1;
|
||||
// }
|
||||
//}
|
||||
|
||||
doc.Root.Add(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
public static void Load(XElement element)
|
||||
{
|
||||
Rectangle rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
int.Parse(element.Attribute("width").Value),
|
||||
int.Parse(element.Attribute("height").Value));
|
||||
|
||||
Gap g = new Gap(rect);
|
||||
g.ID = int.Parse(element.Attribute("ID").Value);
|
||||
|
||||
g.linkedToID = new List<int>();
|
||||
//int i = 0;
|
||||
//while (element.Attribute("linkedto" + i) != null)
|
||||
//{
|
||||
// g.linkedToID.Add(int.Parse(element.Attribute("linkedto" + i).Value));
|
||||
// i += 1;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
|
||||
class Hull : MapEntity
|
||||
{
|
||||
public static List<Hull> hullList = new List<Hull>();
|
||||
|
||||
public static bool EditWater;
|
||||
|
||||
public static WaterRenderer renderer;
|
||||
|
||||
public static bool DebugDraw;
|
||||
|
||||
public const float OxygenDistributionSpeed = 500.0f;
|
||||
public const float OxygenDetoriationSpeed = 0.3f;
|
||||
public const float OxygenConsumptionSpeed = 1000.0f;
|
||||
|
||||
public const int WaveWidth = 16;
|
||||
const float WaveStiffness = 0.003f;
|
||||
const float WaveSpread = 0.05f;
|
||||
const float WaveDampening = 0.01f;
|
||||
|
||||
//how much excess water the room can contain (= more than the volume of the room)
|
||||
public const float MaxCompress = 10000f;
|
||||
|
||||
public readonly Dictionary<string, PropertyDescriptor> properties;
|
||||
|
||||
float lethalPressure;
|
||||
|
||||
float surface;
|
||||
float volume;
|
||||
float pressure;
|
||||
|
||||
float oxygen;
|
||||
|
||||
bool update;
|
||||
|
||||
float[] waveY; //displacement from the surface of the water
|
||||
float[] waveVel; //velocity of the point
|
||||
|
||||
float[] leftDelta;
|
||||
float[] rightDelta;
|
||||
|
||||
public override bool IsLinkable
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public float LethalPressure
|
||||
{
|
||||
get { return lethalPressure; }
|
||||
set { lethalPressure = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
public Vector2 Size
|
||||
{
|
||||
get { return new Vector2(rect.Width, rect.Height); }
|
||||
}
|
||||
|
||||
public float Surface
|
||||
{
|
||||
get { return surface; }
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get { return volume; }
|
||||
set
|
||||
{
|
||||
volume = MathHelper.Clamp(value, 0.0f, FullVolume + MaxCompress);
|
||||
if (volume < FullVolume) Pressure = rect.Y - rect.Height + volume / rect.Width;
|
||||
if (volume > 0.0f) update = true;
|
||||
}
|
||||
}
|
||||
|
||||
public float Oxygen
|
||||
{
|
||||
get { return oxygen; }
|
||||
set { oxygen = MathHelper.Clamp(value, 0.0f, FullVolume); }
|
||||
}
|
||||
|
||||
public float OxygenPercentage
|
||||
{
|
||||
get { return oxygen / FullVolume * 100.0f; }
|
||||
set { Oxygen = (value / 100.0f) * FullVolume; }
|
||||
}
|
||||
|
||||
public float FullVolume
|
||||
{
|
||||
get { return (rect.Width * rect.Height); }
|
||||
}
|
||||
|
||||
public float Pressure
|
||||
{
|
||||
get { return pressure; }
|
||||
set { pressure = value; }
|
||||
}
|
||||
|
||||
public float[] WaveY
|
||||
{
|
||||
get { return waveY; }
|
||||
}
|
||||
|
||||
public float[] WaveVel
|
||||
{
|
||||
get { return waveVel; }
|
||||
}
|
||||
|
||||
public Hull(Rectangle rectangle)
|
||||
{
|
||||
rect = rectangle;
|
||||
|
||||
OxygenPercentage = (float)(Game1.random.NextDouble() * 100.0);
|
||||
|
||||
properties = TypeDescriptor.GetProperties(this.GetType())
|
||||
.Cast<PropertyDescriptor>()
|
||||
.ToDictionary(pr => pr.Name);
|
||||
|
||||
int arraySize = (rectangle.Width / WaveWidth + 1);
|
||||
waveY = new float[arraySize];
|
||||
waveVel = new float[arraySize];
|
||||
|
||||
leftDelta = new float[arraySize];
|
||||
rightDelta = new float[arraySize];
|
||||
|
||||
surface = rect.Y - rect.Height;
|
||||
|
||||
aiTarget = new AITarget(this);
|
||||
aiTarget.SightRange = (rect.Width + rect.Height)*10.0f;
|
||||
|
||||
hullList.Add(this);
|
||||
|
||||
Item.UpdateHulls();
|
||||
Gap.UpdateHulls();
|
||||
|
||||
Volume = 0.0f;
|
||||
|
||||
//add to list of entities as well
|
||||
mapEntityList.Add(this);
|
||||
}
|
||||
|
||||
public override bool Contains(Vector2 position)
|
||||
{
|
||||
return (Map.RectContains(rect, position) &&
|
||||
!Map.RectContains(new Rectangle(rect.X + 8, rect.Y - 8, rect.Width -16, rect.Height -16), position));
|
||||
}
|
||||
|
||||
public int GetWaveIndex(Vector2 position)
|
||||
{
|
||||
int index = (int)(position.X - rect.X) / WaveWidth;
|
||||
index = MathHelper.Clamp(index, 0, waveY.Length-1);
|
||||
return index;
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
rect.X += (int)amount.X;
|
||||
rect.Y += (int)amount.Y;
|
||||
|
||||
Item.UpdateHulls();
|
||||
Gap.UpdateHulls();
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
Item.UpdateHulls();
|
||||
Gap.UpdateHulls();
|
||||
|
||||
//renderer.Dispose();
|
||||
|
||||
hullList.Remove(this);
|
||||
}
|
||||
|
||||
public override void Update(Camera cam, float deltaTime)
|
||||
{
|
||||
Oxygen -= OxygenDetoriationSpeed * deltaTime;
|
||||
|
||||
if (EditWater)
|
||||
{
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
if (Map.RectContains(rect, position))
|
||||
{
|
||||
if (PlayerInput.LeftButtonDown())
|
||||
{
|
||||
waveY[(int)(position.X - rect.X) / Hull.WaveWidth] = 100.0f;
|
||||
Volume = Volume + 1500.0f;
|
||||
}
|
||||
else if (PlayerInput.GetMouseState.RightButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
|
||||
{
|
||||
Volume = Volume - 1500.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!update) return;
|
||||
|
||||
float surfaceY = rect.Y - rect.Height + Volume / rect.Width;
|
||||
for (int i = 0; i < waveY.Length; i++)
|
||||
{
|
||||
float maxDelta = Math.Max(Math.Abs(rightDelta[i]), Math.Abs(leftDelta[i]));
|
||||
if (maxDelta > ToolBox.RandomFloat(0.2f,10.0f))
|
||||
{
|
||||
Game1.particleManager.CreateParticle(ConvertUnits.ToSimUnits(new Vector2(rect.X + WaveWidth * i,surface + waveY[i])),
|
||||
0.0f, new Vector2(0.0f, waveVel[i]/10.0f-1.0f), "mist");
|
||||
}
|
||||
|
||||
waveY[i] = waveY[i] + waveVel[i];
|
||||
|
||||
if (surfaceY + waveY[i] > rect.Y)
|
||||
{
|
||||
waveY[i] -= (surfaceY + waveY[i]) - rect.Y;
|
||||
waveVel[i] = waveVel[i] * -0.5f;
|
||||
}
|
||||
else if (surfaceY + waveY[i] < rect.Y - rect.Height)
|
||||
{
|
||||
waveY[i] -= (surfaceY + waveY[i]) - (rect.Y - rect.Height);
|
||||
waveVel[i] = waveVel[i] * -0.5f;
|
||||
}
|
||||
|
||||
|
||||
//acceleration
|
||||
float a = -WaveStiffness * waveY[i] - waveVel[i] * WaveDampening;
|
||||
waveVel[i] = waveVel[i] + a;
|
||||
|
||||
}
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
leftDelta[i] = WaveSpread * (waveY[i] - waveY[i - 1]);
|
||||
waveVel[i - 1] = waveVel[i - 1] + leftDelta[i];
|
||||
|
||||
rightDelta[i] = WaveSpread * (waveY[i] - waveY[i + 1]);
|
||||
waveVel[i + 1] = waveVel[i + 1] + rightDelta[i];
|
||||
}
|
||||
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
waveY[i - 1] = waveY[i - 1] + leftDelta[i];
|
||||
waveY[i + 1] = waveY[i + 1] + rightDelta[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (volume<FullVolume)
|
||||
{
|
||||
LethalPressure -= 0.5f;
|
||||
if (Volume == 0.0f)
|
||||
{
|
||||
for (int i = 1; i < waveY.Length - 1; i++)
|
||||
{
|
||||
if (waveY[i] > 0.1f) return;
|
||||
}
|
||||
update = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LethalPressure += 1.0f;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing)
|
||||
{
|
||||
if (!editing && !DebugDraw) return;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(rect.X, -rect.Y),
|
||||
new Vector2(rect.Width, rect.Height),
|
||||
isHighlighted ? Color.Green : Color.Blue);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(rect.X, -rect.Y, rect.Width, rect.Height),
|
||||
Color.Red*((100.0f-OxygenPercentage)/400.0f), true);
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Pressure: " + ((int)pressure - rect.Y).ToString() +
|
||||
" - Lethality: " + lethalPressure +
|
||||
" - Oxygen: "+((int)OxygenPercentage).ToString(), new Vector2(rect.X+10, -rect.Y+10), Color.Black);
|
||||
spriteBatch.DrawString(GUI.font, volume.ToString() +" / "+ FullVolume.ToString(), new Vector2(rect.X+10, -rect.Y+30), Color.Black);
|
||||
|
||||
if (isSelected && editing)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(rect.X - 5, -rect.Y - 5),
|
||||
new Vector2(rect.Width + 10, rect.Height + 10),
|
||||
Color.Red);
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(GraphicsDevice graphicsDevice, Camera cam)
|
||||
{
|
||||
if (renderer.positionInBuffer > renderer.vertices.Length - 6) return;
|
||||
|
||||
//calculate where the surface should be based on the water volume
|
||||
float top = rect.Y;
|
||||
float bottom = rect.Y - rect.Height;
|
||||
float surfaceY = bottom + Volume / rect.Width;
|
||||
|
||||
//interpolate the position of the rendered surface towards the "target surface"
|
||||
surface = surface + (surfaceY - surface) / 10.0f;
|
||||
|
||||
Matrix transform =
|
||||
cam.Transform
|
||||
* Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f;
|
||||
|
||||
if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) return;
|
||||
|
||||
if (!update)
|
||||
{
|
||||
// create the four corners of our triangle.
|
||||
Vector3 p1 = new Vector3(rect.X, top, 0.0f);
|
||||
Vector3 p2 = new Vector3(rect.X + rect.Width, top, 0.0f);
|
||||
|
||||
Vector3 p3 = new Vector3(p2.X, bottom, 0.0f);
|
||||
Vector3 p4 = new Vector3(p1.X, bottom, 0.0f);
|
||||
|
||||
renderer.vertices[renderer.positionInBuffer] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 1] = new WaterVertex(p2, new Vector2(p2.X, -p2.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 2] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform);
|
||||
|
||||
renderer.vertices[renderer.positionInBuffer + 3] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 4] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 5] = new WaterVertex(p4, new Vector2(p4.X, -p4.Y), transform);
|
||||
|
||||
renderer.positionInBuffer += 6;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int x = rect.X;
|
||||
int start = (int)Math.Floor((float)(cam.WorldView.X - x) / WaveWidth);
|
||||
start = Math.Max(start, 0);
|
||||
|
||||
int end = (waveY.Length - 1)
|
||||
- (int)Math.Floor((float)((x + rect.Width) - (cam.WorldView.X + cam.WorldView.Width)) / WaveWidth);
|
||||
end = Math.Min(end, waveY.Length - 1);
|
||||
|
||||
x += start * WaveWidth;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
if (renderer.positionInBuffer > renderer.vertices.Length - 6) return;
|
||||
|
||||
Vector3 p1 = new Vector3(x, top, 0.0f);
|
||||
Vector3 p4 = new Vector3(p1.X, surface + waveY[i], 0.0f);
|
||||
|
||||
//skip adjacent "water rects" if the surface of the water is roughly at the same position
|
||||
int width = WaveWidth;
|
||||
while (i<end-1 && Math.Abs(waveY[i + 1] - waveY[i]) < 1.0f)
|
||||
{
|
||||
width += WaveWidth;
|
||||
i++;
|
||||
}
|
||||
|
||||
Vector3 p2 = new Vector3(x + width, top, 0.0f);
|
||||
Vector3 p3 = new Vector3(p2.X, surface + waveY[i+1], 0.0f);
|
||||
|
||||
renderer.vertices[renderer.positionInBuffer] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 1] = new WaterVertex(p2, new Vector2(p2.X, -p2.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 2] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform);
|
||||
|
||||
renderer.vertices[renderer.positionInBuffer + 3] = new WaterVertex(p1, new Vector2(p1.X, -p1.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 4] = new WaterVertex(p3, new Vector2(p3.X, -p3.Y), transform);
|
||||
renderer.vertices[renderer.positionInBuffer + 5] = new WaterVertex(p4, new Vector2(p4.X, -p4.Y), transform);
|
||||
|
||||
renderer.positionInBuffer += 6;
|
||||
|
||||
x += width;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//returns the water block which contains the point (or null if it isn't inside any)
|
||||
public static Hull FindHull(Vector2 position, Hull guess = null)
|
||||
{
|
||||
if (guess != null && hullList.Contains(guess))
|
||||
{
|
||||
if (Map.RectContains(guess.rect, position)) return guess;
|
||||
}
|
||||
|
||||
foreach (Hull w in hullList)
|
||||
{
|
||||
if (Map.RectContains(w.rect, position)) return w;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override XElement Save(XDocument doc)
|
||||
{
|
||||
XElement element = new XElement("Hull");
|
||||
|
||||
element.Add(new XAttribute("ID", ID),
|
||||
new XAttribute("x", rect.X),
|
||||
new XAttribute("y", rect.Y),
|
||||
new XAttribute("width", rect.Width),
|
||||
new XAttribute("height", rect.Height),
|
||||
new XAttribute("water", volume));
|
||||
|
||||
doc.Root.Add(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static void Load(XElement element)
|
||||
{
|
||||
Rectangle rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
int.Parse(element.Attribute("width").Value),
|
||||
int.Parse(element.Attribute("height").Value));
|
||||
|
||||
Hull h = new Hull(rect);
|
||||
|
||||
h.volume = ToolBox.GetAttributeFloat(element, "pressure", 0.0f);
|
||||
|
||||
h.ID = int.Parse(element.Attribute("ID").Value);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
interface IDamageable
|
||||
{
|
||||
//float Damage
|
||||
//{
|
||||
// get;
|
||||
// set;
|
||||
//}
|
||||
|
||||
Vector2 SimPosition
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
void AddDamage(Vector2 position, float amount, float bleedingAmount, float stun);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Subsurface.Lights
|
||||
{
|
||||
class ConvexHull
|
||||
{
|
||||
public static List<ConvexHull> list = new List<ConvexHull>();
|
||||
static BasicEffect drawingEffect;
|
||||
|
||||
private VertexPositionColor[] vertices;
|
||||
private short[] indices;
|
||||
int primitiveCount;
|
||||
|
||||
bool[] backFacing;
|
||||
VertexPositionColor[] shadowVertices;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//private Vector2 position = Vector2.Zero;
|
||||
//public Vector2 Position
|
||||
//{
|
||||
// get { return position; }
|
||||
// set { position = value; }
|
||||
//}
|
||||
|
||||
public ConvexHull(Vector2[] points, Color color)
|
||||
{
|
||||
int vertexCount = points.Length;
|
||||
vertices = new VertexPositionColor[vertexCount + 1];
|
||||
Vector2 center = Vector2.Zero;
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
vertices[i] = new VertexPositionColor(new Vector3(points[i], 0), color);
|
||||
center += points[i];
|
||||
}
|
||||
center /= points.Length;
|
||||
vertices[vertexCount] = new VertexPositionColor(new Vector3(center, 0), color);
|
||||
|
||||
primitiveCount = points.Length;
|
||||
indices = new short[primitiveCount * 3];
|
||||
|
||||
for (int i = 0; i < primitiveCount; i++)
|
||||
{
|
||||
indices[3 * i] = (short)i;
|
||||
indices[3 * i + 1] = (short)((i + 1) % vertexCount);
|
||||
indices[3 * i + 2] = (short)vertexCount;
|
||||
}
|
||||
backFacing = new bool[vertexCount];
|
||||
|
||||
|
||||
Enabled = true;
|
||||
|
||||
list.Add(this);
|
||||
}
|
||||
|
||||
public void Move(Vector2 amount)
|
||||
{
|
||||
for (int i = 0; i < vertices.Count(); i++)
|
||||
{
|
||||
vertices[i].Position = new Vector3(vertices[i].Position.X + amount.X, vertices[i].Position.Y + amount.Y, vertices[i].Position.Z);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVertices(Vector2[] points)
|
||||
{
|
||||
int vertexCount = points.Length;
|
||||
vertices = new VertexPositionColor[vertexCount + 1];
|
||||
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
{
|
||||
vertices[i] = new VertexPositionColor(new Vector3(points[i], 0), Color.Black);
|
||||
}
|
||||
}
|
||||
|
||||
//public void Draw(GameTime gameTime)
|
||||
//{
|
||||
// device.RasterizerState = RasterizerState.CullNone;
|
||||
// device.BlendState = BlendState.Opaque;
|
||||
|
||||
// drawingEffect.World = Matrix.CreateTranslation(position.X, position.Y, 0);
|
||||
|
||||
// foreach (EffectPass pass in drawingEffect.CurrentTechnique.Passes)
|
||||
// {
|
||||
// pass.Apply();
|
||||
// device.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, vertices, 0, vertices.Length, indices, 0, primitiveCount);
|
||||
// }
|
||||
//}
|
||||
|
||||
public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Vector2 lightSourcePos)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
|
||||
if (drawingEffect == null)
|
||||
{
|
||||
drawingEffect = new BasicEffect(graphicsDevice);
|
||||
drawingEffect.VertexColorEnabled = true;
|
||||
}
|
||||
|
||||
//compute facing of each edge, using N*L
|
||||
for (int i = 0; i < primitiveCount; i++)
|
||||
{
|
||||
Vector2 firstVertex = new Vector2(vertices[i].Position.X, vertices[i].Position.Y);
|
||||
int secondIndex = (i + 1) % primitiveCount;
|
||||
Vector2 secondVertex = new Vector2(vertices[secondIndex].Position.X, vertices[secondIndex].Position.Y);
|
||||
Vector2 middle = (firstVertex + secondVertex) / 2;
|
||||
|
||||
Vector2 L = lightSourcePos - middle;
|
||||
|
||||
Vector2 N = new Vector2();
|
||||
N.X = -(secondVertex.Y - firstVertex.Y);
|
||||
N.Y = secondVertex.X - firstVertex.X;
|
||||
|
||||
backFacing[i] = (Vector2.Dot(N, L) < 0);
|
||||
}
|
||||
|
||||
//find beginning and ending vertices which
|
||||
//belong to the shadow
|
||||
int startingIndex = 0;
|
||||
int endingIndex = 0;
|
||||
for (int i = 0; i < primitiveCount; i++)
|
||||
{
|
||||
int currentEdge = i;
|
||||
int nextEdge = (i + 1) % primitiveCount;
|
||||
|
||||
if (backFacing[currentEdge] && !backFacing[nextEdge])
|
||||
endingIndex = nextEdge;
|
||||
|
||||
if (!backFacing[currentEdge] && backFacing[nextEdge])
|
||||
startingIndex = nextEdge;
|
||||
}
|
||||
|
||||
int shadowVertexCount;
|
||||
|
||||
//nr of vertices that are in the shadow
|
||||
if (endingIndex > startingIndex)
|
||||
shadowVertexCount = endingIndex - startingIndex + 1;
|
||||
else
|
||||
shadowVertexCount = primitiveCount + 1 - startingIndex + endingIndex;
|
||||
|
||||
shadowVertices = new VertexPositionColor[shadowVertexCount * 2];
|
||||
|
||||
//create a triangle strip that has the shape of the shadow
|
||||
int currentIndex = startingIndex;
|
||||
int svCount = 0;
|
||||
while (svCount != shadowVertexCount * 2)
|
||||
{
|
||||
Vector3 vertexPos = vertices[currentIndex].Position;
|
||||
|
||||
//one vertex on the hull
|
||||
shadowVertices[svCount] = new VertexPositionColor();
|
||||
shadowVertices[svCount].Color = Color.Black;
|
||||
shadowVertices[svCount].Position = vertexPos;
|
||||
|
||||
//one extruded by the light direction
|
||||
shadowVertices[svCount + 1] = new VertexPositionColor();
|
||||
shadowVertices[svCount + 1].Color = Color.Black;
|
||||
Vector3 L2P = vertexPos - new Vector3(lightSourcePos, 0);
|
||||
L2P.Normalize();
|
||||
shadowVertices[svCount + 1].Position = new Vector3(lightSourcePos, 0) + L2P * 9000;
|
||||
|
||||
svCount += 2;
|
||||
currentIndex = (currentIndex + 1) % primitiveCount;
|
||||
}
|
||||
|
||||
drawingEffect.World = cam.ShaderTransform
|
||||
* Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1) * 0.5f;
|
||||
drawingEffect.CurrentTechnique.Passes[0].Apply();
|
||||
|
||||
graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertexCount * 2 - 2);
|
||||
|
||||
}
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
list.Remove(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Subsurface.Lights
|
||||
{
|
||||
class LightManager
|
||||
{
|
||||
public static Vector2 viewPos;
|
||||
|
||||
public static bool fowEnabled = true;
|
||||
|
||||
public static void DrawFow(GraphicsDevice graphics, Camera cam)
|
||||
{
|
||||
if (!fowEnabled) return;
|
||||
foreach (ConvexHull convexHull in ConvexHull.list)
|
||||
{
|
||||
convexHull.DrawShadows(graphics, cam, viewPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using FarseerPhysics.Collision;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
public enum Direction : byte
|
||||
{
|
||||
None = 0, Left = 1, Right = 2
|
||||
}
|
||||
|
||||
static class Map
|
||||
{
|
||||
public static Vector2 gridSize = new Vector2(16.0f, 16.0f);
|
||||
|
||||
private static Vector2 lastPickedPosition;
|
||||
private static float lastPickedFraction;
|
||||
|
||||
private static Rectangle borders;
|
||||
|
||||
private static string filePath;
|
||||
|
||||
public static Vector2 LastPickedPosition
|
||||
{
|
||||
get { return lastPickedPosition; }
|
||||
}
|
||||
|
||||
public static float LastPickedFraction
|
||||
{
|
||||
get { return lastPickedFraction; }
|
||||
}
|
||||
|
||||
public static Rectangle Borders
|
||||
{
|
||||
get { return borders; }
|
||||
}
|
||||
|
||||
public static string FilePath
|
||||
{
|
||||
get { return filePath; }
|
||||
}
|
||||
|
||||
public static void Draw(SpriteBatch spriteBatch, bool editing = false)
|
||||
{
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count(); i++ )
|
||||
{
|
||||
MapEntity.mapEntityList[i].Draw(spriteBatch, editing);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawFront(SpriteBatch spriteBatch, bool editing = false)
|
||||
{
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count(); i++)
|
||||
{
|
||||
if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth < 0.5f)
|
||||
MapEntity.mapEntityList[i].Draw(spriteBatch, editing);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawBack(SpriteBatch spriteBatch, bool editing = false)
|
||||
{
|
||||
|
||||
for (int i = 0; i < MapEntity.mapEntityList.Count(); i++)
|
||||
{
|
||||
if (MapEntity.mapEntityList[i].sprite == null || MapEntity.mapEntityList[i].sprite.Depth >= 0.5f)
|
||||
MapEntity.mapEntityList[i].Draw(spriteBatch, editing);
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2 MouseToWorldGrid(Camera cam)
|
||||
{
|
||||
Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y);
|
||||
position = cam.ScreenToWorld(position);
|
||||
|
||||
return VectorToWorldGrid(position);
|
||||
}
|
||||
|
||||
public static Vector2 VectorToWorldGrid(Vector2 position)
|
||||
{
|
||||
position.X = (float)Math.Floor(Convert.ToDouble(position.X / gridSize.X)) * gridSize.X;
|
||||
position.Y = (float)Math.Ceiling(Convert.ToDouble(position.Y / gridSize.Y)) * gridSize.Y;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
public static Rectangle AbsRect(Vector2 pos, Vector2 size)
|
||||
{
|
||||
if (size.X < 0.0f)
|
||||
{
|
||||
pos.X += size.X;
|
||||
size.X = -size.X;
|
||||
}
|
||||
if (size.Y < 0.0f)
|
||||
{
|
||||
pos.Y -= size.Y;
|
||||
size.Y = -size.Y;
|
||||
}
|
||||
|
||||
return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
|
||||
}
|
||||
|
||||
public static bool RectContains(Rectangle rect, Vector2 pos)
|
||||
{
|
||||
return (pos.X > rect.X && pos.X < rect.X + rect.Width
|
||||
&& pos.Y < rect.Y && pos.Y > rect.Y - rect.Height);
|
||||
}
|
||||
|
||||
public static bool RectsOverlap(Rectangle rect1, Rectangle rect2)
|
||||
{
|
||||
return !(rect1.X > rect2.X + rect2.Width || rect1.X + rect1.Width < rect2.X ||
|
||||
rect1.Y < rect2.Y - rect2.Height || rect1.Y - rect1.Height > rect2.Y);
|
||||
}
|
||||
|
||||
public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List<Body> ignoredBodies = null)
|
||||
{
|
||||
float closestFraction = 1.0f;
|
||||
Body closestBody = null;
|
||||
Game1.world.RayCast((fixture, point, normal, fraction) =>
|
||||
{
|
||||
if (fixture == null || fixture.CollisionCategories == Category.None) return -1;
|
||||
if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1;
|
||||
|
||||
Structure structure = fixture.Body.UserData as Structure;
|
||||
if (structure != null && (structure.IsPlatform || !structure.HasBody)) return -1;
|
||||
|
||||
if (fraction < closestFraction)
|
||||
{
|
||||
closestFraction = fraction;
|
||||
if (fixture.Body!=null) closestBody = fixture.Body;
|
||||
}
|
||||
return fraction;
|
||||
}
|
||||
, rayStart, rayEnd);
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
return closestBody;
|
||||
}
|
||||
|
||||
|
||||
public static Structure CheckVisibility(Vector2 rayStart, Vector2 rayEnd)
|
||||
{
|
||||
Structure closestStructure = null;
|
||||
float closestFraction = 1.0f;
|
||||
|
||||
if (Vector2.Distance(rayStart,rayEnd)<0.01f)
|
||||
{
|
||||
closestFraction = 0.01f;
|
||||
return null;
|
||||
}
|
||||
|
||||
Game1.world.RayCast((fixture, point, normal, fraction) =>
|
||||
{
|
||||
if (fixture == null || fixture.CollisionCategories != Physics.CollisionWall) return -1;
|
||||
|
||||
Structure structure = fixture.Body.UserData as Structure;
|
||||
if (structure != null)
|
||||
{
|
||||
if (structure.IsPlatform || structure.StairDirection != Direction.None) return -1;
|
||||
int sectionIndex = structure.FindSectionIndex(ConvertUnits.ToDisplayUnits(point));
|
||||
if (sectionIndex > -1 && structure.SectionHasHole(sectionIndex)) return -1;
|
||||
}
|
||||
|
||||
if (fraction < closestFraction)
|
||||
{
|
||||
if (structure != null) closestStructure = structure;
|
||||
closestFraction = fraction;
|
||||
}
|
||||
return closestFraction;
|
||||
}
|
||||
, rayStart, rayEnd);
|
||||
|
||||
|
||||
lastPickedPosition = rayStart + (rayEnd - rayStart) * closestFraction;
|
||||
lastPickedFraction = closestFraction;
|
||||
return closestStructure;
|
||||
}
|
||||
|
||||
public static Body PickBody(Vector2 point)
|
||||
{
|
||||
Body foundBody = null;
|
||||
AABB aabb = new AABB(point, point);
|
||||
|
||||
Game1.world.QueryAABB(p =>
|
||||
{
|
||||
foundBody = p.Body;
|
||||
|
||||
return true;
|
||||
|
||||
}, ref aabb);
|
||||
|
||||
return foundBody;
|
||||
}
|
||||
|
||||
public static bool InsideWall(Vector2 point)
|
||||
{
|
||||
Body foundBody = Map.PickBody(point);
|
||||
if (foundBody==null) return false;
|
||||
|
||||
Structure wall = foundBody.UserData as Structure;
|
||||
if (wall == null || wall.IsPlatform) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void Save(string filePath, string fileName)
|
||||
{
|
||||
if (fileName==null)
|
||||
{
|
||||
DebugConsole.ThrowError("No save file selected");
|
||||
return;
|
||||
}
|
||||
XDocument doc = new XDocument(
|
||||
new XElement((XName)fileName));
|
||||
|
||||
foreach (MapEntity e in MapEntity.mapEntityList)
|
||||
{
|
||||
e.Save(doc);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string docString = doc.ToString();
|
||||
ToolBox.CompressStringToFile(filePath+fileName+".gz", doc.ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Saving map ''" + filePath + fileName + "'' failed!");
|
||||
}
|
||||
|
||||
|
||||
//doc.Save(filePath + fileName);
|
||||
}
|
||||
|
||||
public static string[] GetMapFilePaths()
|
||||
{
|
||||
string[] mapFilePaths;
|
||||
try
|
||||
{
|
||||
mapFilePaths = Directory.GetFiles("Content/SavedMaps");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't open directory ''Content/SavedMaps''!", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return mapFilePaths;
|
||||
}
|
||||
|
||||
public static void Load(string filePath, string fileName)
|
||||
{
|
||||
Load(filePath + fileName);
|
||||
}
|
||||
|
||||
public static void Load(string file)
|
||||
{
|
||||
Clear();
|
||||
filePath = file;
|
||||
XDocument doc = null;
|
||||
|
||||
string extension = Path.GetExtension(file);
|
||||
|
||||
if (extension==".gz")
|
||||
{
|
||||
Stream stream = ToolBox.DecompressFiletoStream(file);
|
||||
if (stream == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading map ''" + file + "'' failed!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
stream.Position = 0;
|
||||
doc = XDocument.Load(stream); //ToolBox.TryLoadXml(file);
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
DebugConsole.ThrowError("Loading map ''" + file + "'' failed!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (extension ==".xml")
|
||||
{
|
||||
doc = XDocument.Load(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Couldn't load map ''"+file+"! (Unrecognized file extension)");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
foreach (XElement element in doc.Root.Elements())
|
||||
{
|
||||
string typeName = element.Name.ToString();
|
||||
|
||||
Type t;
|
||||
try
|
||||
{
|
||||
// Get the type of a specified class.
|
||||
t = Type.GetType("Subsurface." + typeName + ", Subsurface", true, true);
|
||||
if (t == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + file + "! Could not find a entity of the type ''" + typeName + "''.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + file + "! Could not find a entity of the type ''" + typeName + "''.", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
MethodInfo loadMethod = t.GetMethod("Load");
|
||||
loadMethod.Invoke(t, new object[] { element });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not find the method ''Load'' in " + t + ".", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
borders = new Rectangle(0, 0, 1, 1);
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.Rect.X < borders.X || borders.X == 0) borders.X = hull.Rect.X;
|
||||
if (hull.Rect.Y > borders.Y || borders.Y == 0) borders.Y = hull.Rect.Y;
|
||||
|
||||
if (hull.Rect.X + hull.Rect.Width > borders.X + borders.Width) borders.Width = hull.Rect.X + hull.Rect.Width - borders.X;
|
||||
if (hull.Rect.Y - hull.Rect.Height < borders.Y - borders.Height) borders.Height = borders.Y - (hull.Rect.Y - hull.Rect.Height);
|
||||
}
|
||||
|
||||
MapEntity.LinkAll();
|
||||
foreach (Item item in Item.itemList)
|
||||
{
|
||||
foreach (ItemComponent ic in item.components)
|
||||
{
|
||||
ic.OnMapLoaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void Clear()
|
||||
{
|
||||
Map.filePath = "";
|
||||
|
||||
if (Game1.gameScreen.Cam != null) Game1.gameScreen.Cam.TargetPos = Vector2.Zero;
|
||||
|
||||
Entity.RemoveAll();
|
||||
|
||||
if (Game1.gameSession!=null)
|
||||
Game1.gameSession.crewManager.EndShift();
|
||||
|
||||
PhysicsBody.list.Clear();
|
||||
|
||||
Ragdoll.list.Clear();
|
||||
|
||||
Game1.world.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class MapEntity : Entity
|
||||
{
|
||||
public static List<MapEntity> mapEntityList = new List<MapEntity>();
|
||||
|
||||
//which entities have been selected for editing
|
||||
protected static List<MapEntity> selectedList = new List<MapEntity>();
|
||||
|
||||
protected static GUIComponent editingHUD;
|
||||
|
||||
protected static Vector2 selectionPos = Vector2.Zero;
|
||||
protected static Vector2 selectionSize = Vector2.Zero;
|
||||
|
||||
protected static Vector2 startMovingPos = Vector2.Zero;
|
||||
|
||||
protected List<int> linkedToID;
|
||||
|
||||
//observable collection because some entities may need to be notified when the collection is modified
|
||||
public ObservableCollection<MapEntity> linkedTo;
|
||||
|
||||
//protected float soundRange;
|
||||
//protected float sightRange;
|
||||
|
||||
//is the mouse inside the rect
|
||||
protected bool isHighlighted;
|
||||
|
||||
protected bool isSelected;
|
||||
|
||||
//the position and dimensions of the entity
|
||||
protected Rectangle rect;
|
||||
|
||||
public virtual Rectangle Rect {
|
||||
get { return rect; }
|
||||
set { rect = value; }
|
||||
}
|
||||
|
||||
public virtual Sprite sprite
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public virtual bool IsLinkable
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public Vector2 Position
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector2(
|
||||
rect.X + rect.Width / 2.0f,
|
||||
rect.Y - rect.Height / 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector2 SimPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConvertUnits.ToSimUnits(Position);
|
||||
}
|
||||
}
|
||||
|
||||
public float SoundRange
|
||||
{
|
||||
get
|
||||
{
|
||||
if (aiTarget == null) return 0.0f;
|
||||
return aiTarget.SoundRange;
|
||||
}
|
||||
set { aiTarget.SoundRange = value; }
|
||||
}
|
||||
|
||||
public float SightRange
|
||||
{
|
||||
get
|
||||
{
|
||||
if (aiTarget == null) return 0.0f;
|
||||
return aiTarget.SightRange;
|
||||
}
|
||||
set { aiTarget.SightRange = value; }
|
||||
}
|
||||
|
||||
public bool IsHighlighted {
|
||||
get { return isHighlighted; }
|
||||
set { isHighlighted = value; }
|
||||
}
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get { return isSelected; }
|
||||
set { isSelected = value; }
|
||||
}
|
||||
|
||||
public virtual string Name
|
||||
{
|
||||
get { return ""; }
|
||||
}
|
||||
|
||||
public virtual void Move(Vector2 amount)
|
||||
{
|
||||
rect.X += (int)amount.X;
|
||||
rect.Y += (int)amount.Y;
|
||||
}
|
||||
|
||||
public virtual bool Contains(Vector2 position)
|
||||
{
|
||||
return (Map.RectContains(rect, position));
|
||||
}
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch, bool editing) {}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
mapEntityList.Remove(this);
|
||||
|
||||
if (aiTarget != null) aiTarget.Remove();
|
||||
|
||||
if (linkedTo != null)
|
||||
{
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
e.RemoveLinked(this);
|
||||
}
|
||||
linkedTo.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call Update() on every object in Entity.list
|
||||
/// </summary>
|
||||
public static void UpdateAll(Camera cam, float deltaTime)
|
||||
{
|
||||
foreach (Item item in Item.itemList)
|
||||
{
|
||||
item.Updated = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mapEntityList.Count; i++)
|
||||
{
|
||||
mapEntityList[i].Update(cam, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Update(Camera cam, float deltaTime) { }
|
||||
|
||||
/// <summary>
|
||||
/// Update the selection logic in editmap-screen
|
||||
/// </summary>
|
||||
public static void UpdateSelecting(Camera cam)
|
||||
{
|
||||
if (GUIComponent.MouseOn != null) return;
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
e.isHighlighted = false;
|
||||
e.isSelected = false;
|
||||
}
|
||||
|
||||
if (MapEntityPrefab.Selected != null)
|
||||
{
|
||||
selectionPos = Vector2.Zero;
|
||||
selectedList.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.Delete))
|
||||
{
|
||||
foreach (MapEntity e in selectedList)
|
||||
e.Remove();
|
||||
selectedList.Clear();
|
||||
}
|
||||
|
||||
Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y);
|
||||
position = cam.ScreenToWorld(position);
|
||||
|
||||
MapEntity highLightedEntity = null;
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (highLightedEntity == null || e.sprite == null ||
|
||||
(highLightedEntity.sprite!=null && e.sprite.Depth < highLightedEntity.sprite.Depth))
|
||||
{
|
||||
if (e.Contains(position)) highLightedEntity = e;
|
||||
}
|
||||
e.isSelected = false;
|
||||
}
|
||||
|
||||
if (highLightedEntity!=null)
|
||||
highLightedEntity.isHighlighted = true;
|
||||
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
e.isSelected = true;
|
||||
}
|
||||
|
||||
//started moving selected entities
|
||||
if (startMovingPos != Vector2.Zero)
|
||||
{
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Released)
|
||||
{
|
||||
//mouse released -> move the entities to the new position of the mouse
|
||||
|
||||
Vector2 moveAmount = position - startMovingPos;
|
||||
moveAmount = Map.VectorToWorldGrid(moveAmount);
|
||||
|
||||
if (moveAmount != Vector2.Zero)
|
||||
{
|
||||
foreach (MapEntity e in selectedList)
|
||||
e.Move(moveAmount);
|
||||
}
|
||||
|
||||
startMovingPos = Vector2.Zero;
|
||||
}
|
||||
|
||||
}
|
||||
//started dragging a "selection rectangle"
|
||||
else if (selectionPos != Vector2.Zero)
|
||||
{
|
||||
selectionSize.X = position.X - selectionPos.X;
|
||||
selectionSize.Y = selectionPos.Y - position.Y;
|
||||
|
||||
List<MapEntity> newSelection = new List<MapEntity>();// FindSelectedEntities(selectionPos, selectionSize);
|
||||
if (Math.Abs(selectionSize.X) > Map.gridSize.X || Math.Abs(selectionSize.Y) > Map.gridSize.Y)
|
||||
{
|
||||
newSelection = FindSelectedEntities(selectionPos, selectionSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (highLightedEntity != null) newSelection.Add(highLightedEntity);
|
||||
}
|
||||
|
||||
foreach (MapEntity e in newSelection)
|
||||
{
|
||||
e.isHighlighted = true;
|
||||
}
|
||||
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Released)
|
||||
{
|
||||
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.LeftControl) ||
|
||||
PlayerInput.GetKeyboardState.IsKeyDown(Keys.RightControl))
|
||||
{
|
||||
foreach (MapEntity e in newSelection)
|
||||
{
|
||||
bool alreadySelected = false;
|
||||
|
||||
foreach (MapEntity e2 in selectedList)
|
||||
{
|
||||
Debug.WriteLine(e.ID+", "+e2.ID);
|
||||
if (e.ID == e2.ID) alreadySelected = true;
|
||||
}
|
||||
|
||||
if (alreadySelected)
|
||||
selectedList.Remove(e);
|
||||
else
|
||||
selectedList.Add(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedList = newSelection;
|
||||
}
|
||||
|
||||
selectionPos = Vector2.Zero;
|
||||
Debug.WriteLine("zero");
|
||||
selectionSize = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
//default, not doing anything specific yet
|
||||
else
|
||||
{
|
||||
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed &&
|
||||
PlayerInput.GetKeyboardState.IsKeyUp(Keys.Space))
|
||||
{
|
||||
//if clicking a selected entity, start moving it
|
||||
foreach (MapEntity e in selectedList)
|
||||
{
|
||||
if (e.Contains(position)) startMovingPos = position;
|
||||
}
|
||||
|
||||
selectionPos = position;
|
||||
Debug.WriteLine("pos");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw the "selection rectangle" and outlines of entities that are being dragged (if any)
|
||||
/// </summary>
|
||||
public static void DrawSelecting(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (GUIComponent.MouseOn != null) return;
|
||||
|
||||
Vector2 position = new Vector2(PlayerInput.GetMouseState.X, PlayerInput.GetMouseState.Y);
|
||||
position = cam.ScreenToWorld(position);
|
||||
|
||||
if (startMovingPos != Vector2.Zero)
|
||||
{
|
||||
Vector2 moveAmount = position - startMovingPos;
|
||||
moveAmount = Map.VectorToWorldGrid(moveAmount);
|
||||
moveAmount.Y = -moveAmount.Y;
|
||||
//started moving the selected entities
|
||||
if (moveAmount != Vector2.Zero)
|
||||
{
|
||||
foreach (MapEntity e in selectedList)
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Vector2(e.rect.X, -e.rect.Y) + moveAmount,
|
||||
new Vector2(e.rect.Width, e.rect.Height),
|
||||
Color.DarkRed);
|
||||
|
||||
//stop dragging the "selection rectangle"
|
||||
selectionPos = Vector2.Zero;
|
||||
}
|
||||
}
|
||||
if (selectionPos != null && selectionPos != Vector2.Zero)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, new Vector2(selectionPos.X, -selectionPos.Y), selectionSize, Color.DarkRed);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call DrawEditing() if only one entity is selected
|
||||
/// </summary>
|
||||
public static void Edit(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
if (selectedList.Count == 1)
|
||||
{
|
||||
selectedList[0].DrawEditing(spriteBatch, cam);
|
||||
}
|
||||
else
|
||||
{
|
||||
editingHUD = null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DrawEditing(SpriteBatch spriteBatch, Camera cam) {}
|
||||
|
||||
public static List<MapEntity> FindMapEntities(Vector2 pos)
|
||||
{
|
||||
List<MapEntity> foundEntities = new List<MapEntity>();
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (Map.RectContains(e.rect, pos)) foundEntities.Add(e);
|
||||
}
|
||||
return foundEntities;
|
||||
}
|
||||
|
||||
public static MapEntity FindMapEntity(Vector2 pos)
|
||||
{
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (Map.RectContains(e.rect, pos)) return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find entities whose rect intersects with the "selection rect"
|
||||
/// </summary>
|
||||
public static List<MapEntity> FindSelectedEntities(Vector2 pos, Vector2 size)
|
||||
{
|
||||
List<MapEntity> foundEntities = new List<MapEntity>();
|
||||
|
||||
Rectangle selectionRect = Map.AbsRect(pos, size);
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (Map.RectsOverlap(selectionRect, e.rect))
|
||||
foundEntities.Add(e);
|
||||
}
|
||||
|
||||
return foundEntities;
|
||||
}
|
||||
|
||||
|
||||
public virtual XElement Save(XDocument doc)
|
||||
{
|
||||
DebugConsole.ThrowError("Saving entity " + this.GetType() + " failed.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the linkedTo-lists of the entities based on the linkedToID-lists
|
||||
/// Has to be done after all the entities have been loaded (an entity can't
|
||||
/// be linked to some other entity that hasn't been loaded yet)
|
||||
/// </summary>
|
||||
public static void LinkAll()
|
||||
{
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (e.linkedToID == null) continue;
|
||||
if (e.linkedToID.Count == 0) continue;
|
||||
|
||||
e.linkedTo.Clear();
|
||||
|
||||
foreach (int i in e.linkedToID)
|
||||
{
|
||||
MapEntity linked = FindEntityByID(i) as MapEntity;
|
||||
|
||||
if (linked != null)
|
||||
e.linkedTo.Add(linked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveLinked(MapEntity e)
|
||||
{
|
||||
if (linkedTo == null) return;
|
||||
if (linkedTo.Contains(e)) linkedTo.Remove(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class MapEntityPrefab
|
||||
{
|
||||
public static List<MapEntityPrefab> list = new List<MapEntityPrefab>();
|
||||
|
||||
protected string name;
|
||||
|
||||
protected bool isLinkable;
|
||||
|
||||
public Sprite sprite;
|
||||
|
||||
//the position where the structure is being placed (needed when stretching the structure)
|
||||
protected static Vector2 placePosition;
|
||||
|
||||
protected ConstructorInfo constructor;
|
||||
|
||||
//is it possible to stretch the entity horizontally/vertically
|
||||
protected bool resizeHorizontal;
|
||||
protected bool resizeVertical;
|
||||
|
||||
|
||||
|
||||
//which prefab has been selected for placing
|
||||
protected static MapEntityPrefab selected;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public static MapEntityPrefab Selected
|
||||
{
|
||||
get { return selected; }
|
||||
}
|
||||
|
||||
public virtual bool IsLinkable
|
||||
{
|
||||
get { return isLinkable; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
MapEntityPrefab ep = new MapEntityPrefab();
|
||||
ep.name = "hull";
|
||||
ep.constructor = typeof(Hull).GetConstructor(new Type[] { typeof(Rectangle) });
|
||||
ep.resizeHorizontal = true;
|
||||
ep.resizeVertical = true;
|
||||
list.Add(ep);
|
||||
|
||||
ep = new MapEntityPrefab();
|
||||
ep.name = "gap";
|
||||
ep.constructor = typeof(Gap).GetConstructor(new Type[] { typeof(Rectangle) });
|
||||
ep.resizeHorizontal = true;
|
||||
ep.resizeVertical = true;
|
||||
list.Add(ep);
|
||||
|
||||
ep = new MapEntityPrefab();
|
||||
ep.name = "waypoint";
|
||||
ep.constructor = typeof(WayPoint).GetConstructor(new Type[] { typeof(Rectangle) });
|
||||
list.Add(ep);
|
||||
}
|
||||
|
||||
|
||||
public virtual void UpdatePlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Vector2 placeSize = Map.gridSize;
|
||||
|
||||
if (placePosition == null || placePosition == Vector2.Zero)
|
||||
{
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed)
|
||||
placePosition = Map.MouseToWorldGrid(cam);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 position = Map.MouseToWorldGrid(cam);
|
||||
|
||||
if (resizeHorizontal) placeSize.X = position.X - placePosition.X;
|
||||
if (resizeVertical) placeSize.Y = placePosition.Y - position.Y;
|
||||
|
||||
Rectangle newRect = Map.AbsRect(placePosition, placeSize);
|
||||
newRect.Width = (int)Math.Max(newRect.Width, Map.gridSize.X);
|
||||
newRect.Height = (int)Math.Max(newRect.Height, Map.gridSize.Y);
|
||||
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Released)
|
||||
{
|
||||
object[] lobject = new object[] { newRect };
|
||||
constructor.Invoke(lobject);
|
||||
placePosition = Vector2.Zero;
|
||||
selected = null;
|
||||
}
|
||||
|
||||
newRect.Y = -newRect.Y;
|
||||
GUI.DrawRectangle(spriteBatch, newRect, Color.DarkBlue);
|
||||
}
|
||||
|
||||
if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed)
|
||||
{
|
||||
placePosition = Vector2.Zero;
|
||||
selected = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static bool SelectPrefab(object selection)
|
||||
{
|
||||
if ((selected = selection as MapEntityPrefab) != null)
|
||||
{
|
||||
placePosition = Vector2.Zero;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//a method that allows the GUIListBoxes to check through a delegate if the entityprefab is still selected
|
||||
public static object GetSelected()
|
||||
{
|
||||
return (object)selected;
|
||||
}
|
||||
|
||||
public void DrawListLine(SpriteBatch spriteBatch, Vector2 pos, Color color)
|
||||
{
|
||||
spriteBatch.DrawString(GUI.font, name, pos, color);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,592 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Factories;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Subsurface.Networking;
|
||||
using Subsurface.Lights;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class WallSection
|
||||
{
|
||||
public Rectangle rect;
|
||||
public float damage;
|
||||
public Gap gap;
|
||||
|
||||
public bool isHighLighted;
|
||||
|
||||
public WallSection(Rectangle rect)
|
||||
{
|
||||
this.rect = rect;
|
||||
damage = 0.0f;
|
||||
}
|
||||
|
||||
public WallSection(Rectangle rect, float damage)
|
||||
{
|
||||
this.rect = rect;
|
||||
this.damage = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
class Structure : MapEntity, IDamageable
|
||||
{
|
||||
static int wallSectionSize = 100;
|
||||
public static List<Structure> wallList = new List<Structure>();
|
||||
|
||||
ConvexHull convexHull;
|
||||
|
||||
StructurePrefab prefab;
|
||||
|
||||
//farseer physics bodies, separated by gaps
|
||||
List<Body> bodies;
|
||||
|
||||
//sections of the wall that are supposed to be rendered
|
||||
private WallSection[] sections;
|
||||
|
||||
bool isHorizontal;
|
||||
|
||||
public override Sprite sprite
|
||||
{
|
||||
get { return prefab.sprite; }
|
||||
}
|
||||
|
||||
public bool IsPlatform
|
||||
{
|
||||
get { return prefab.IsPlatform; }
|
||||
}
|
||||
|
||||
public Direction StairDirection
|
||||
{
|
||||
get { return prefab.StairDirection; }
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "structure"; }
|
||||
}
|
||||
|
||||
public bool HasBody
|
||||
{
|
||||
get { return prefab.HasBody; }
|
||||
}
|
||||
|
||||
public bool IsHorizontal
|
||||
{
|
||||
get { return isHorizontal; }
|
||||
}
|
||||
|
||||
public int SectionCount
|
||||
{
|
||||
get { return sections.Length; }
|
||||
}
|
||||
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
base.Move(amount);
|
||||
|
||||
for (int i = 0; i < sections.Count(); i++)
|
||||
{
|
||||
Rectangle r = sections[i].rect;
|
||||
r.X += (int)amount.X;
|
||||
r.Y += (int)amount.Y;
|
||||
sections[i].rect = r;
|
||||
}
|
||||
|
||||
if (bodies != null)
|
||||
{
|
||||
Vector2 simAmount = ConvertUnits.ToSimUnits(amount);
|
||||
foreach (Body b in bodies)
|
||||
{
|
||||
b.SetTransform(b.Position + simAmount, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (convexHull!=null)
|
||||
{
|
||||
convexHull.Move(amount);
|
||||
}
|
||||
//if (gaps != null)
|
||||
//{
|
||||
// foreach (Gap g in gaps)
|
||||
// {
|
||||
// g.Move(amount);
|
||||
// //g.position.X += amount.X;
|
||||
// //g.position.Y -= amount.Y;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public Structure(Rectangle rectangle, StructurePrefab sp)
|
||||
{
|
||||
if (rectangle.Width == 0 || rectangle.Height == 0) return;
|
||||
|
||||
rect = rectangle;
|
||||
prefab = sp;
|
||||
|
||||
isHorizontal = (rect.Width>rect.Height);
|
||||
|
||||
if (prefab.HasBody)
|
||||
{
|
||||
bodies = new List<Body>();
|
||||
//gaps = new List<Gap>();
|
||||
|
||||
Body newBody = BodyFactory.CreateRectangle(Game1.world,
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
1.5f);
|
||||
newBody.BodyType = BodyType.Static;
|
||||
newBody.Position = ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2.0f, rect.Y - rect.Height / 2.0f));
|
||||
newBody.Friction = 0.5f;
|
||||
|
||||
newBody.OnCollision += OnWallCollision;
|
||||
|
||||
newBody.UserData = this;
|
||||
|
||||
newBody.CollisionCategories = (prefab.IsPlatform) ? Physics.CollisionPlatform : Physics.CollisionWall;
|
||||
|
||||
bodies.Add(newBody);
|
||||
|
||||
wallList.Add(this);
|
||||
|
||||
int xsections = 1;
|
||||
int ysections = 1;
|
||||
int width, height;
|
||||
if (isHorizontal)
|
||||
{
|
||||
xsections = (int)Math.Ceiling((float)rect.Width / wallSectionSize);
|
||||
sections = new WallSection[xsections];
|
||||
width = (int)wallSectionSize;
|
||||
height = rect.Height;
|
||||
}
|
||||
else
|
||||
{
|
||||
ysections = (int)Math.Ceiling((float)rect.Height / wallSectionSize);
|
||||
sections = new WallSection[ysections];
|
||||
width = rect.Width;
|
||||
height = (int)wallSectionSize;
|
||||
}
|
||||
|
||||
for (int x = 0; x < xsections; x++ )
|
||||
{
|
||||
for (int y = 0; y < ysections; y++)
|
||||
{
|
||||
Rectangle sectionRect = new Rectangle(rect.X + x * width, rect.Y - y * height, width, height);
|
||||
sectionRect.Width -= (int)Math.Max((sectionRect.X + sectionRect.Width) - (rect.X + rect.Width), 0.0f);
|
||||
sectionRect.Height -= (int)Math.Max((rect.Y - rect.Height)-(sectionRect.Y - sectionRect.Height), 0.0f);
|
||||
|
||||
sections[x+y] = new WallSection(sectionRect);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sections = new WallSection[1];
|
||||
sections[0] = new WallSection(rect);
|
||||
|
||||
if (StairDirection!=Direction.None)
|
||||
{
|
||||
bodies = new List<Body>();
|
||||
|
||||
Body newBody = BodyFactory.CreateRectangle(Game1.world,
|
||||
ConvertUnits.ToSimUnits(rect.Width * Math.Sqrt(2.0) - Map.gridSize.X),
|
||||
ConvertUnits.ToSimUnits(10),
|
||||
1.5f);
|
||||
|
||||
newBody.BodyType = BodyType.Static;
|
||||
Vector2 stairPos = new Vector2(Position.X, rect.Y - rect.Height + rect.Width / 2.0f);
|
||||
stairPos += new Vector2(
|
||||
(StairDirection == Direction.Right) ? -Map.gridSize.X*1.5f : Map.gridSize.X*1.5f,
|
||||
- Map.gridSize.Y*2.0f);
|
||||
|
||||
|
||||
newBody.Position = ConvertUnits.ToSimUnits(stairPos);
|
||||
newBody.Rotation = (StairDirection == Direction.Right) ? MathHelper.PiOver4 : -MathHelper.PiOver4;
|
||||
newBody.Friction = 0.8f;
|
||||
|
||||
newBody.CollisionCategories = Physics.CollisionStairs;
|
||||
|
||||
newBody.UserData = this;
|
||||
bodies.Add(newBody);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (prefab.CastShadow)
|
||||
{
|
||||
|
||||
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);
|
||||
|
||||
convexHull = new ConvexHull(corners, Color.Black);
|
||||
}
|
||||
|
||||
mapEntityList.Add(this);
|
||||
}
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
base.Remove();
|
||||
|
||||
if (wallList.Contains(this)) wallList.Remove(this);
|
||||
|
||||
if (bodies != null)
|
||||
{
|
||||
foreach (Body b in bodies)
|
||||
Game1.world.RemoveBody(b);
|
||||
}
|
||||
|
||||
if (convexHull != null) convexHull.Remove();
|
||||
}
|
||||
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing)
|
||||
{
|
||||
if (prefab.sprite == null) return;
|
||||
|
||||
Color color = (isHighlighted) ? Color.Green : Color.White;
|
||||
if (isSelected && editing) color = Color.Red;
|
||||
|
||||
prefab.sprite.DrawTiled(spriteBatch, new Vector2(rect.X, -rect.Y), new Vector2(rect.Width, rect.Height), Vector2.Zero, color);
|
||||
|
||||
foreach (WallSection s in sections)
|
||||
{
|
||||
if (s.isHighLighted)
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle((int)s.rect.X, (int)-s.rect.Y, (int)s.rect.Width, (int)s.rect.Height),
|
||||
new Color((s.damage / prefab.MaxHealth), 1.0f - (s.damage / prefab.MaxHealth), 0.0f, 1.0f), true);
|
||||
|
||||
s.isHighLighted = false;
|
||||
|
||||
if (s.damage == 0.0f) continue;
|
||||
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle((int)s.rect.X, (int)-s.rect.Y, (int)s.rect.Width, (int)s.rect.Height),
|
||||
Color.Black * (s.damage / prefab.MaxHealth), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool OnWallCollision(Fixture f1, Fixture f2, Contact contact)
|
||||
{
|
||||
//Structure structure = f1.Body.UserData as Structure;
|
||||
|
||||
//if (f2.Body.UserData as Item != null)
|
||||
//{
|
||||
// if (prefab.IsPlatform || prefab.StairDirection != Direction.None) return false;
|
||||
//}
|
||||
|
||||
if (prefab.IsPlatform)
|
||||
{
|
||||
Limb limb;
|
||||
if ((limb = f2.Body.UserData as Limb) != null)
|
||||
{
|
||||
if (limb.character.animController.IgnorePlatforms) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prefab.IsPlatform && prefab.StairDirection == Direction.None)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(f2.Body.Position);
|
||||
|
||||
int section = FindSectionIndex(pos);
|
||||
if (section>0)
|
||||
{
|
||||
Vector2 normal = contact.Manifold.LocalNormal;
|
||||
|
||||
float impact = Vector2.Dot(f2.Body.LinearVelocity, -normal)*f2.Body.Mass*0.1f;
|
||||
|
||||
if (impact < 10.0f) return true;
|
||||
|
||||
AmbientSoundManager.PlayDamageSound(DamageSoundType.StructureBlunt, impact,
|
||||
new Vector2(
|
||||
sections[section].rect.X + sections[section].rect.Width / 2,
|
||||
sections[section].rect.Y - sections[section].rect.Height / 2));
|
||||
|
||||
AddDamage(section, impact);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void HighLightSection(int sectionIndex)
|
||||
{
|
||||
sections[sectionIndex].isHighLighted = true;
|
||||
}
|
||||
|
||||
public bool SectionHasHole(int sectionIndex)
|
||||
{
|
||||
if (sectionIndex < 0 || sectionIndex >= sections.Length) return false;
|
||||
|
||||
return (sections[sectionIndex].damage>=prefab.MaxHealth);
|
||||
}
|
||||
|
||||
public void AddDamage(int sectionIndex, float damage)
|
||||
{
|
||||
if (!prefab.HasBody || prefab.IsPlatform) return;
|
||||
|
||||
if (Game1.client==null)
|
||||
SetDamage(sectionIndex, sections[sectionIndex].damage + damage);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int FindSectionIndex(Vector2 pos)
|
||||
{
|
||||
int index = (isHorizontal) ?
|
||||
(int)Math.Floor((pos.X - rect.X) / wallSectionSize) :
|
||||
(int)Math.Floor((rect.Y - pos.Y) / wallSectionSize);
|
||||
|
||||
if (index < 0 || index > sections.Length - 1) return -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
public float SectionDamage(int sectionIndex)
|
||||
{
|
||||
if (sectionIndex < 0 || sectionIndex >= sections.Length) return 0.0f;
|
||||
|
||||
return sections[sectionIndex].damage;
|
||||
}
|
||||
|
||||
public Vector2 SectionPosition(int sectionIndex)
|
||||
{
|
||||
if (sectionIndex < 0 || sectionIndex >= sections.Length) return Vector2.Zero;
|
||||
|
||||
return new Vector2(
|
||||
sections[sectionIndex].rect.X + sections[sectionIndex].rect.Width / 2.0f,
|
||||
sections[sectionIndex].rect.Y - sections[sectionIndex].rect.Height / 2.0f);
|
||||
}
|
||||
|
||||
public void AddDamage(Vector2 position, float amount, float bleedingAmount, float stun)
|
||||
{
|
||||
if (!prefab.HasBody || prefab.IsPlatform) return;
|
||||
|
||||
int i = FindSectionIndex(ConvertUnits.ToDisplayUnits(position));
|
||||
if (i == -1) return;
|
||||
|
||||
Game1.particleManager.CreateParticle(ConvertUnits.ToSimUnits(SectionPosition(i)), 0.0f, 0.0f, "dustcloud");
|
||||
|
||||
|
||||
AddDamage(i, amount);
|
||||
}
|
||||
|
||||
private void SetDamage(int sectionIndex, float damage)
|
||||
{
|
||||
if (!prefab.HasBody) return;
|
||||
|
||||
if (damage != sections[sectionIndex].damage)
|
||||
new NetworkEvent(ID, false);
|
||||
|
||||
if (damage < prefab.MaxHealth*0.5f)
|
||||
{
|
||||
if (sections[sectionIndex].gap != null)
|
||||
{
|
||||
//remove existing gap if damage is below 50%
|
||||
sections[sectionIndex].gap.Remove();
|
||||
sections[sectionIndex].gap = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sections[sectionIndex].gap == null)
|
||||
{
|
||||
sections[sectionIndex].gap = new Gap(sections[sectionIndex].rect, !isHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
if (sections[sectionIndex].gap != null)
|
||||
sections[sectionIndex].gap.Open = (float)Math.Pow(((damage / prefab.MaxHealth)-0.5)*2.0, 2.0);
|
||||
|
||||
bool hadHole = SectionHasHole(sectionIndex);
|
||||
sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, prefab.MaxHealth);
|
||||
|
||||
bool hasHole = SectionHasHole(sectionIndex);
|
||||
|
||||
if (hadHole != hasHole) UpdateSections();
|
||||
|
||||
}
|
||||
|
||||
private void UpdateSections()
|
||||
{
|
||||
foreach (Body b in bodies)
|
||||
{
|
||||
Game1.world.RemoveBody(b);
|
||||
}
|
||||
bodies.Clear();
|
||||
|
||||
int x = sections[0].rect.X;
|
||||
int y = sections[0].rect.Y;
|
||||
int width = sections[0].rect.Width;
|
||||
int height = sections[0].rect.Height;
|
||||
|
||||
bool hasHoles = false;
|
||||
|
||||
for (int i = 1; i < sections.Length; i++)
|
||||
{
|
||||
bool hasHole = SectionHasHole(i);
|
||||
if (hasHole) hasHoles = true;
|
||||
if (hasHole || i == sections.Length - 1)
|
||||
{
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
CreateRectBody(new Rectangle(x, y, width, height));
|
||||
}
|
||||
if (isHorizontal)
|
||||
{
|
||||
x = sections[i].rect.X+ sections[i].rect.Width;
|
||||
width = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = sections[i].rect.Y - sections[i].rect.Height;
|
||||
height = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
width += sections[i].rect.Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
height += sections[i].rect.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasHoles)
|
||||
{
|
||||
CreateRectBody(rect).IsSensor = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Body CreateRectBody(Rectangle rect)
|
||||
{
|
||||
Body newBody = BodyFactory.CreateRectangle(Game1.world,
|
||||
ConvertUnits.ToSimUnits(rect.Width),
|
||||
ConvertUnits.ToSimUnits(rect.Height),
|
||||
1.5f);
|
||||
newBody.BodyType = BodyType.Static;
|
||||
newBody.Position = ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width / 2.0f, rect.Y - rect.Height / 2.0f));
|
||||
newBody.Friction = 0.5f;
|
||||
|
||||
newBody.OnCollision += OnWallCollision;
|
||||
|
||||
newBody.CollisionCategories = Physics.CollisionWall;
|
||||
|
||||
newBody.UserData = this;
|
||||
|
||||
bodies.Add(newBody);
|
||||
|
||||
return newBody;
|
||||
}
|
||||
|
||||
|
||||
public override XElement Save(XDocument doc)
|
||||
{
|
||||
XElement element = new XElement("Structure");
|
||||
|
||||
element.Add(new XAttribute("name", prefab.Name),
|
||||
new XAttribute("ID", ID),
|
||||
new XAttribute("rect", rect.X + "," + rect.Y+","+rect.Width+","+rect.Height));
|
||||
|
||||
for (int i = 0; i < sections.Count(); i++)
|
||||
{
|
||||
if (sections[i].damage == 0.0f) continue;
|
||||
|
||||
element.Add(new XElement("section",
|
||||
new XAttribute("i", i),
|
||||
new XAttribute("damage", sections[i].damage)));
|
||||
}
|
||||
|
||||
doc.Root.Add(element);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static void Load(XElement element)
|
||||
{
|
||||
string rectString = ToolBox.GetAttributeString(element, "rect", "0,0,0,0");
|
||||
string[] rectValues = rectString.Split(',');
|
||||
|
||||
Rectangle rect = new Rectangle(
|
||||
int.Parse(rectValues[0]),
|
||||
int.Parse(rectValues[1]),
|
||||
int.Parse(rectValues[2]),
|
||||
int.Parse(rectValues[3]));
|
||||
|
||||
string name = element.Attribute("name").Value;
|
||||
|
||||
Debug.WriteLine(name+" - "+rect);
|
||||
|
||||
Structure s = null;
|
||||
|
||||
foreach (MapEntityPrefab ep in MapEntityPrefab.list)
|
||||
{
|
||||
if (ep.Name == name)
|
||||
{
|
||||
s = new Structure(rect, (StructurePrefab)ep);
|
||||
s.ID = int.Parse(element.Attribute("ID").Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Structure prefab " + name + " not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString())
|
||||
{
|
||||
case "section":
|
||||
if (subElement.Attribute("i") == null) continue;
|
||||
|
||||
s.sections[int.Parse(subElement.Attribute("i").Value)].damage =
|
||||
ToolBox.GetAttributeFloat(subElement, "damage", 0.0f);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data)
|
||||
{
|
||||
for (int i = 0; i < sections.Length; i++ )
|
||||
{
|
||||
message.Write(sections[i].damage);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message)
|
||||
{
|
||||
for (int i = 0; i < sections.Length; i++)
|
||||
{
|
||||
float damage = message.ReadFloat();
|
||||
if (damage != sections[i].damage) SetDamage(i, damage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class StructurePrefab : MapEntityPrefab
|
||||
{
|
||||
//public static List<StructurePrefab> list = new List<StructurePrefab>();
|
||||
|
||||
//does the structure have a physics body
|
||||
bool hasBody;
|
||||
|
||||
bool castShadow;
|
||||
|
||||
bool isPlatform;
|
||||
Direction stairDirection;
|
||||
|
||||
float maxHealth;
|
||||
|
||||
//default size
|
||||
Vector2 size;
|
||||
|
||||
public bool HasBody
|
||||
{
|
||||
get { return hasBody; }
|
||||
}
|
||||
|
||||
public bool IsPlatform
|
||||
{
|
||||
get { return isPlatform; }
|
||||
}
|
||||
|
||||
public float MaxHealth
|
||||
{
|
||||
get { return maxHealth; }
|
||||
}
|
||||
|
||||
public bool CastShadow
|
||||
{
|
||||
get { return castShadow; }
|
||||
}
|
||||
|
||||
public Direction StairDirection
|
||||
{
|
||||
get { return stairDirection; }
|
||||
}
|
||||
|
||||
public static void LoadAll(string filePath)
|
||||
{
|
||||
XDocument doc = ToolBox.TryLoadXml(filePath);
|
||||
if (doc == null) return;
|
||||
|
||||
foreach (XElement el in doc.Root.Elements())
|
||||
{
|
||||
StructurePrefab sp = Load(el);
|
||||
|
||||
Debug.WriteLine(sp.name);
|
||||
|
||||
list.Add(sp);
|
||||
}
|
||||
}
|
||||
|
||||
public static StructurePrefab Load(XElement el)
|
||||
{
|
||||
StructurePrefab sp = new StructurePrefab();
|
||||
sp.name = el.Name.ToString();
|
||||
|
||||
Vector4 sourceVector = ToolBox.GetAttributeVector4(el, "sourcerect", new Vector4(0,0,1,1));
|
||||
|
||||
Rectangle sourceRect = new Rectangle(
|
||||
(int)sourceVector.X,
|
||||
(int)sourceVector.Y,
|
||||
(int)sourceVector.Z,
|
||||
(int)sourceVector.W);
|
||||
|
||||
if (el.Attribute("sprite") != null)
|
||||
{
|
||||
sp.sprite = new Sprite(el.Attribute("sprite").Value, sourceRect, Vector2.Zero);
|
||||
|
||||
sp.sprite.Depth = ToolBox.GetAttributeFloat(el, "depth", 0.0f);
|
||||
|
||||
if (ToolBox.GetAttributeBool(el, "fliphorizontal", false)) sp.sprite.effects = SpriteEffects.FlipHorizontally;
|
||||
if (ToolBox.GetAttributeBool(el, "flipvertical", false)) sp.sprite.effects = SpriteEffects.FlipVertically;
|
||||
}
|
||||
|
||||
sp.size = Vector2.Zero;
|
||||
sp.size.X = ToolBox.GetAttributeFloat(el, "width", 0.0f);
|
||||
sp.size.Y = ToolBox.GetAttributeFloat(el, "height", 0.0f);
|
||||
|
||||
sp.maxHealth = ToolBox.GetAttributeFloat(el, "health", 100.0f);
|
||||
|
||||
sp.resizeHorizontal = ToolBox.GetAttributeBool(el, "resizehorizontal", false);
|
||||
sp.resizeVertical = ToolBox.GetAttributeBool(el, "resizevertical", false);
|
||||
|
||||
sp.isPlatform = ToolBox.GetAttributeBool(el, "platform", false);
|
||||
sp.stairDirection = (Direction)Enum.Parse(typeof(Direction), ToolBox.GetAttributeString(el, "stairdirection", "None"));
|
||||
|
||||
sp.castShadow = ToolBox.GetAttributeBool(el, "castshadow", false);
|
||||
|
||||
|
||||
sp.hasBody = ToolBox.GetAttributeBool(el, "body", false);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
public override void UpdatePlacing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
Vector2 position = Map.MouseToWorldGrid(cam);
|
||||
//Vector2 placeSize = size;
|
||||
|
||||
Rectangle newRect = new Rectangle((int)position.X, (int)position.Y, (int)size.X, (int)size.Y);
|
||||
|
||||
|
||||
if (placePosition == Vector2.Zero)
|
||||
{
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Pressed)
|
||||
placePosition = Map.MouseToWorldGrid(cam);
|
||||
|
||||
newRect.X = (int)position.X;
|
||||
newRect.Y = (int)position.Y;
|
||||
|
||||
//sprite.Draw(spriteBatch, new Vector2(position.X, -position.Y), placeSize, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 placeSize = size;
|
||||
if (resizeHorizontal) placeSize.X = position.X - placePosition.X;
|
||||
if (resizeVertical) placeSize.Y = placePosition.Y - position.Y;
|
||||
|
||||
newRect = Map.AbsRect(placePosition, placeSize);
|
||||
|
||||
//newRect.Width = (int)Math.Max(newRect.Width, Map.gridSize.X);
|
||||
//newRect.Height = (int)Math.Max(newRect.Height, Map.gridSize.Y);
|
||||
|
||||
if (PlayerInput.GetMouseState.LeftButton == ButtonState.Released)
|
||||
{
|
||||
new Structure(newRect, this);
|
||||
selected = null;
|
||||
return;
|
||||
}
|
||||
|
||||
//position = placePosition;
|
||||
}
|
||||
|
||||
sprite.DrawTiled(spriteBatch, new Vector2(newRect.X, -newRect.Y), new Vector2(newRect.Width, newRect.Height), Color.White);
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(newRect.X - Game1.GraphicsWidth, -newRect.Y, newRect.Width + Game1.GraphicsWidth*2, newRect.Height), Color.White);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(newRect.X, -newRect.Y - Game1.GraphicsHeight, newRect.Width, newRect.Height + Game1.GraphicsHeight*2), Color.White);
|
||||
|
||||
if (PlayerInput.GetMouseState.RightButton == ButtonState.Pressed) selected = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
struct WaterVertex
|
||||
{
|
||||
public Vector3 position;
|
||||
private Vector2 texCoord;
|
||||
|
||||
public WaterVertex(Vector3 position, Vector2 texCoord, Matrix transform)
|
||||
{
|
||||
this.position = position;
|
||||
|
||||
this.texCoord = Vector2.Transform(texCoord, transform);
|
||||
}
|
||||
|
||||
public WaterVertex(Vector3 position, Vector2 texCoord)
|
||||
{
|
||||
this.position = position;
|
||||
|
||||
this.texCoord = texCoord;
|
||||
}
|
||||
|
||||
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
|
||||
(
|
||||
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
|
||||
new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
|
||||
);
|
||||
|
||||
public void TransformTexCoord(Matrix transform)
|
||||
{
|
||||
this.texCoord = Vector2.Transform(this.texCoord, transform);
|
||||
}
|
||||
}
|
||||
|
||||
class WaterRenderer : IDisposable
|
||||
{
|
||||
const int DefaultBufferSize = 1500;
|
||||
|
||||
Effect effect;
|
||||
|
||||
Vector2 wavePos;
|
||||
|
||||
public WaterVertex[] vertices = new WaterVertex[DefaultBufferSize];
|
||||
|
||||
private VertexBuffer vertexBuffer;
|
||||
|
||||
public int positionInBuffer = 0;
|
||||
|
||||
public WaterRenderer(GraphicsDevice graphicsDevice)
|
||||
{
|
||||
//vertexBuffer = new VertexBuffer(graphicsDevice, WaterVertex.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
|
||||
//vertexBuffer.SetData(vertices);
|
||||
|
||||
//effect = Game1.game.Content.Load<Effect>("effects");
|
||||
|
||||
byte[] bytecode = File.ReadAllBytes("Content/effects.mgfx");
|
||||
effect = new Effect(graphicsDevice, bytecode);
|
||||
|
||||
//Texture2D waterBumpMap = Game1.textureLoader.FromFile("Content/waterbump.jpg");
|
||||
//effect.Parameters["xBump"].SetValue(waterBumpMap);
|
||||
//effect.Parameters["xWaveLength"].SetValue(0.5f);
|
||||
//effect.Parameters["xWaveHeight"].SetValue(0.03f);
|
||||
effect.Parameters["xProjection"].SetValue(Matrix.CreateOrthographic(Game1.GraphicsWidth, Game1.GraphicsHeight, -1, 1));
|
||||
effect.Parameters["xColor"].SetValue(new Vector4(0.75f, 0.8f, 0.9f, 1.0f));
|
||||
effect.Parameters["xBlurDistance"].SetValue(0.0005f);
|
||||
|
||||
effect.Parameters["xWaterBumpMap"].SetValue(Game1.textureLoader.FromFile("Content/waterbump.jpg"));
|
||||
effect.Parameters["xWaveWidth"].SetValue(0.1f);
|
||||
effect.Parameters["xWaveHeight"].SetValue(0.1f);
|
||||
|
||||
vertexBuffer = new VertexBuffer(graphicsDevice, WaterVertex.VertexDeclaration, DefaultBufferSize, BufferUsage.WriteOnly);
|
||||
}
|
||||
|
||||
public void RenderBack(GraphicsDevice graphicsDevice, RenderTarget2D texture, Matrix transform)
|
||||
{
|
||||
WaterVertex[] verts = new WaterVertex[6];
|
||||
|
||||
// create the four corners of our triangle.
|
||||
Vector3 p1 = new Vector3(-graphicsDevice.Viewport.Width / 2.0f, graphicsDevice.Viewport.Height / 2.0f, 0.0f);
|
||||
Vector3 p2 = new Vector3(-p1.X, p1.Y, 0.0f);
|
||||
|
||||
Vector3 p3 = new Vector3(p2.X, -p1.Y, 0.0f);
|
||||
Vector3 p4 = new Vector3(p1.X, -p1.Y, 0.0f);
|
||||
|
||||
verts[0] = new WaterVertex(p1, new Vector2(0, 0));
|
||||
verts[1] = new WaterVertex(p2, new Vector2(1, 0));
|
||||
verts[2] = new WaterVertex(p3, new Vector2(1, 1));
|
||||
|
||||
verts[3] = new WaterVertex(p1, new Vector2(0, 0));
|
||||
verts[4] = new WaterVertex(p3, new Vector2(1, 1));
|
||||
verts[5] = new WaterVertex(p4, new Vector2(0, 1));
|
||||
|
||||
vertexBuffer.SetData(verts);
|
||||
|
||||
effect.CurrentTechnique = effect.Techniques["WaterShader"];
|
||||
effect.Parameters["xTexture"].SetValue(texture);
|
||||
effect.Parameters["xView"].SetValue(Matrix.Identity);
|
||||
|
||||
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
|
||||
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, verts, 0, verts.Length / 3, WaterVertex.VertexDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
public void Render(GraphicsDevice graphicsDevice, Camera cam, RenderTarget2D texture, Matrix transform)
|
||||
{
|
||||
if (vertices == null) return;
|
||||
if (vertices.Length < 0) return;
|
||||
|
||||
vertexBuffer.SetData(vertices);
|
||||
|
||||
wavePos.X += 0.0001f;
|
||||
wavePos.Y += 0.0001f;
|
||||
|
||||
effect.Parameters["xBumpPos"].SetValue(cam.Position/Game1.GraphicsWidth/cam.Zoom);
|
||||
effect.Parameters["xWavePos"].SetValue(wavePos);
|
||||
|
||||
effect.CurrentTechnique = effect.Techniques["EmptyShader"];
|
||||
effect.Parameters["xTexture"].SetValue(texture);
|
||||
effect.Parameters["xView"].SetValue(transform);
|
||||
|
||||
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
|
||||
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, vertices, 0, vertices.Length / 3, WaterVertex.VertexDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (vertexBuffer != null)
|
||||
{
|
||||
vertexBuffer.Dispose();
|
||||
vertexBuffer = null;
|
||||
}
|
||||
|
||||
if (effect != null)
|
||||
{
|
||||
effect.Dispose();
|
||||
effect = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Subsurface
|
||||
{
|
||||
class WayPoint : MapEntity
|
||||
{
|
||||
public enum SpawnType { None, Human, Enemy };
|
||||
|
||||
private SpawnType spawnType;
|
||||
|
||||
public override Vector2 SimPosition
|
||||
{
|
||||
get { return ConvertUnits.ToSimUnits(new Vector2(rect.X, rect.Y)); }
|
||||
}
|
||||
|
||||
public WayPoint(Rectangle newRect)
|
||||
{
|
||||
rect = newRect;
|
||||
linkedTo = new ObservableCollection<MapEntity>();
|
||||
|
||||
mapEntityList.Add(this);
|
||||
}
|
||||
|
||||
public override void Draw(SpriteBatch spriteBatch, bool editing)
|
||||
{
|
||||
if (!editing) return;
|
||||
|
||||
Color clr = (isSelected) ? Color.Red : Color.LightGreen;
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, -rect.Y, rect.Width, rect.Height), clr, true);
|
||||
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
GUI.DrawLine(spriteBatch,
|
||||
new Vector2(rect.X + rect.Width / 2, -rect.Y + rect.Height / 2),
|
||||
new Vector2(e.Rect.X + e.Rect.Width / 2, -e.Rect.Y + e.Rect.Height / 2),
|
||||
Color.Green);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawEditing(SpriteBatch spriteBatch, Camera cam)
|
||||
{
|
||||
int x = 300, y = 10;
|
||||
|
||||
spriteBatch.DrawString(GUI.font, "Editing waypoint", new Vector2(x, y), Color.Black);
|
||||
spriteBatch.DrawString(GUI.font, "Hold space to link to another entity", new Vector2(x, y + 20), Color.Black);
|
||||
spriteBatch.DrawString(GUI.font, "Spawnpoint: "+spawnType.ToString()+" +/-", new Vector2(x, y + 40), Color.Black);
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Add)) spawnType += 1;
|
||||
if (PlayerInput.KeyHit(Keys.Subtract)) spawnType -= 1;
|
||||
|
||||
if (spawnType > SpawnType.Enemy) spawnType = SpawnType.None;
|
||||
if (spawnType < SpawnType.None) spawnType = SpawnType.Enemy;
|
||||
|
||||
if (!PlayerInput.LeftButtonClicked()) return;
|
||||
|
||||
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
if (e.GetType()!=typeof(WayPoint)) continue;
|
||||
if (e == this) continue;
|
||||
|
||||
if (!Map.RectContains(e.Rect, position)) continue;
|
||||
|
||||
linkedTo.Add(e);
|
||||
e.linkedTo.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static WayPoint GetRandom(SpawnType spawnType = SpawnType.None)
|
||||
{
|
||||
List<WayPoint> wayPoints = new List<WayPoint>();
|
||||
|
||||
foreach (MapEntity e in mapEntityList)
|
||||
{
|
||||
WayPoint wayPoint = e as WayPoint;
|
||||
if (wayPoint==null) continue;
|
||||
|
||||
if (spawnType != SpawnType.None && wayPoint.spawnType != spawnType) continue;
|
||||
|
||||
wayPoints.Add(wayPoint);
|
||||
}
|
||||
|
||||
if (wayPoints.Count() == 0) return null;
|
||||
|
||||
return wayPoints[Game1.random.Next(wayPoints.Count())];
|
||||
}
|
||||
|
||||
public override XElement Save(XDocument doc)
|
||||
{
|
||||
XElement element = new XElement("WayPoint");
|
||||
|
||||
element.Add(new XAttribute("ID", ID),
|
||||
new XAttribute("x", rect.X),
|
||||
new XAttribute("y", rect.Y),
|
||||
new XAttribute("spawn", spawnType));
|
||||
|
||||
doc.Root.Add(element);
|
||||
|
||||
if (linkedTo != null)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (MapEntity e in linkedTo)
|
||||
{
|
||||
element.Add(new XAttribute("linkedto" + i, e.ID));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public static void Load(XElement element)
|
||||
{
|
||||
Rectangle rect = new Rectangle(
|
||||
int.Parse(element.Attribute("x").Value),
|
||||
int.Parse(element.Attribute("y").Value),
|
||||
(int)Map.gridSize.X, (int)Map.gridSize.Y);
|
||||
|
||||
WayPoint w = new WayPoint(rect);
|
||||
|
||||
w.ID = int.Parse(element.Attribute("ID").Value);
|
||||
w.spawnType = (SpawnType)Enum.Parse(typeof(SpawnType),
|
||||
ToolBox.GetAttributeString(element, "spawn", "None"));
|
||||
|
||||
w.linkedToID = new List<int>();
|
||||
int i = 0;
|
||||
while (element.Attribute("linkedto" + i) != null)
|
||||
{
|
||||
w.linkedToID.Add(int.Parse(element.Attribute("linkedto" + i).Value));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user