diff --git a/Subsurface/Content/Items/Engine/engine.xml b/Subsurface/Content/Items/Engine/engine.xml index 3ae2f1d81..f71d89bee 100644 --- a/Subsurface/Content/Items/Engine/engine.xml +++ b/Subsurface/Content/Items/Engine/engine.xml @@ -1,31 +1,31 @@  - + - + - - - - - - + + + + + + - + - + @@ -38,12 +38,12 @@ - - + + - - - - - + + + + + \ No newline at end of file diff --git a/Subsurface/Content/Items/Reactor/reactor.xml b/Subsurface/Content/Items/Reactor/reactor.xml index 306b9b1f0..761987246 100644 --- a/Subsurface/Content/Items/Reactor/reactor.xml +++ b/Subsurface/Content/Items/Reactor/reactor.xml @@ -27,7 +27,7 @@ - + diff --git a/Subsurface/Content/Items/Tools/tools.xml b/Subsurface/Content/Items/Tools/tools.xml index de8247a95..3edec139d 100644 --- a/Subsurface/Content/Items/Tools/tools.xml +++ b/Subsurface/Content/Items/Tools/tools.xml @@ -34,7 +34,7 @@ - + @@ -74,7 +74,7 @@ - + diff --git a/Subsurface/Content/Items/Weapons/explosives.xml b/Subsurface/Content/Items/Weapons/explosives.xml index bcf007454..f23a12245 100644 --- a/Subsurface/Content/Items/Weapons/explosives.xml +++ b/Subsurface/Content/Items/Weapons/explosives.xml @@ -12,7 +12,7 @@ - + diff --git a/Subsurface/Content/Items/Weapons/railgun.xml b/Subsurface/Content/Items/Weapons/railgun.xml index 02b90a194..474b461c4 100644 --- a/Subsurface/Content/Items/Weapons/railgun.xml +++ b/Subsurface/Content/Items/Weapons/railgun.xml @@ -12,7 +12,7 @@ rotationlimits="180,360" powerconsumption="500.0"> - + diff --git a/Subsurface/Content/Items/Weapons/weapons.xml b/Subsurface/Content/Items/Weapons/weapons.xml index a20e0ff6d..22e44c66d 100644 --- a/Subsurface/Content/Items/Weapons/weapons.xml +++ b/Subsurface/Content/Items/Weapons/weapons.xml @@ -51,7 +51,7 @@ - + diff --git a/Subsurface/Content/Sounds/Water/WaterAmbience.ogg b/Subsurface/Content/Sounds/Water/WaterAmbience1.ogg similarity index 100% rename from Subsurface/Content/Sounds/Water/WaterAmbience.ogg rename to Subsurface/Content/Sounds/Water/WaterAmbience1.ogg diff --git a/Subsurface/Content/Sounds/Water/WaterAmbience2.ogg b/Subsurface/Content/Sounds/Water/WaterAmbience2.ogg new file mode 100644 index 000000000..ba4ba86ba Binary files /dev/null and b/Subsurface/Content/Sounds/Water/WaterAmbience2.ogg differ diff --git a/Subsurface/Source/Characters/AI/AIController.cs b/Subsurface/Source/Characters/AI/AIController.cs index 07e36afe7..577f51a56 100644 --- a/Subsurface/Source/Characters/AI/AIController.cs +++ b/Subsurface/Source/Characters/AI/AIController.cs @@ -44,6 +44,8 @@ namespace Subsurface steeringManager = new SteeringManager(this); } + public virtual void OnAttacked(IDamageable attacker, float amount) { } + public virtual void SelectTarget(AITarget target) { } public virtual void Update(float deltaTime) { } diff --git a/Subsurface/Source/Characters/AI/EnemyAIController.cs b/Subsurface/Source/Characters/AI/EnemyAIController.cs index 9655c8206..a21591f92 100644 --- a/Subsurface/Source/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Source/Characters/AI/EnemyAIController.cs @@ -262,6 +262,13 @@ namespace Subsurface targetEntity = closestBody.UserData as IDamageable; } + public override void OnAttacked(IDamageable attacker, float amount) + { + if (attacker==null || attacker.AiTarget==null) return; + AITargetMemory targetMemory = FindTargetMemory(attacker.AiTarget); + targetMemory.Priority += amount; + } + private void UpdateLimbAttack(float deltaTime, Limb limb, Vector2 attackPosition) { IDamageable damageTarget = null; @@ -295,8 +302,8 @@ namespace Subsurface { attackTimer += deltaTime; limb.body.ApplyTorque(limb.Mass * 50.0f * Character.AnimController.Dir * dir); - - limb.attack.DoDamage(damageTarget, limb.SimPosition, deltaTime, (limb.soundTimer <= 0.0f)); + + limb.attack.DoDamage(Character, damageTarget, limb.SimPosition, deltaTime, (limb.soundTimer <= 0.0f)); limb.soundTimer = Limb.SoundInterval; } diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index db2a9ff56..3cb471020 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -10,6 +10,8 @@ namespace Subsurface { class AICharacter : Character { + const float AttackBackPriority = 1.0f; + private AIController aiController; public AICharacter(string file) : this(file, Vector2.Zero, null) @@ -57,6 +59,15 @@ namespace Subsurface aiController.Update(deltaTime); } + public override AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, bool playSound = false) + { + AttackResult result = base.AddDamage(attacker, position, attack, playSound); + + aiController.OnAttacked(attacker, (result.Damage + result.Bleeding)/Math.Max(health,1.0f)); + + return result; + } + public override void FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) { if (type == NetworkEventType.KillCharacter) diff --git a/Subsurface/Source/Characters/Attack.cs b/Subsurface/Source/Characters/Attack.cs index 21724003b..678015716 100644 --- a/Subsurface/Source/Characters/Attack.cs +++ b/Subsurface/Source/Characters/Attack.cs @@ -51,6 +51,12 @@ namespace Subsurface private float priority; + + //public Attack(AttackType type, float range,) + //{ + + //} + public Attack(XElement element) { try @@ -94,10 +100,10 @@ namespace Subsurface { if (subElement.Name.ToString().ToLower() == "particleemitter") particleEmitterPrefab = new ParticleEmitterPrefab(subElement); } - } - public AttackResult DoDamage(IDamageable target, Vector2 position, float deltaTime, bool playSound = true) + + public AttackResult DoDamage(IDamageable attacker, IDamageable target, Vector2 position, float deltaTime, bool playSound = true) { float damageAmount = 0.0f; //DamageSoundType damageSoundType = DamageSoundType.None; @@ -125,7 +131,7 @@ namespace Subsurface sound.Play(1.0f, 500.0f, position); } - return target.AddDamage(position, DamageType, damageAmount, bleedingAmount, Stun, playSound); + return target.AddDamage(attacker, position, this, playSound); } } diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index bb2709f47..dfbcd2c07 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -856,7 +856,12 @@ namespace Subsurface } } - public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) + public virtual AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, bool playSound = false) + { + return AddDamage(position, attack.DamageType, attack.Damage, attack.BleedingDamage, attack.Stun, playSound); + } + + public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound) { AnimController.StunTimer = Math.Max(AnimController.StunTimer, stun); @@ -882,7 +887,6 @@ namespace Subsurface bleeding += attackResult.Bleeding; return attackResult; - } public void Stun() diff --git a/Subsurface/Source/Characters/Ragdoll.cs b/Subsurface/Source/Characters/Ragdoll.cs index 7749a1ca6..7ab5b1f7d 100644 --- a/Subsurface/Source/Characters/Ragdoll.cs +++ b/Subsurface/Source/Characters/Ragdoll.cs @@ -669,13 +669,13 @@ namespace Subsurface foreach (MapEntity e in MapEntity.mapEntityList) { Gap gap = e as Gap; - if (gap == null || gap.FlowTargetHull != currentHull || gap.FlowForce == Vector2.Zero) continue; + if (gap == null || gap.FlowTargetHull != currentHull || gap.LerpedFlowForce == Vector2.Zero) continue; Vector2 gapPos = gap.SimPosition; float dist = Vector2.Distance(limbPos, gapPos); - force += Vector2.Normalize(gap.FlowForce) * (Math.Max(gap.FlowForce.Length() - dist, 0.0f) / 500.0f); + force += Vector2.Normalize(gap.LerpedFlowForce) * (Math.Max(gap.LerpedFlowForce.Length() - dist, 0.0f) / 500.0f); } if (force.Length() > 20.0f) return force; diff --git a/Subsurface/Source/Events/MonsterEvent.cs b/Subsurface/Source/Events/MonsterEvent.cs index f6a6f21b9..cc0aeadfd 100644 --- a/Subsurface/Source/Events/MonsterEvent.cs +++ b/Subsurface/Source/Events/MonsterEvent.cs @@ -27,7 +27,7 @@ namespace Subsurface int amount = Rand.Range(minAmount, maxAmount, false); - monsters = new Character[amount]; + monsters = new AICharacter[amount]; for (int i = 0; i < amount; i++) { diff --git a/Subsurface/Source/Items/Components/Door.cs b/Subsurface/Source/Items/Components/Door.cs index b446a7695..a6eed6412 100644 --- a/Subsurface/Source/Items/Components/Door.cs +++ b/Subsurface/Source/Items/Components/Door.cs @@ -245,9 +245,9 @@ namespace Subsurface.Items.Components public override void UpdateBroken(float deltaTime, Camera cam) { body.Enabled = false; - convexHull.Enabled = false; + //convexHull.Enabled = false; linkedGap.Open = 1.0f; - if (convexHull2 != null) convexHull2.Enabled = false; + //if (convexHull2 != null) convexHull2.Enabled = false; } public override void Draw(SpriteBatch spriteBatch, bool editing) diff --git a/Subsurface/Source/Items/Components/Holdable/MeleeWeapon.cs b/Subsurface/Source/Items/Components/Holdable/MeleeWeapon.cs index 783e416c6..80be13d01 100644 --- a/Subsurface/Source/Items/Components/Holdable/MeleeWeapon.cs +++ b/Subsurface/Source/Items/Components/Holdable/MeleeWeapon.cs @@ -16,6 +16,8 @@ namespace Subsurface.Items.Components private float range; + private Character user; + [HasDefaultValue(0.0f, false)] public float Range { @@ -45,6 +47,8 @@ namespace Subsurface.Items.Components if (character == null) return false; if (!character.GetInputState(InputType.SecondaryHeld) || hitting) return false; + user = character; + if (hitPos < MathHelper.Pi * 0.69f) return false; item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile; @@ -178,7 +182,7 @@ namespace Subsurface.Items.Components if (target == null) return false; - attack.DoDamage(target, item.Position, 1.0f); + attack.DoDamage(user, target, item.Position, 1.0f); RestoreCollision(); hitting = false; diff --git a/Subsurface/Source/Items/Components/Label.cs b/Subsurface/Source/Items/Components/Label.cs index b09c58a5c..97e086077 100644 --- a/Subsurface/Source/Items/Components/Label.cs +++ b/Subsurface/Source/Items/Components/Label.cs @@ -1,106 +1,106 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml.Linq; +//using Microsoft.Xna.Framework; +//using Microsoft.Xna.Framework.Graphics; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using System.Xml.Linq; -namespace Subsurface.Items.Components -{ - class Label : ItemComponent - { - GUITextBox textBox; +//namespace Subsurface.Items.Components +//{ +// class Label : ItemComponent +// { +// GUITextBox textBox; - private string text; +// private string text; - [HasDefaultValue("", true)] - public string Text - { - get { return text; } - set - { - text = value; - } - } +// [HasDefaultValue("", true)] +// public string Text +// { +// get { return text; } +// set +// { +// text = value; +// } +// } - public Label(Item item, XElement element) - : base(item, element) - { +// public Label(Item item, XElement element) +// : base(item, element) +// { - } +// } - public override bool Select(Character character) - { - if (textBox == null) - { - textBox = new GUITextBox(Rectangle.Empty, GUI.Style, GuiFrame); - textBox.Wrap = true; - textBox.OnTextChanged = TextChanged; - textBox.LimitText = true; +// public override bool Select(Character character) +// { +// if (textBox == null) +// { +// textBox = new GUITextBox(Rectangle.Empty, GUI.Style, GuiFrame); +// textBox.Wrap = true; +// textBox.OnTextChanged = TextChanged; +// textBox.LimitText = true; - GUIButton button = new GUIButton(new Rectangle(0,0,100,15), "OK", null, Alignment.BottomRight, GUI.Style, GuiFrame); - button.OnClicked = Close; - } +// GUIButton button = new GUIButton(new Rectangle(0,0,100,15), "OK", null, Alignment.BottomRight, GUI.Style, GuiFrame); +// button.OnClicked = Close; +// } - textBox.Text = text; +// textBox.Text = text; - textBox.Select(); +// textBox.Select(); - return base.Select(character); - } +// return base.Select(character); +// } - public override void DrawHUD(SpriteBatch spriteBatch, Character character) - { - //isActive = true; - GuiFrame.Update((float)Physics.step); - GuiFrame.Draw(spriteBatch); +// public override void DrawHUD(SpriteBatch spriteBatch, Character character) +// { +// //isActive = true; +// GuiFrame.Update((float)Physics.step); +// GuiFrame.Draw(spriteBatch); - //int width = 300, height = 300; - //int x = Game1.GraphicsWidth / 2 - width / 2; - //int y = Game1.GraphicsHeight / 2 - height / 2 - 50; +// //int width = 300, height = 300; +// //int x = Game1.GraphicsWidth / 2 - width / 2; +// //int y = Game1.GraphicsHeight / 2 - height / 2 - 50; - //GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); - if (!textBox.Selected) character.SelectedConstruction = null; - } +// //GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); +// if (!textBox.Selected) character.SelectedConstruction = null; +// } - private bool TextChanged(GUITextBox textBox, string text) - { - this.text = text; - item.NewComponentEvent(this, true); +// private bool TextChanged(GUITextBox textBox, string text) +// { +// this.text = text; +// item.NewComponentEvent(this, true); - return true; - } +// return true; +// } - private bool Close(GUIButton button, object obj) - { - textBox.Deselect(); +// private bool Close(GUIButton button, object obj) +// { +// textBox.Deselect(); - return true; - } +// return true; +// } - public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message) - { - message.Write(Text); - } +// public override void FillNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetOutgoingMessage message) +// { +// message.Write(Text); +// } - public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message) - { - string newText = ""; - try - { - newText = message.ReadString(); - } +// public override void ReadNetworkData(Networking.NetworkEventType type, Lidgren.Network.NetIncomingMessage message) +// { +// string newText = ""; +// try +// { +// newText = message.ReadString(); +// } - catch (Exception e) - { -#if DEBUG - DebugConsole.ThrowError("invalid network message", e); -#endif - return; - } +// catch (Exception e) +// { +//#if DEBUG +// DebugConsole.ThrowError("invalid network message", e); +//#endif +// return; +// } - Text = newText; - } - } -} +// Text = newText; +// } +// } +//} diff --git a/Subsurface/Source/Items/Components/Projectile.cs b/Subsurface/Source/Items/Components/Projectile.cs index 54f38c97c..95a92416f 100644 --- a/Subsurface/Source/Items/Components/Projectile.cs +++ b/Subsurface/Source/Items/Components/Projectile.cs @@ -145,11 +145,11 @@ namespace Subsurface.Items.Components Structure structure; if ((limb = (f2.Body.UserData as Limb)) != null) { - attackResult = attack.DoDamage(limb.character, item.SimPosition, 1.0f); + attackResult = attack.DoDamage(null, limb.character, item.SimPosition, 1.0f); } else if ((structure = (f2.Body.UserData as Structure)) != null) { - attackResult = attack.DoDamage(structure, item.SimPosition, 1.0f); + attackResult = attack.DoDamage(null, structure, item.SimPosition, 1.0f); } } diff --git a/Subsurface/Source/Items/Components/Signal/Wire.cs b/Subsurface/Source/Items/Components/Signal/Wire.cs index d146a3c14..d169f58a4 100644 --- a/Subsurface/Source/Items/Components/Signal/Wire.cs +++ b/Subsurface/Source/Items/Components/Signal/Wire.cs @@ -289,37 +289,39 @@ namespace Subsurface.Items.Components { GUI.DrawRectangle(spriteBatch, new Rectangle((int)Nodes[i].X - 3, (int)-Nodes[i].Y - 3, 6, 6), Color.Red, true, 0.0f); - if (GUIComponent.MouseOn == null && - Vector2.Distance(GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), Nodes[i]) < 20.0f) + if (GUIComponent.MouseOn != null || + Vector2.Distance(GameMain.EditMapScreen.Cam.ScreenToWorld(PlayerInput.MousePosition), Nodes[i]) > 20.0f) { - GUI.DrawRectangle(spriteBatch, new Rectangle((int)Nodes[i].X - 10, (int)-Nodes[i].Y - 10, 20, 20), Color.Red, false, 0.0f); + continue; + } - if (selectedNodeIndex==null)// && selectedNodeIndex>0 && selectedNodeIndex 0.0f) + if (attack.StructureDamage > 0.0f) { List structureList = new List(); @@ -98,7 +93,7 @@ namespace Subsurface 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); + if (distFactor > 0.0f) structure.AddDamage(i, attack.StructureDamage*distFactor); } } } @@ -107,16 +102,16 @@ namespace Subsurface { float dist = Vector2.Distance(c.SimPosition, simPosition); - if (dist > range) continue; + if (dist > attack.Range) continue; - float distFactor = 1.0f - dist / range; + float distFactor = 1.0f - dist / attack.Range; foreach (Limb limb in c.AnimController.Limbs) { - distFactor = 1.0f - Vector2.Distance(limb.SimPosition, simPosition)/range; - - c.AddDamage(limb.SimPosition, DamageType.None, damage / c.AnimController.Limbs.Length * distFactor, 0.0f, stun * distFactor); + distFactor = 1.0f - Vector2.Distance(limb.SimPosition, simPosition)/attack.Range; + c.AddDamage(limb.SimPosition, DamageType.None, + attack.Damage / c.AnimController.Limbs.Length * distFactor, 0.0f, attack.Stun * distFactor, true); if (force>0.0f) { limb.body.ApplyLinearImpulse(Vector2.Normalize(limb.SimPosition - simPosition) * distFactor * force); diff --git a/Subsurface/Source/Map/Gap.cs b/Subsurface/Source/Map/Gap.cs index dee826e67..072e6a328 100644 --- a/Subsurface/Source/Map/Gap.cs +++ b/Subsurface/Source/Map/Gap.cs @@ -40,6 +40,13 @@ namespace Subsurface get { return flowForce*soundVolume; } } + public Vector2 LerpedFlowForce + { + get { return lerpedFlowForce; } + } + + private Vector2 lerpedFlowForce; + public Hull FlowTargetHull { get { return flowTargetHull; } @@ -178,6 +185,14 @@ namespace Subsurface public override void Draw(SpriteBatch sb, bool editing) { + if (GameMain.DebugDraw) + { + Vector2 center = new Vector2(rect.X + rect.Width / 2.0f, -(rect.Y - rect.Width / 2.0f)); + GUI.DrawLine(sb, center, center + flowForce/10.0f, Color.Red); + + GUI.DrawLine(sb, center + Vector2.One * 5.0f, center + lerpedFlowForce / 10.0f + Vector2.One * 5.0f, Color.Orange); + } + if (!editing) return; Color clr = (open == 0.0f) ? Color.Red : Color.Cyan; @@ -251,6 +266,8 @@ namespace Subsurface UpdateRoomToRoom(deltaTime); } + lerpedFlowForce = Vector2.Lerp(lerpedFlowForce, flowForce, 0.1f); + if (FlowForce.Length() > 150.0f && flowTargetHull != null && flowTargetHull.Volume < flowTargetHull.FullVolume) { //UpdateFlowForce(); diff --git a/Subsurface/Source/Map/IDamageable.cs b/Subsurface/Source/Map/IDamageable.cs index bfd5ae1b0..f06cea4d7 100644 --- a/Subsurface/Source/Map/IDamageable.cs +++ b/Subsurface/Source/Map/IDamageable.cs @@ -19,6 +19,6 @@ namespace Subsurface get; } - AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound=true); + AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, bool playSound=true); } } diff --git a/Subsurface/Source/Map/MapEntity.cs b/Subsurface/Source/Map/MapEntity.cs index 8ff2201a3..bcd902a86 100644 --- a/Subsurface/Source/Map/MapEntity.cs +++ b/Subsurface/Source/Map/MapEntity.cs @@ -41,9 +41,10 @@ namespace Subsurface public static bool DisableSelect { get { return disableSelect; } - set { + set + { disableSelect = value; - if (disableSelect==true) + if (disableSelect) { startMovingPos = Vector2.Zero; selectionSize = Vector2.Zero; @@ -52,6 +53,12 @@ namespace Subsurface } } + + public static bool SelectedAny + { + get { return selectedList.Count > 0; } + } + public bool MoveWithLevel { get; diff --git a/Subsurface/Source/Map/Structure.cs b/Subsurface/Source/Map/Structure.cs index fb7e97800..4a67c7cb6 100644 --- a/Subsurface/Source/Map/Structure.cs +++ b/Subsurface/Source/Map/Structure.cs @@ -386,11 +386,11 @@ namespace Subsurface } - public int FindSectionIndex(Vector2 pos) + public int FindSectionIndex(Vector2 displayPos) { int index = (isHorizontal) ? - (int)Math.Floor((pos.X - rect.X) / wallSectionSize) : - (int)Math.Floor((rect.Y - pos.Y) / wallSectionSize); + (int)Math.Floor((displayPos.X - rect.X) / wallSectionSize) : + (int)Math.Floor((rect.Y - displayPos.Y) / wallSectionSize); if (index < 0 || index > sections.Length - 1) return -1; return index; @@ -412,7 +412,7 @@ namespace Subsurface sections[sectionIndex].rect.Y - sections[sectionIndex].rect.Height / 2.0f); } - public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) + public AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, bool playSound = false) { if (!prefab.HasBody || prefab.IsPlatform) return new AttackResult(0.0f, 0.0f); @@ -423,13 +423,13 @@ namespace Subsurface if (playSound && !SectionHasHole(i)) { - DamageSoundType damageSoundType = (damageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash; - AmbientSoundManager.PlayDamageSound(damageSoundType, amount, position); + DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash; + AmbientSoundManager.PlayDamageSound(damageSoundType, attack.Damage, position); } - AddDamage(i, amount); + AddDamage(i, attack.Damage); - return new AttackResult(amount, 0.0f); + return new AttackResult(attack.Damage, 0.0f); } private void SetDamage(int sectionIndex, float damage) diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 8ac493396..e5abeae62 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -1,10 +1,7 @@ using FarseerPhysics; using FarseerPhysics.Collision; using FarseerPhysics.Common; -using FarseerPhysics.Common.Decomposition; using FarseerPhysics.Dynamics; -using FarseerPhysics.Dynamics.Contacts; -using FarseerPhysics.Factories; using Lidgren.Network; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -15,7 +12,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Xml.Linq; -using Voronoi2; namespace Subsurface { @@ -32,20 +28,14 @@ namespace Subsurface private static Submarine loaded; + private SubmarineBody subBody; + private static Vector2 lastPickedPosition; private static float lastPickedFraction; static string SaveFolder; Md5Hash hash; - Vector2 speed; - - Vector2 targetPosition; - - private Rectangle borders; - - private Body hullBody; - private string filePath; private string name; @@ -70,12 +60,6 @@ namespace Subsurface get { return lastPickedFraction; } } - public List HullVertices - { - get; - private set; - } - public Md5Hash MD5Hash { get @@ -98,14 +82,11 @@ namespace Subsurface { get { - return (loaded==null) ? Rectangle.Empty : loaded.borders; + return (loaded==null) ? Rectangle.Empty : Loaded.subBody.Borders; } } - public Vector2 Center - { - get { return new Vector2(borders.X+borders.Width/2, borders.Y - borders.Height/2); } - } + public Vector2 Position { @@ -114,14 +95,16 @@ namespace Subsurface public Vector2 Speed { - get { return speed; } - set - { - if (!MathUtils.IsValid(value)) return; - speed = value; - } + get { return subBody.Speed; } + set { subBody.Speed = value; } } + public List HullVertices + { + get { return subBody.HullVertices; } + } + + public string FilePath { get { return filePath; } @@ -162,69 +145,6 @@ namespace Subsurface ID = -1; } - private List GenerateConvexHull() - { - List points = new List(); - - 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 hullPoints = new List(); - - Vector2 currPoint = leftMost; - Vector2 endPoint; - do - { - hullPoints.Add(currPoint); - endPoint = points[0]; - - for (int i = 1; i < points.Count; i++) - { - if ((currPoint == endPoint) - || (Orientation(currPoint, endPoint, points[i]) == -1)) - { - endPoint = points[i]; - } - } - - currPoint = endPoint; - - } - while (endPoint != hullPoints[0]); - - return hullPoints; - } - - private static int Orientation(Vector2 p1, Vector2 p2, Vector2 p) - { - // Determinant - float Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y - p1.Y); - - if (Orin > 0) - return -1; // (* Orientation is to the left-hand side *) - if (Orin < 0) - return 1; // (* Orientation is to the right-hand side *) - - return 0; // (* Orientation is neutral aka collinear *) - } - //drawing ---------------------------------------------------- public static void Draw(SpriteBatch spriteBatch, bool editing = false) @@ -419,188 +339,41 @@ namespace Subsurface //movement ---------------------------------------------------- - float collisionRigidness = 1.0f; public void Update(float deltaTime) { - Vector2 translateAmount = speed * deltaTime; - translateAmount += ConvertUnits.ToDisplayUnits(hullBody.Position) * collisionRigidness; - - if (targetPosition != Vector2.Zero && Vector2.Distance(targetPosition, Position) > 50.0f) - { - translateAmount += (targetPosition - Position) * 0.01f; - } - else - { - targetPosition = Vector2.Zero; - } - - Translate(translateAmount); - - //------------------------- - - Vector2 totalForce = CalculateBuoyancy(); - - float dragCoefficient = 0.00001f; - - float speedLength = (speed == Vector2.Zero) ? 0.0f : speed.Length(); - float drag = speedLength * speedLength * dragCoefficient * mass; - - if (speed != Vector2.Zero) - { - totalForce += -Vector2.Normalize(speed) * drag; - } - - ApplyForce(totalForce); - - //hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position; - - //hullBody.SetTransform(Vector2.Zero , 0.0f); - hullBody.LinearVelocity = -hullBody.Position/(float)Physics.step; - - if (collidingCell == null) - { - collisionRigidness = MathHelper.Lerp(collisionRigidness, 1.0f, 0.1f); - return; - } - - foreach (GraphEdge ge in collidingCell.edges) - { - Body body = PickBody( - ConvertUnits.ToSimUnits(ge.point1+ GameMain.GameSession.Level.Position), - ConvertUnits.ToSimUnits(ge.point2 + GameMain.GameSession.Level.Position), new List(){collidingCell.body}); - if (body == null || body.UserData == null) continue; - - Structure structure = body.UserData as Structure; - if (structure == null) continue; - structure.AddDamage(lastPickedPosition, DamageType.Blunt, 50.0f, 0.0f, 0.0f, true); - } - - collidingCell = null; - - //hullBodies[0].body.SetTransform(Vector2.Zero, 0.0f); - - //position = hullBodies[0].body.Position; - - //Level.Loaded.Move(-ConvertUnits.ToDisplayUnits(position - prevPosition)); - - //prevPosition = hullBodies[0].body.Position; + if (Level.Loaded == null) return; + subBody.Update(deltaTime); } - private Vector2 CalculateBuoyancy() + public void ApplyForce(Vector2 force) { - 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 = neutralPercentage-waterPercentage; - buoyancy *= mass * 30.0f; - - return new Vector2(0.0f, buoyancy); + subBody.ApplyForce(force); } public void SetPosition(Vector2 position) { - //hullBodies[0].body.SetTransform(position, 0.0f); + if (!MathUtils.IsValid(position)) return; Level.Loaded.SetPosition(-position); //prevPosition = position; } - private void Translate(Vector2 amount) + public void Translate(Vector2 amount) { - if (amount == Vector2.Zero || !amount.IsValid()) return; + if (amount == Vector2.Zero || !MathUtils.IsValid(amount)) return; Level.Loaded.Move(-amount); } - float mass = 10000.0f; - public void ApplyForce(Vector2 force) - { - speed += force/mass; - } - - VoronoiCell collidingCell; - public bool OnCollision(Fixture f1, Fixture f2, Contact contact) - { - System.Diagnostics.Debug.WriteLine("colliding"); - VoronoiCell cell = f2.Body.UserData as VoronoiCell; - if (cell==null) return true; - - Vector2 normal = contact.Manifold.LocalNormal; - Vector2 simSpeed = ConvertUnits.ToSimUnits(speed); - float impact = Vector2.Dot(simSpeed, normal); - - Vector2 u = Vector2.Dot(simSpeed, -normal)*-normal; - Vector2 w = simSpeed - u; - - Vector2 limbForce = normal * impact; - - 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) - { - limb.body.ApplyLinearImpulse(limb.Mass * limbForce); - } - } - - if (impact >= 1.0f) - { - AmbientSoundManager.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, cell.body); - - FixedArray2 worldPoints; - contact.GetWorldManifold(out normal, out worldPoints); - - - AmbientSoundManager.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, ConvertUnits.ToDisplayUnits(worldPoints[0])); - - GameMain.GameScreen.Cam.Shake = impact*2.0f; - } - - System.Diagnostics.Debug.WriteLine("IMPACT: "+impact + " normal: "+normal+" simspeed: "+simSpeed+" u: "+u+" w: " +w); - if (impact < 4.0f) - { - speed = ConvertUnits.ToDisplayUnits(w * 0.9f - u * 0.2f); - return true; - } - else - { - speed = ConvertUnits.ToDisplayUnits(w * 0.9f + u * 0.5f); - } - - - collisionRigidness = 0.8f; - - collidingCell = cell; - - return true; - } - - public void OnSeparation(Fixture f1, Fixture f2) - { - collidingCell = null; - } - public override void FillNetworkData(Networking.NetworkEventType type, NetOutgoingMessage message, object data) { message.Write((float)NetTime.Now); message.Write(Position.X); message.Write(Position.Y); - message.Write(speed.X); - message.Write(speed.Y); + message.Write(Speed.X); + message.Write(Speed.Y); } @@ -630,13 +403,12 @@ namespace Subsurface //newTargetPosition = newTargetPosition + newSpeed * (float)(NetTime.Now - sendingTime); - targetPosition = newTargetPosition; - speed = newSpeed; + subBody.TargetPosition = newTargetPosition; + subBody.Speed = newSpeed; lastNetworkUpdate = sendingTime; } - - + //saving/loading ---------------------------------------------------- @@ -829,42 +601,7 @@ namespace Subsurface } - List 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); - - hullBody = BodyFactory.CreateCompoundPolygon(GameMain.World, triangulatedVertices, 5.0f); - hullBody.BodyType = BodyType.Dynamic; - - hullBody.CollisionCategories = Physics.CollisionMisc; - hullBody.CollidesWith = Physics.CollisionLevel; - hullBody.FixedRotation = true; - hullBody.Awake = true; - hullBody.SleepingAllowed = false; - hullBody.GravityScale = 0.0f; - hullBody.OnCollision += OnCollision; - hullBody.OnSeparation += OnSeparation; + subBody = new SubmarineBody(this); MapEntity.LinkAll(); @@ -908,6 +645,8 @@ namespace Subsurface { if (GameMain.GameScreen.Cam != null) GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; + subBody = null; + Entity.RemoveAll(); PhysicsBody.list.Clear(); diff --git a/Subsurface/Source/Map/SubmarineHull.cs b/Subsurface/Source/Map/SubmarineHull.cs new file mode 100644 index 000000000..c0fdeded5 --- /dev/null +++ b/Subsurface/Source/Map/SubmarineHull.cs @@ -0,0 +1,318 @@ +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 System.Text; +using Voronoi2; + +namespace Subsurface +{ + class SubmarineBody + { + + public List HullVertices + { + get; + private set; + } + + private Submarine sub; + + private Body body; + + private Vector2 speed; + + private Vector2 targetPosition; + + public Rectangle Borders + { + get; + private set; + } + + public Vector2 Speed + { + get { return speed; } + set + { + if (!MathUtils.IsValid(value)) return; + speed = value; + } + } + + public Vector2 TargetPosition + { + get { return targetPosition; } + set + { + if (!MathUtils.IsValid(value)) return; + targetPosition = value; + } + } + + + public Vector2 Center + { + get { return new Vector2(Borders.X + Borders.Width / 2, Borders.Y - Borders.Height / 2); } + } + + public SubmarineBody(Submarine sub) + { + this.sub = sub; + + + List 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.CreateCompoundPolygon(GameMain.World, triangulatedVertices, 5.0f); + body.BodyType = BodyType.Dynamic; + + body.CollisionCategories = Physics.CollisionMisc; + body.CollidesWith = Physics.CollisionLevel; + body.FixedRotation = true; + body.Awake = true; + body.SleepingAllowed = false; + body.GravityScale = 0.0f; + body.OnCollision += OnCollision; + body.OnSeparation += OnSeparation; + } + + + private List GenerateConvexHull() + { + List points = new List(); + + 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 hullPoints = new List(); + + 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; + } + + + float collisionRigidness = 1.0f; + + public void Update(float deltaTime) + { + Vector2 translateAmount = speed * deltaTime; + translateAmount += ConvertUnits.ToDisplayUnits(body.Position) * collisionRigidness; + + if (targetPosition != Vector2.Zero && Vector2.Distance(targetPosition, sub.Position) > 50.0f) + { + translateAmount += (targetPosition - sub.Position) * 0.01f; + } + else + { + targetPosition = Vector2.Zero; + } + + sub.Translate(translateAmount); + + //------------------------- + + Vector2 totalForce = CalculateBuoyancy(); + + float dragCoefficient = 0.00001f; + + float speedLength = (speed == Vector2.Zero) ? 0.0f : speed.Length(); + float drag = speedLength * speedLength * dragCoefficient * mass; + + if (speed != Vector2.Zero) + { + totalForce += -Vector2.Normalize(speed) * drag; + } + + ApplyForce(totalForce); + + //hullBodies[0].body.LinearVelocity = -hullBodies[0].body.Position; + + //hullBody.SetTransform(Vector2.Zero , 0.0f); + body.LinearVelocity = -body.Position / (float)Physics.step; + + if (collidingCell == null) + { + collisionRigidness = MathHelper.Lerp(collisionRigidness, 1.0f, 0.1f); + return; + } + + foreach (GraphEdge ge in collidingCell.edges) + { + Body wallBody = Submarine.PickBody( + ConvertUnits.ToSimUnits(ge.point1 + GameMain.GameSession.Level.Position), + ConvertUnits.ToSimUnits(ge.point2 + GameMain.GameSession.Level.Position), new List() { collidingCell.body }); + if (wallBody == null || wallBody.UserData == null) continue; + + Structure structure = wallBody.UserData as Structure; + if (structure == null) continue; + structure.AddDamage( + structure.FindSectionIndex(ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition)), 50.0f); + } + + collidingCell = null; + } + + 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 = neutralPercentage - waterPercentage; + buoyancy *= mass * 30.0f; + + return new Vector2(0.0f, buoyancy); + } + + float mass = 10000.0f; + public void ApplyForce(Vector2 force) + { + speed += force / mass; + } + + VoronoiCell collidingCell; + public bool OnCollision(Fixture f1, Fixture f2, Contact contact) + { + VoronoiCell cell = f2.Body.UserData as VoronoiCell; + if (cell == null) + { + speed = new Vector2(speed.X * 0.9f, speed.Y * 0.2f); + return true; + } + + Vector2 normal = contact.Manifold.LocalNormal; + Vector2 simSpeed = ConvertUnits.ToSimUnits(speed); + float impact = Vector2.Dot(simSpeed, normal); + + Vector2 u = Vector2.Dot(simSpeed, -normal) * -normal; + Vector2 w = simSpeed - u; + + Vector2 limbForce = normal * impact; + + 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); + } + } + + if (impact >= 1.0f) + { + AmbientSoundManager.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, cell.body); + + FarseerPhysics.Common.FixedArray2 worldPoints; + contact.GetWorldManifold(out normal, out worldPoints); + + AmbientSoundManager.PlayDamageSound(DamageSoundType.StructureBlunt, impact * 10.0f, ConvertUnits.ToDisplayUnits(worldPoints[0])); + + GameMain.GameScreen.Cam.Shake = impact * 2.0f; + } + + System.Diagnostics.Debug.WriteLine("IMPACT: " + impact + " normal: " + normal + " simspeed: " + simSpeed + " u: " + u + " w: " + w); + if (impact < 4.0f) + { + speed = ConvertUnits.ToDisplayUnits(w * 0.9f - u * 0.2f); + return true; + } + else + { + speed = ConvertUnits.ToDisplayUnits(w * 0.9f + u * 0.5f); + } + + + collisionRigidness = 0.8f; + + collidingCell = cell; + + return true; + } + + public void OnSeparation(Fixture f1, Fixture f2) + { + collidingCell = null; + } + } +} diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 5c7d5f1f4..5fde178e5 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -98,7 +98,10 @@ namespace Subsurface Ragdoll.UpdateAll((float)Physics.step); - if (GameMain.GameSession != null && GameMain.GameSession.Level != null) GameMain.GameSession.Submarine.Update((float)Physics.step); + if (GameMain.GameSession != null && GameMain.GameSession.Level != null) + { + GameMain.GameSession.Submarine.Update((float)Physics.step); + } GameMain.World.Step((float)Physics.step); diff --git a/Subsurface/Source/Sounds/AmbientSoundManager.cs b/Subsurface/Source/Sounds/AmbientSoundManager.cs index 2d7d719fa..84eb0cc5d 100644 --- a/Subsurface/Source/Sounds/AmbientSoundManager.cs +++ b/Subsurface/Source/Sounds/AmbientSoundManager.cs @@ -55,8 +55,8 @@ namespace Subsurface private const float MusicLerpSpeed = 0.01f; - private static Sound waterAmbience; - private static int waterAmbienceIndex; + private static Sound[] waterAmbiences = new Sound[2]; + private static int[] waterAmbienceIndexes = new int[2]; private static DamageSound[] damageSounds; @@ -78,7 +78,9 @@ namespace Subsurface yield return CoroutineStatus.Running; - waterAmbience = Sound.Load("Content/Sounds/Water/WaterAmbience.ogg"); + waterAmbiences[0] = Sound.Load("Content/Sounds/Water/WaterAmbience1.ogg"); + yield return CoroutineStatus.Running; + waterAmbiences[1] = Sound.Load("Content/Sounds/Water/WaterAmbience2.ogg"); yield return CoroutineStatus.Running; flowSounds[0] = Sound.Load("Content/Sounds/Water/FlowSmall.ogg"); yield return CoroutineStatus.Running; @@ -162,22 +164,33 @@ namespace Subsurface } } - float ambienceVolume = 0.5f; + float ambienceVolume = 0.6f; float lowpassHFGain = 1.0f; if (Character.Controlled != null) { AnimController animController = Character.Controlled.AnimController; if (animController.HeadInWater) { - ambienceVolume = 0.5f; + ambienceVolume = 0.8f; ambienceVolume += animController.Limbs[0].LinearVelocity.Length(); lowpassHFGain = 0.2f; } } + //how fast the sub is moving, scaled to 0.0 -> 1.0 + float movementFactor = 0.0f; + if (Submarine.Loaded!=null) + { + movementFactor = (Submarine.Loaded.Speed == Vector2.Zero) ? 0.0f : Submarine.Loaded.Speed.Length() / 500.0f; + + movementFactor = MathHelper.Clamp(movementFactor, 0.0f, 1.0f); + } + SoundManager.LowPassHFGain = lowpassHFGain; - waterAmbienceIndex = waterAmbience.Loop(waterAmbienceIndex, ambienceVolume); + waterAmbienceIndexes[0] = waterAmbiences[0].Loop(waterAmbienceIndexes[0], ambienceVolume * (1.0f-movementFactor)); + waterAmbienceIndexes[1] = waterAmbiences[1].Loop(waterAmbienceIndexes[1], ambienceVolume * movementFactor); + } private static void UpdateMusic() diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index 10b736eee..50c993542 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -36,6 +36,21 @@ namespace Subsurface { return (IsValid(vector.X) && IsValid(vector.Y)); } + + + public static int VectorOrientation(Vector2 p1, Vector2 p2, Vector2 p) + { + // Determinant + float Orin = (p2.X - p1.X) * (p.Y - p1.Y) - (p.X - p1.X) * (p2.Y - p1.Y); + + if (Orin > 0) + return -1; // (* Orientation is to the left-hand side *) + if (Orin < 0) + return 1; // (* Orientation is to the right-hand side *) + + return 0; // (* Orientation is neutral aka collinear *) + } + public static float CurveAngle(float from, float to, float step) { diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 6faae5fab..65735f615 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -94,6 +94,7 @@ + @@ -682,7 +683,7 @@ PreserveNewest - PreserveNewest + Always PreserveNewest @@ -706,6 +707,7 @@ PreserveNewest + Designer PreserveNewest @@ -943,13 +945,16 @@ PreserveNewest + + PreserveNewest + PreserveNewest PreserveNewest - + PreserveNewest diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 29bc80cc3..569993ce4 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ