more accurate submarine body generation, multiplayer fixes, saving takes HiddenSubPosition into account, fire coordinate fixes, editscreen fixes, checking item triggers in AIObjectiveGoto, netlobbyscreen sync fixes, re-enabled level start/end positions, water edit fixed

This commit is contained in:
Regalis
2015-12-17 18:26:40 +02:00
parent 859be53d28
commit af470eab2e
53 changed files with 1065 additions and 427 deletions

View File

@@ -16,12 +16,14 @@ namespace Barotrauma
private int basicSoundIndex, largeSoundIndex;
Hull hull;
private Hull hull;
LightSource lightSource;
private LightSource lightSource;
Vector2 position;
Vector2 size;
private Vector2 position;
private Vector2 size;
private Entity Submarine;
public Vector2 Position
{
@@ -34,6 +36,11 @@ namespace Barotrauma
}
}
public Vector2 WorldPosition
{
get { return Submarine.Position + position; }
}
public Vector2 Size
{
get { return size; }
@@ -50,11 +57,16 @@ namespace Barotrauma
fireSoundLarge = Sound.Load("Content/Sounds/firelarge.ogg");
}
lightSource = new LightSource(worldPosition, 50.0f, new Color(1.0f, 0.9f, 0.6f), hull == null ? null : hull.Submarine);
hull.AddFireSource(this, !networkEvent);
this.position = worldPosition - new Vector2(-5.0f, 5.0f);
Submarine = hull.Submarine;
this.position = worldPosition - new Vector2(-5.0f, 5.0f) - Submarine.Position;
lightSource = new LightSource(this.position, 50.0f, new Color(1.0f, 0.9f, 0.7f), hull == null ? null : hull.Submarine);
//this.position.Y = hull.Rect.Y - hull.Rect.Height;
@@ -136,9 +148,9 @@ namespace Barotrauma
{
float normalizedPos = 0.5f-(i / count);
Vector2 spawnPos = new Vector2(position.X + Rand.Range(0.0f, size.X), Rand.Range(position.Y - size.Y, position.Y)+10.0f);
Vector2 spawnPos = new Vector2(WorldPosition.X + Rand.Range(0.0f, size.X), Rand.Range(WorldPosition.Y - size.Y, WorldPosition.Y) + 10.0f);
Vector2 speed = new Vector2((spawnPos.X - (position.X + size.X/2.0f)), (float)Math.Sqrt(size.X)*Rand.Range(10.0f,15.0f)*growModifier);
Vector2 speed = new Vector2((spawnPos.X - (WorldPosition.X + size.X / 2.0f)), (float)Math.Sqrt(size.X) * Rand.Range(10.0f, 15.0f) * growModifier);
var particle = GameMain.ParticleManager.CreateParticle("flame",
spawnPos, speed, 0.0f, hull);
@@ -265,8 +277,8 @@ namespace Barotrauma
{
float range = 100.0f;
if (pos.X < position.X-range || pos.X > position.X + size.X+range) return;
if (pos.Y < position.Y - size.Y || pos.Y > position.Y + 500.0f) return;
if (pos.X < WorldPosition.X - range || pos.X > WorldPosition.X + size.X + range) return;
if (pos.Y < WorldPosition.Y - size.Y || pos.Y > WorldPosition.Y + 500.0f) return;
float extinquishAmount = amount * deltaTime;

View File

@@ -79,6 +79,13 @@ namespace Barotrauma
InsertToList();
}
public override void Move(Vector2 amount)
{
base.Move(amount);
FindHulls();
}
public static void UpdateHulls()
{
foreach (Gap g in Gap.GapList)
@@ -119,7 +126,7 @@ namespace Barotrauma
if (hulls[0] == null && hulls[1] == null) return;
if (hulls[0]!=null && hulls[1]!=null)
if (hulls[0] != null && hulls[1] != null)
{
if ((isHorizontal && hulls[0].Rect.X > hulls[1].Rect.X) || (!isHorizontal && hulls[0].Rect.Y < hulls[1].Rect.Y))
{
@@ -537,15 +544,21 @@ namespace Barotrauma
if (soundIndex > -1) Sounds.SoundManager.Stop(soundIndex);
}
public override void OnMapLoaded()
{
UpdateHulls();
}
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));
element.Add(new XAttribute("ID", ID));
element.Add(new XAttribute("rect",
(int)(rect.X - Submarine.HiddenSubPosition.X) + "," +
(int)(rect.Y - Submarine.HiddenSubPosition.Y) + "," +
rect.Width + "," + rect.Height));
//if (linkedTo != null)
//{
@@ -566,11 +579,27 @@ namespace Barotrauma
public static void Load(XElement element, Submarine submarine)
{
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));
Rectangle rect = Rectangle.Empty;
if (element.Attribute("rect") != null)
{
string rectString = ToolBox.GetAttributeString(element, "rect", "0,0,0,0");
string[] rectValues = rectString.Split(',');
rect = new Rectangle(
int.Parse(rectValues[0]),
int.Parse(rectValues[1]),
int.Parse(rectValues[2]),
int.Parse(rectValues[3]));
}
else
{
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, submarine);
g.ID = (ushort)int.Parse(element.Attribute("ID").Value);

View File

@@ -229,11 +229,11 @@ namespace Barotrauma
if (EditWater)
{
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
if (Submarine.RectContains(rect, position))
if (Submarine.RectContains(WorldRect, position))
{
if (PlayerInput.LeftButtonDown())
{
waveY[(int)(position.X - rect.X) / WaveWidth] = 100.0f;
//waveY[GetWaveIndex(position.X - rect.X - Submarine.Position.X) / WaveWidth] = 100.0f;
Volume = Volume + 1500.0f;
}
else if (PlayerInput.RightButtonDown())
@@ -245,7 +245,7 @@ namespace Barotrauma
else if (EditFire)
{
Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition);
if (Submarine.RectContains(rect, position))
if (Submarine.RectContains(WorldRect, position))
{
if (PlayerInput.LeftButtonClicked())
{
@@ -524,12 +524,15 @@ namespace Barotrauma
{
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));
element.Add
(
new XAttribute("ID", ID),
new XAttribute("rect",
(int)(rect.X - Submarine.HiddenSubPosition.X) + "," +
(int)(rect.Y - Submarine.HiddenSubPosition.Y) + "," +
rect.Width + "," + rect.Height),
new XAttribute("water", volume)
);
doc.Root.Add(element);
@@ -538,11 +541,27 @@ namespace Barotrauma
public static void Load(XElement element, Submarine submarine)
{
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));
Rectangle rect = Rectangle.Empty;
if (element.Attribute("rect") != null)
{
string rectString = ToolBox.GetAttributeString(element, "rect", "0,0,0,0");
string[] rectValues = rectString.Split(',');
rect = new Rectangle(
int.Parse(rectValues[0]),
int.Parse(rectValues[1]),
int.Parse(rectValues[2]),
int.Parse(rectValues[3]));
}
else
{
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, submarine);

View File

@@ -25,7 +25,7 @@ namespace Barotrauma
private LevelRenderer renderer;
//how close the sub has to be to start/endposition to exit
const float ExitDistance = 6000.0f;
public const float ExitDistance = 6000.0f;
private string seed;
@@ -56,12 +56,6 @@ namespace Barotrauma
get { return startPosition; }
}
public bool AtStartPosition
{
get;
private set;
}
public Vector2 Size
{
get { return new Vector2(borders.Width, borders.Height); }
@@ -71,13 +65,7 @@ namespace Barotrauma
{
get { return endPosition; }
}
public bool AtEndPosition
{
get;
private set;
}
public List<Vector2> PositionsOfInterest
{
get { return positionsOfInterest; }
@@ -380,6 +368,8 @@ namespace Barotrauma
endPosition = temp;
}
renderer.PlaceSprites(100);
Debug.WriteLine("**********************************************************************************");
Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
Debug.WriteLine("Seed: "+seed);
@@ -967,7 +957,7 @@ namespace Barotrauma
renderer.Draw(spriteBatch);
}
public void DrawBack(SpriteBatch spriteBatch, Camera cam, BackgroundSpriteManager backgroundSpriteManager = null)
public void DrawBack(SpriteBatch spriteBatch, Camera cam, BackgroundCreatureManager backgroundSpriteManager = null)
{
if (renderer == null) return;
renderer.DrawBackground(spriteBatch, cam, backgroundSpriteManager);

View File

@@ -16,6 +16,8 @@ namespace Barotrauma
private static Texture2D dustParticles;
private static Texture2D shaftTexture;
private static BackgroundSpriteManager backgroundSpriteManager;
Vector2 dustOffset;
private Level level;
@@ -43,16 +45,25 @@ namespace Barotrauma
basicEffect.Texture = TextureLoader.FromFile("Content/Map/iceWall.png");
}
if (backgroundSpriteManager==null)
{
backgroundSpriteManager = new BackgroundSpriteManager("Content/BackgroundSprites/BackgroundSpritePrefabs.xml");
}
this.level = level;
}
public void PlaceSprites(int amount)
{
backgroundSpriteManager.PlaceSprites(level, amount);
}
public void Update(float deltaTime)
{
dustOffset -= Vector2.UnitY * 10.0f * (float)deltaTime;
}
public void DrawBackground(SpriteBatch spriteBatch, Camera cam, BackgroundSpriteManager backgroundSpriteManager = null)
public void DrawBackground(SpriteBatch spriteBatch, Camera cam, BackgroundCreatureManager backgroundCreatureManager = null)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap);
@@ -87,7 +98,9 @@ namespace Barotrauma
SamplerState.LinearWrap, DepthStencilState.Default, null, null,
cam.Transform);
if (backgroundSpriteManager!=null) backgroundSpriteManager.Draw(spriteBatch);
backgroundSpriteManager.DrawSprites(spriteBatch);
if (backgroundCreatureManager!=null) backgroundCreatureManager.Draw(spriteBatch);
spriteBatch.End();
@@ -118,12 +131,10 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch)
{
Vector2 pos = new Vector2(0.0f, -level.StartPosition.Y);// level.EndPosition;
//pos.Y = -pos.Y - level.Position.Y;
if (GameMain.GameScreen.Cam.WorldView.Y < -pos.Y - 512) return;
pos.X = GameMain.GameScreen.Cam.WorldView.X -512.0f;
//pos.X += Position.X % 512;
int width = (int)(Math.Ceiling(GameMain.GameScreen.Cam.WorldView.Width / 512.0f + 2.0f) * 512.0f);

View File

@@ -236,8 +236,6 @@ namespace Barotrauma
/// </summary>
public static void UpdateSelecting(Camera cam)
{
if (GUIComponent.MouseOn != null) return;
if (DisableSelect)
{
DisableSelect = false;
@@ -250,6 +248,10 @@ namespace Barotrauma
e.isSelected = false;
}
if (GUIComponent.MouseOn != null) return;
if (MapEntityPrefab.Selected != null)
{
selectionPos = Vector2.Zero;
@@ -278,8 +280,7 @@ namespace Barotrauma
e.isSelected = false;
}
if (highLightedEntity != null)
highLightedEntity.isHighlighted = true;
if (highLightedEntity != null) highLightedEntity.isHighlighted = true;
foreach (MapEntity e in selectedList)
{
@@ -304,7 +305,6 @@ namespace Barotrauma
startMovingPos = Vector2.Zero;
}
}
//started dragging a "selection rectangle"
else if (selectionPos != Vector2.Zero)
@@ -397,7 +397,7 @@ namespace Barotrauma
{
foreach (MapEntity e in selectedList)
GUI.DrawRectangle(spriteBatch,
new Vector2(e.rect.X, -e.rect.Y) + moveAmount,
new Vector2(e.WorldRect.X, -e.WorldRect.Y) + moveAmount,
new Vector2(e.rect.Width, e.rect.Height),
Color.DarkRed);
@@ -502,8 +502,7 @@ namespace Barotrauma
{
MapEntity linked = FindEntityByID(i) as MapEntity;
if (linked != null)
e.linkedTo.Add(linked);
if (linked != null) e.linkedTo.Add(linked);
}
}

View File

@@ -289,7 +289,7 @@ namespace Barotrauma
{
if (prefab.sprite == null) return;
Color color = (isHighlighted) ? Color.Green : Color.White;
Color color = (isHighlighted) ? Color.Orange : Color.White;
if (isSelected && editing) color = Color.Red;
Vector2 drawOffset = Submarine == null ? Vector2.Zero : Submarine.DrawPosition;
@@ -583,8 +583,11 @@ namespace Barotrauma
element.Add(new XAttribute("name", prefab.Name),
new XAttribute("ID", ID),
new XAttribute("rect", rect.X + "," + rect.Y+","+rect.Width+","+rect.Height));
new XAttribute("rect",
(int)(rect.X - Submarine.HiddenSubPosition.X) + "," +
(int)(rect.Y - Submarine.HiddenSubPosition.Y) + "," +
rect.Width + "," + rect.Height));
for (int i = 0; i < sections.Count(); i++)
{
if (sections[i].damage == 0.0f) continue;

View File

@@ -104,6 +104,24 @@ namespace Barotrauma
get { return subBody==null ? Vector2.Zero : subBody.Position - HiddenSubPosition; }
}
public bool AtEndPosition
{
get
{
if (Level.Loaded == null) return false;
return (Vector2.Distance(Position + HiddenSubPosition, Level.Loaded.EndPosition) < Level.ExitDistance);
}
}
public bool AtStartPosition
{
get
{
if (Level.Loaded == null) return false;
return (Vector2.Distance(Position + HiddenSubPosition, Level.Loaded.StartPosition) < Level.ExitDistance);
}
}
public new Vector2 DrawPosition
{
get;
@@ -283,6 +301,8 @@ namespace Barotrauma
public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List<Body> ignoredBodies = null, Category? collisionCategory = null)
{
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.0f) return null;
float closestFraction = 1.0f;
Body closestBody = null;
GameMain.World.RayCast((fixture, point, normal, fraction) =>
@@ -397,8 +417,8 @@ namespace Barotrauma
{
if (subBody == null) return false;
message.Write(Position.X);
message.Write(Position.Y);
message.Write(subBody.Position.X);
message.Write(subBody.Position.Y);
message.Write(Velocity.X);
message.Write(Velocity.Y);

View File

@@ -15,7 +15,7 @@ namespace Barotrauma
{
class SubmarineBody
{
public const float DamageDepth = -10000.0f;
public const float DamageDepth = -30000.0f;
const float PressureDamageMultiplier = 0.001f;
//structure damage = impact * damageMultiplier
@@ -115,7 +115,27 @@ namespace Barotrauma
foreach (Hull hull in Hull.hullList)
{
FixtureFactory.AttachRectangle(ConvertUnits.ToSimUnits(hull.Rect.Width), ConvertUnits.ToSimUnits(hull.Rect.Height), 5.0f, hull.SimPosition, body, this);
Rectangle rect = hull.Rect;
foreach (Structure wall in Structure.WallList)
{
if (!Submarine.RectsOverlap(wall.Rect, hull.Rect)) continue;
Rectangle wallRect = wall.IsHorizontal ?
new Rectangle(hull.Rect.X, wall.Rect.Y, hull.Rect.Width, wall.Rect.Height) :
new Rectangle(wall.Rect.X, hull.Rect.Y, wall.Rect.Width, hull.Rect.Height);
rect = Rectangle.Union(
new Rectangle(wallRect.X, wallRect.Y-wallRect.Height, wallRect.Width, wallRect.Height),
new Rectangle(rect.X, rect.Y - rect.Height, rect.Width, rect.Height));
rect.Y = rect.Y + rect.Height;
}
FixtureFactory.AttachRectangle(
ConvertUnits.ToSimUnits(rect.Width),
ConvertUnits.ToSimUnits(rect.Height),
5.0f,
ConvertUnits.ToSimUnits(new Vector2(rect.X + rect.Width/2, rect.Y - rect.Height/2)),
body, this);
}
body.BodyType = BodyType.Dynamic;
@@ -189,36 +209,26 @@ namespace Barotrauma
}
public void Update(float deltaTime)
{
if (Position!=Vector2.Zero)
{
if (targetPosition != Vector2.Zero && targetPosition != Position)
{
//!!!!!!!!!!!!!!!!
//UpdateColliding();
float dist = Vector2.Distance(targetPosition, Position);
if (dist > 1000.0f)
{
body.SetTransform(ConvertUnits.ToSimUnits(targetPosition), 0.0f);
targetPosition = Vector2.Zero;
}
else if (dist > 50.0f)
{
body.SetTransform((ConvertUnits.ToSimUnits(targetPosition) - body.Position) * 0.01f, 0.0f);
}
}
else
{
targetPosition = Vector2.Zero;
}
//Vector2 translateAmount = speed * deltaTime;
//translateAmount += ConvertUnits.ToDisplayUnits(Position) * collisionRigidness;
//if (targetPosition != Vector2.Zero && targetPosition != Position)
//{
// float dist = Vector2.Distance(targetPosition, Position);
// if (dist>1000.0f)
// {
// sub.SetPosition(targetPosition);
// targetPosition = Vector2.Zero;
// }
// else if (dist>50.0f)
// {
// translateAmount += (targetPosition - Position) * 0.01f;
// }
//}
//else
//{
// targetPosition = Vector2.Zero;
//}
//sub.Translate(translateAmount);
//-------------------------
@@ -236,13 +246,8 @@ namespace Barotrauma
ApplyForce(totalForce);
//UpdateDepthDamage(deltaTime);
UpdateDepthDamage(deltaTime);
//hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position;
//hullBody.SetTransform(Vector2.Zero , 0.0f);
//body.SetTransform(Vector2.Zero, 0.0f);// .LinearVelocity = -body.Position / (float)Physics.step;
//body.LinearVelocity = Vector2.Zero;
}
private Vector2 CalculateBuoyancy()
@@ -311,80 +316,15 @@ namespace Barotrauma
GameMain.GameScreen.Cam.Shake = depth * PressureDamageMultiplier * 0.1f;
damagePos += submarine.Position + Submarine.HiddenSubPosition;
Explosion.RangedStructureDamage(damagePos, depth * PressureDamageMultiplier * 50.0f, depth * PressureDamageMultiplier);
//SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, Rand.Range(0.0f, 100.0f), damagePos, 5000.0f);
depthDamageTimer = 10.0f;
}
//private void UpdateColliding()
//{
// return;
// if (body.Position.LengthSquared()<0.00001f) return;
// Vector2 normal = Vector2.Normalize(body.Position);
// Vector2 simSpeed = ConvertUnits.ToSimUnits(body.LinearVelocity);
// float impact = Vector2.Dot(simSpeed, -normal);
// if (impact < 0.0f) return;
// Vector2 u = Vector2.Dot(simSpeed, -normal) * normal;
// Vector2 w = (simSpeed + u);
// //speed = ConvertUnits.ToDisplayUnits(w * (1.0f - Friction) + u * Restitution);
// if (lastContactPoint == null || lastContactCell==null || impact < 3.0f) return;
// SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, ConvertUnits.ToDisplayUnits((Vector2)lastContactPoint));
// GameMain.GameScreen.Cam.Shake = impact * 2.0f;
// Vector2 limbForce = -normal * impact*0.5f;
// float length = limbForce.Length();
// if (length > 10.0f) limbForce = (limbForce / length) * 10.0f;
// foreach (Character c in Character.CharacterList)
// {
// if (c.AnimController.CurrentHull == null) continue;
// if (impact > 2.0f) c.AnimController.StunTimer = (impact - 2.0f) * 0.1f;
// foreach (Limb limb in c.AnimController.Limbs)
// {
// if (c.AnimController.LowestLimb == limb) continue;
// limb.body.ApplyLinearImpulse(limb.Mass * limbForce);
// }
// }
// Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits((Vector2)lastContactPoint), impact*50.0f, impact*DamageMultiplier);
// //Body wallBody = Submarine.PickBody(
// // (Vector2)lastContactPoint - body.Position,
// // (Vector2)lastContactPoint + body.Position * 10.0f,
// // new List<Body>() { lastContactCell.body });
// //if (wallBody == null || wallBody.UserData == null) return;
// //var damageable = wallBody.UserData as IDamageable;
// //Structure structure = wallBody.UserData as Structure;
// //if (structure == null) return;
// //int sectionIndex = structure.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition));
// //for (int i = sectionIndex - (int)(impact / 5.0f); i < sectionIndex + (int)(impact / 5.0f); i++)
// //{
// // structure.AddDamage(i, impact * DamageMultiplier);
// //}
//}
public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
{
VoronoiCell cell = f2.Body.UserData as VoronoiCell;
if (cell == null)
@@ -396,7 +336,9 @@ namespace Barotrauma
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal2, out points);
if (Submarine.PickBody(points[0] - ConvertUnits.ToSimUnits(submarine.Position) + normal2, points[0] - ConvertUnits.ToSimUnits(submarine.Position) - normal2, null, Physics.CollisionWall) != null)
if (Submarine.PickBody(
points[0] - limb.LinearVelocity * ((float)Physics.step) - ConvertUnits.ToSimUnits(submarine.Position) - submarine.Velocity * ((float)Physics.step) + normal2,
points[0] - ConvertUnits.ToSimUnits(submarine.Position) - normal2, null, Physics.CollisionWall) != null)
{
return true;
@@ -441,7 +383,7 @@ namespace Barotrauma
{
if (c.AnimController.CurrentHull == null) continue;
if (impact > 2.0f) c.AnimController.StunTimer = (impact - 2.0f) * 0.1f;
if (impact > 2.0f) c.StartStun((impact - 2.0f) * 0.1f);
foreach (Limb limb in c.AnimController.Limbs)
{

View File

@@ -420,8 +420,8 @@ namespace Barotrauma
XElement element = new XElement("WayPoint");
element.Add(new XAttribute("ID", ID),
new XAttribute("x", rect.X),
new XAttribute("y", rect.Y),
new XAttribute("x", (int)(rect.X - Submarine.HiddenSubPosition.X)),
new XAttribute("y", (int)(rect.Y - Submarine.HiddenSubPosition.Y)),
new XAttribute("spawn", spawnType));
if (idCardTags.Length > 0)

View File

@@ -0,0 +1,404 @@
using FarseerPhysics;
using FarseerPhysics.Collision;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using Voronoi2;
namespace Barotrauma
{
class SubmarineBody
{
public const float DamageDepth = -30000.0f;
const float PressureDamageMultiplier = 0.001f;
//structure damage = impact * damageMultiplier
const float DamageMultiplier = 50.0f;
const float Friction = 0.2f, Restitution = 0.0f;
public List<Vector2> HullVertices
{
get;
private set;
}
private float depthDamageTimer;
private Submarine submarine;
private Body body;
private Vector2 targetPosition;
float mass = 10000.0f;
//private Vector2? lastContactPoint;
//private VoronoiCell lastContactCell;
public Rectangle Borders
{
get;
private set;
}
public Vector2 Velocity
{
get { return body.LinearVelocity; }
set
{
if (!MathUtils.IsValid(value)) return;
body.LinearVelocity = value;
}
}
public Vector2 TargetPosition
{
get { return targetPosition; }
set
{
if (!MathUtils.IsValid(value)) return;
targetPosition = value;
}
}
public Vector2 Position
{
get { return ConvertUnits.ToDisplayUnits(body.Position); }
}
public Vector2 Center
{
get { return new Vector2(Borders.X + Borders.Width / 2, Borders.Y - Borders.Height / 2); }
}
public bool AtDamageDepth
{
get { return Position.Y < DamageDepth; }
}
public SubmarineBody(Submarine sub)
{
this.submarine = sub;
List<Vector2> convexHull = GenerateConvexHull();
HullVertices = convexHull;
for (int i = 0; i < convexHull.Count; i++)
{
convexHull[i] = ConvertUnits.ToSimUnits(convexHull[i]);
}
convexHull.Reverse();
//get farseer 'vertices' from vectors
Vertices shapevertices = new Vertices(convexHull);
AABB hullAABB = shapevertices.GetAABB();
Borders = new Rectangle(
(int)ConvertUnits.ToDisplayUnits(hullAABB.LowerBound.X),
(int)ConvertUnits.ToDisplayUnits(hullAABB.UpperBound.Y),
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.X * 2.0f),
(int)ConvertUnits.ToDisplayUnits(hullAABB.Extents.Y * 2.0f));
//var triangulatedVertices = Triangulate.ConvexPartition(shapevertices, TriangulationAlgorithm.Bayazit);
body = BodyFactory.CreateBody(GameMain.World, this);
foreach (Hull hull in Hull.hullList)
{
Rectangle rect = hull.Rect;
foreach (Structure wall in Structure.WallList)
{
if (!Submarine.RectsOverlap(wall.Rect, hull.Rect)) continue;
if (wall.IsHorizontal)
{
if (wall.Rect.Y >= hull.Rect.Y)
{
rect = new Rectangle(rect.X, wall.Rect.Y, rect.Width, rect.Height + (wall.Rect.Y - rect.Y));
}
else
{
rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + (rect.Y - rect.Height - (wall.Rect.Y - wall.Rect.Height)));
}
}
}
FixtureFactory.AttachRectangle(
ConvertUnits.ToSimUnits(rect.Width),
ConvertUnits.ToSimUnits(rect.Height),
5.0f,
ConvertUnits.ToSimUnits(rect.Center.ToVector2()),
body, this);
}
body.BodyType = BodyType.Dynamic;
body.CollisionCategories = Physics.CollisionMisc | Physics.CollisionWall;
body.CollidesWith = Physics.CollisionLevel | Physics.CollisionCharacter;
body.Restitution = Restitution;
body.Friction = Friction;
body.FixedRotation = true;
body.Mass = mass;
body.Awake = true;
body.SleepingAllowed = false;
body.IgnoreGravity = true;
body.OnCollision += OnCollision;
//body.UserData = this;
}
private List<Vector2> GenerateConvexHull()
{
if (!Structure.WallList.Any())
{
return new List<Vector2>() { new Vector2(-1.0f, 1.0f), new Vector2(1.0f, 1.0f), new Vector2(0.0f, -1.0f) };
}
List<Vector2> points = new List<Vector2>();
Vector2 leftMost = Vector2.Zero;
foreach (Structure wall in Structure.WallList)
{
for (int x = -1; x <= 1; x += 2)
{
for (int y = -1; y <= 1; y += 2)
{
Vector2 corner = new Vector2(wall.Rect.X + wall.Rect.Width / 2.0f, wall.Rect.Y - wall.Rect.Height / 2.0f);
corner.X += x * wall.Rect.Width / 2.0f;
corner.Y += y * wall.Rect.Height / 2.0f;
if (points.Contains(corner)) continue;
points.Add(corner);
if (leftMost == Vector2.Zero || corner.X < leftMost.X) leftMost = corner;
}
}
}
List<Vector2> hullPoints = new List<Vector2>();
Vector2 currPoint = leftMost;
Vector2 endPoint;
do
{
hullPoints.Add(currPoint);
endPoint = points[0];
for (int i = 1; i < points.Count; i++)
{
if ((currPoint == endPoint)
|| (MathUtils.VectorOrientation(currPoint, endPoint, points[i]) == -1))
{
endPoint = points[i];
}
}
currPoint = endPoint;
}
while (endPoint != hullPoints[0]);
return hullPoints;
}
public void Update(float deltaTime)
{
if (targetPosition != Vector2.Zero && targetPosition != Position)
{
float dist = Vector2.Distance(targetPosition, Position);
if (dist > 1000.0f)
{
body.SetTransform(ConvertUnits.ToSimUnits(targetPosition), 0.0f);
targetPosition = Vector2.Zero;
}
else if (dist > 50.0f)
{
body.SetTransform((ConvertUnits.ToSimUnits(targetPosition) - body.Position) * 0.01f, 0.0f);
}
}
else
{
targetPosition = Vector2.Zero;
}
//-------------------------
Vector2 totalForce = CalculateBuoyancy();
if (body.LinearVelocity.LengthSquared() > 0.000001f)
{
float dragCoefficient = 0.01f;
float speedLength = (body.LinearVelocity == Vector2.Zero) ? 0.0f : body.LinearVelocity.Length();
float drag = speedLength * speedLength * dragCoefficient * mass;
totalForce += -Vector2.Normalize(body.LinearVelocity) * drag;
}
ApplyForce(totalForce);
UpdateDepthDamage(deltaTime);
}
private Vector2 CalculateBuoyancy()
{
float waterVolume = 0.0f;
float volume = 0.0f;
foreach (Hull hull in Hull.hullList)
{
waterVolume += hull.Volume;
volume += hull.FullVolume;
}
float waterPercentage = waterVolume / volume;
float neutralPercentage = 0.07f;
float buoyancy = Math.Max(neutralPercentage - waterPercentage, -neutralPercentage*2.0f);
buoyancy *= mass;
return new Vector2(0.0f, buoyancy*10.0f);
}
public void ApplyForce(Vector2 force)
{
body.ApplyForce(force);
}
public void SetPosition(Vector2 position)
{
body.SetTransform(ConvertUnits.ToSimUnits(position), 0.0f);
}
private void UpdateDepthDamage(float deltaTime)
{
if (Position.Y > DamageDepth) return;
float depth = DamageDepth - Position.Y;
depth = Math.Min(depth, 40000.0f);
// float prevTimer = depthDamageTimer;
depthDamageTimer -= deltaTime*Math.Min(depth,20000)*PressureDamageMultiplier;
//if (prevTimer>5.0f && depthDamageTimer<=5.0f)
//{
// SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f,);
//}
if (depthDamageTimer > 0.0f) return;
Vector2 damagePos = Vector2.Zero;
if (Rand.Int(2)==0)
{
damagePos = new Vector2(
(Rand.Int(2) == 0) ? Borders.X : Borders.X+Borders.Width,
Rand.Range(Borders.Y - Borders.Height, Borders.Y));
}
else
{
damagePos = new Vector2(
Rand.Range(Borders.X, Borders.X + Borders.Width),
(Rand.Int(2) == 0) ? Borders.Y : Borders.Y - Borders.Height);
}
SoundPlayer.PlayDamageSound(DamageSoundType.Pressure, 50.0f, damagePos, 10000.0f);
GameMain.GameScreen.Cam.Shake = depth * PressureDamageMultiplier * 0.1f;
damagePos += submarine.Position + Submarine.HiddenSubPosition;
Explosion.RangedStructureDamage(damagePos, depth * PressureDamageMultiplier * 50.0f, depth * PressureDamageMultiplier);
//SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, Rand.Range(0.0f, 100.0f), damagePos, 5000.0f);
depthDamageTimer = 10.0f;
}
public bool OnCollision(Fixture f1, Fixture f2, Contact contact)
{
VoronoiCell cell = f2.Body.UserData as VoronoiCell;
if (cell == null)
{
Limb limb = f2.Body.UserData as Limb;
if (limb!=null && limb.character.Submarine==null)
{
Vector2 normal2;
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal2, out points);
if (Submarine.PickBody(
points[0] - limb.LinearVelocity * ((float)Physics.step) - ConvertUnits.ToSimUnits(submarine.Position) - submarine.Velocity * ((float)Physics.step) + normal2,
points[0] - ConvertUnits.ToSimUnits(submarine.Position) - normal2, null, Physics.CollisionWall) != null)
{
return true;
}
var ragdoll = limb.character.AnimController;
ragdoll.FindHull();
return false;
}
return true;
}
Vector2 normal;
FarseerPhysics.Common.FixedArray2<Vector2> worldPoints;
contact.GetWorldManifold(out normal, out worldPoints);
Vector2 lastContactPoint = worldPoints[0];
normal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(body.Position) - cell.Center);
float impact = Vector2.Dot(Velocity, -normal);
//Vector2 u = Vector2.Dot(Velocity, -normal) * normal;
//Vector2 w = (Velocity + u);
//speed = ConvertUnits.ToDisplayUnits(w * (1.0f - Friction) + u * Restitution);
if (impact < 3.0f) return true;
SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, ConvertUnits.ToDisplayUnits(lastContactPoint));
GameMain.GameScreen.Cam.Shake = impact * 2.0f;
Vector2 limbForce = -normal * impact * 0.5f;
float length = limbForce.Length();
if (length > 10.0f) limbForce = (limbForce / length) * 10.0f;
foreach (Character c in Character.CharacterList)
{
if (c.AnimController.CurrentHull == null) continue;
if (impact > 2.0f) c.StartStun((impact - 2.0f) * 0.1f);
foreach (Limb limb in c.AnimController.Limbs)
{
if (c.AnimController.LowestLimb == limb) continue;
limb.body.ApplyLinearImpulse(limb.Mass * limbForce);
}
}
Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * DamageMultiplier);
return true;
}
}
}