From cc16bb3ad76ea3b8248dc2b32e2dd4e4c3f4dc73 Mon Sep 17 00:00:00 2001 From: Regalis Date: Mon, 28 Sep 2015 19:48:31 +0300 Subject: [PATCH] Loaded sounds are properly freed, ObjectProperty optimization, expanded skill effects (rangedweapon accuracy, welding efficiency, electrical shocks), armored wearables + ballistic vest & helmet --- .../Content/Characters/Crawler/crawler.xml | 6 +- .../Content/Characters/Mantis/mantis.xml | 10 +-- .../Content/Characters/Moloch/moloch.xml | 2 +- Subsurface/Content/Items/Clothes/clothes.xml | 30 ++++++++ .../Content/Items/Clothes/securitygear.png | Bin 0 -> 12408 bytes .../Content/Items/Diving/divinggear.xml | 2 +- .../Content/Items/Electricity/poweritems.xml | 54 ++++++++------ Subsurface/Content/Items/Tools/tools.xml | 9 +-- Subsurface/Content/Map/StructurePrefabs.xml | 16 ++--- Subsurface/Content/randomevents.xml | 7 ++ Subsurface/Source/Characters/Character.cs | 23 +++--- .../Characters/HumanoidAnimController.cs | 3 +- Subsurface/Source/Characters/Limb.cs | 66 ++++++++++++------ Subsurface/Source/Characters/StatusEffect.cs | 4 +- Subsurface/Source/GUI/GUI.cs | 2 +- Subsurface/Source/GameSession/GameSession.cs | 3 +- .../Items/Components/Holdable/RangedWeapon.cs | 38 +++++----- .../Items/Components/Holdable/RepairTool.cs | 11 ++- .../Source/Items/Components/ItemComponent.cs | 44 ++++++++---- .../Source/Items/Components/Power/Powered.cs | 4 +- .../Components/Signal/ConnectionPanel.cs | 29 ++++++++ .../Source/Items/Components/Wearable.cs | 37 ++++++++-- Subsurface/Source/Items/Item.cs | 1 - Subsurface/Source/Map/Explosion.cs | 29 ++++++-- Subsurface/Source/Map/Submarine.cs | 3 +- Subsurface/Source/Networking/GameServer.cs | 3 + Subsurface/Source/Properties.cs | 62 +++++++++++++--- Subsurface/Source/Screens/GameScreen.cs | 5 +- Subsurface/Source/Screens/LobbyScreen.cs | 3 +- .../Source/Sounds/AmbientSoundManager.cs | 23 +++--- Subsurface/Source/Sounds/Sound.cs | 59 ++++++++++------ Subsurface/Subsurface.csproj | 3 + Subsurface_Solution.sln | 3 - Subsurface_Solution.v12.suo | Bin 705536 -> 715776 bytes 34 files changed, 411 insertions(+), 183 deletions(-) create mode 100644 Subsurface/Content/Items/Clothes/securitygear.png diff --git a/Subsurface/Content/Characters/Crawler/crawler.xml b/Subsurface/Content/Characters/Crawler/crawler.xml index 38b7e8b3a..f34cde953 100644 --- a/Subsurface/Content/Characters/Crawler/crawler.xml +++ b/Subsurface/Content/Characters/Crawler/crawler.xml @@ -14,17 +14,17 @@ flip="true"> - + - + - + diff --git a/Subsurface/Content/Characters/Mantis/mantis.xml b/Subsurface/Content/Characters/Mantis/mantis.xml index e6101c656..31f0db1c2 100644 --- a/Subsurface/Content/Characters/Mantis/mantis.xml +++ b/Subsurface/Content/Characters/Mantis/mantis.xml @@ -16,22 +16,22 @@ flip="true"> - + - + - + - + @@ -44,7 +44,7 @@ - + diff --git a/Subsurface/Content/Characters/Moloch/moloch.xml b/Subsurface/Content/Characters/Moloch/moloch.xml index 05db8ab13..d9168a7ab 100644 --- a/Subsurface/Content/Characters/Moloch/moloch.xml +++ b/Subsurface/Content/Characters/Moloch/moloch.xml @@ -9,7 +9,7 @@ - + diff --git a/Subsurface/Content/Items/Clothes/clothes.xml b/Subsurface/Content/Items/Clothes/clothes.xml index e5cc154a9..e52fef947 100644 --- a/Subsurface/Content/Items/Clothes/clothes.xml +++ b/Subsurface/Content/Items/Clothes/clothes.xml @@ -52,5 +52,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Subsurface/Content/Items/Clothes/securitygear.png b/Subsurface/Content/Items/Clothes/securitygear.png new file mode 100644 index 0000000000000000000000000000000000000000..d9e3c67c79b2e1ef0467b0f8f5288a485dcda52d GIT binary patch literal 12408 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 - + diff --git a/Subsurface/Content/Items/Electricity/poweritems.xml b/Subsurface/Content/Items/Electricity/poweritems.xml index fb0260648..69a93d797 100644 --- a/Subsurface/Content/Items/Electricity/poweritems.xml +++ b/Subsurface/Content/Items/Electricity/poweritems.xml @@ -1,11 +1,11 @@  - - - + + + @@ -17,33 +17,41 @@ - - - + + + + + + + + - + - + - + - - - - - + + + + + + + + + + + - - - \ No newline at end of file diff --git a/Subsurface/Content/Items/Tools/tools.xml b/Subsurface/Content/Items/Tools/tools.xml index 3edec139d..95cc3ae5b 100644 --- a/Subsurface/Content/Items/Tools/tools.xml +++ b/Subsurface/Content/Items/Tools/tools.xml @@ -32,10 +32,7 @@ - - - - + @@ -73,9 +70,7 @@ - - - + diff --git a/Subsurface/Content/Map/StructurePrefabs.xml b/Subsurface/Content/Map/StructurePrefabs.xml index fd28129fd..2dfff52c7 100644 --- a/Subsurface/Content/Map/StructurePrefabs.xml +++ b/Subsurface/Content/Map/StructurePrefabs.xml @@ -1,18 +1,18 @@ - - - - - - - - + + \ No newline at end of file diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 969af89cf..f5a58ec55 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -15,6 +15,7 @@ using System.Xml.Linq; namespace Subsurface { + class Character : Entity, IDamageable, IPropertyObject { public static List CharacterList = new List(); @@ -170,6 +171,12 @@ namespace Subsurface } } + public float Stun + { + get { return AnimController.StunTimer; } + set { StartStun(value); } + } + public float Health { get @@ -873,8 +880,7 @@ namespace Subsurface public AttackResult AddDamage(Vector2 simPosition, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound) { - AnimController.StunTimer = Math.Max(AnimController.StunTimer, stun); - + StartStun(stun); if (controlled == this) CharacterHUD.TakeDamage(); Limb closestLimb = null; @@ -901,14 +907,11 @@ namespace Subsurface return attackResult; } - public void Stun() + public void StartStun(float stunTimer) { - //for (int i = 0; i < selectedItems.Length; i++ ) - //{ - // if (selectedItems[i] == null) continue; - // selectedItems[i].Drop(); - // selectedItems[i] = null; - //} + if (stunTimer <= 0.0f) return; + + AnimController.StunTimer = Math.Max(AnimController.StunTimer, stunTimer); selectedConstruction = null; } @@ -1268,7 +1271,7 @@ namespace Subsurface } catch { return; } - AnimController.StunTimer = newStunTimer; + StartStun(newStunTimer); Health = newHealth; LargeUpdateTimer = 1; diff --git a/Subsurface/Source/Characters/HumanoidAnimController.cs b/Subsurface/Source/Characters/HumanoidAnimController.cs index bd4b58030..cc79e911a 100644 --- a/Subsurface/Source/Characters/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/HumanoidAnimController.cs @@ -125,8 +125,7 @@ namespace Subsurface //stun (= disable the animations) if the ragdoll receives a large enough impact if (strongestImpact > 0.0f) { - character.Stun(); - stunTimer = MathHelper.Clamp(strongestImpact * 0.5f, stunTimer, 5.0f); + character.StartStun(MathHelper.Min(strongestImpact * 0.5f, 5.0f)); } strongestImpact = 0.0f; diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index 741f0b130..d76166327 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -62,7 +62,7 @@ namespace Subsurface private Direction dir; - private Item wearingItem; + private Wearable wearingItem; private WearableSprite wearingItemSprite; private Vector2 animTargetPos; @@ -92,6 +92,7 @@ namespace Subsurface get { return body.Rotation; } } + //where an animcontroller is trying to pull the limb, only used for debug visualization public Vector2 AnimTargetPos { get { return animTargetPos; } @@ -156,7 +157,7 @@ namespace Subsurface // set { bleeding = MathHelper.Clamp(value, 0.0f, 100.0f); } //} - public Item WearingItem + public Wearable WearingItem { get { return wearingItem; } set { wearingItem = value; } @@ -238,7 +239,7 @@ namespace Subsurface armorSector.X = MathHelper.ToRadians(armorSector.X); armorSector.Y = MathHelper.ToRadians(armorSector.Y); - armorValue = Math.Max(ToolBox.GetAttributeFloat(element, "armor", 1.0f), 1.0f); + armorValue = Math.Max(ToolBox.GetAttributeFloat(element, "armor", 0.0f), 0.0f); body.BodyType = BodyType.Dynamic; body.FarseerBody.AngularDamping = LimbAngularDamping; @@ -290,27 +291,33 @@ namespace Subsurface DamageSoundType damageSoundType = (damageType == DamageType.Blunt) ? DamageSoundType.LimbBlunt : DamageSoundType.LimbSlash; bool hitArmor = false; - if (armorSector != Vector2.Zero) + float totalArmorValue = 0.0f; + + if (armorValue>0.0f && SectorHit(armorSector, simPosition)) { - float rot = body.Rotation; - if (Dir == -1) rot -= MathHelper.Pi; - - Vector2 armorLimits = new Vector2(rot-armorSector.X*Dir, rot-armorSector.Y*Dir); - - float mid = (armorLimits.X + armorLimits.Y) / 2.0f; - - float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(simPosition - SimPosition), mid); - - if (Math.Abs(angleDiff) < (armorSector.Y - armorSector.X) / 2.0f) - { - hitArmor = true; - damageSoundType = DamageSoundType.LimbArmor; - amount /= armorValue; - bleedingAmount /= armorValue; - } + hitArmor = true; + totalArmorValue += armorValue; } - if (playSound && amount>0.0f) + if (wearingItem!=null && + wearingItem.ArmorValue>0.0f && + SectorHit(wearingItem.ArmorSectorLimits, simPosition)) + { + hitArmor = true; + totalArmorValue += wearingItem.ArmorValue; + } + + if (hitArmor) + { + totalArmorValue = Math.Max(totalArmorValue, 0.0f); + + damageSoundType = DamageSoundType.LimbArmor; + amount = Math.Max(0.0f, amount - totalArmorValue); + bleedingAmount = Math.Max(0.0f, bleedingAmount - totalArmorValue); ; + } + + + if (playSound) { AmbientSoundManager.PlayDamageSound(damageSoundType, amount, ConvertUnits.ToDisplayUnits(simPosition)); } @@ -338,6 +345,21 @@ namespace Subsurface return new AttackResult(amount, bleedingAmount, hitArmor); } + public bool SectorHit(Vector2 armorSector, Vector2 simPosition) + { + if (armorSector == Vector2.Zero) return false; + + float rot = body.Rotation; + if (Dir == -1) rot -= MathHelper.Pi; + + Vector2 armorLimits = new Vector2(rot - armorSector.X * Dir, rot - armorSector.Y * Dir); + + float mid = (armorLimits.X + armorLimits.Y) / 2.0f; + float angleDiff = MathUtils.GetShortestAngle(MathUtils.VectorToAngle(simPosition - SimPosition), mid); + + return (Math.Abs(angleDiff) < (armorSector.Y - armorSector.X) / 2.0f); + } + public void Update(float deltaTime) { if (LinearVelocity.X>100.0f) @@ -416,7 +438,7 @@ namespace Subsurface float depth = sprite.Depth - 0.000001f; - if (wearingItemSprite.DepthLimb==LimbType.None) + if (wearingItemSprite.DepthLimb!=LimbType.None) { Limb depthLimb = character.AnimController.GetLimb(wearingItemSprite.DepthLimb); if (depthLimb!=null) diff --git a/Subsurface/Source/Characters/StatusEffect.cs b/Subsurface/Source/Characters/StatusEffect.cs index 8854ba914..60fd2f13d 100644 --- a/Subsurface/Source/Characters/StatusEffect.cs +++ b/Subsurface/Source/Characters/StatusEffect.cs @@ -228,6 +228,7 @@ namespace Subsurface if (type == typeof(float)) { float floatValue = (float)value * deltaTime; + if (!setValue) floatValue += (float)property.GetValue(); property.TrySetValue(floatValue); } @@ -253,7 +254,6 @@ namespace Subsurface { DelayedEffect.List[i].Update(deltaTime); } - } - + } } } diff --git a/Subsurface/Source/GUI/GUI.cs b/Subsurface/Source/GUI/GUI.cs index 8ae08d3d6..274826e1c 100644 --- a/Subsurface/Source/GUI/GUI.cs +++ b/Subsurface/Source/GUI/GUI.cs @@ -49,7 +49,7 @@ namespace Subsurface graphicsDevice = graphics; sounds = new Sound[2]; - sounds[0] = Sound.Load("Content/Sounds/UI/UImsg.ogg"); + sounds[0] = Sound.Load("Content/Sounds/UI/UImsg.ogg", false); // create 1x1 texture for line drawing t = new Texture2D(graphicsDevice, 1, 1); diff --git a/Subsurface/Source/GameSession/GameSession.cs b/Subsurface/Source/GameSession/GameSession.cs index 0023de375..08b279630 100644 --- a/Subsurface/Source/GameSession/GameSession.cs +++ b/Subsurface/Source/GameSession/GameSession.cs @@ -138,7 +138,8 @@ namespace Subsurface } else if (GameMain.Client==null) - { + { + Submarine.Unload(); GameMain.LobbyScreen.Select(); } diff --git a/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs b/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs index fdc1c33b8..9af04c513 100644 --- a/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs +++ b/Subsurface/Source/Items/Components/Holdable/RangedWeapon.cs @@ -56,8 +56,6 @@ namespace Subsurface.Items.Components if (!character.GetInputState(InputType.SecondaryHeld) || reload > 0.0f) return false; isActive = true; reload = 1.0f; - - bool failed = DoesUseFail(character); List limbBodies = new List(); foreach (Limb l in character.AnimController.Limbs) @@ -68,6 +66,15 @@ namespace Subsurface.Items.Components Item[] containedItems = item.ContainedItems; if (containedItems == null || !containedItems.Any()) return false; + float degreeOfFailure = (100.0f - DegreeOfSuccess(character))/100.0f; + + degreeOfFailure *= degreeOfFailure; + + if (degreeOfFailure > Rand.Range(0.0f, 1.0f)) + { + ApplyStatusEffects(ActionType.OnFailure, 1.0f, character); + } + foreach (Item projectile in containedItems) { if (projectile == null) continue; @@ -76,35 +83,28 @@ namespace Subsurface.Items.Components //so that the player can't shoot himself Projectile projectileComponent= projectile.GetComponent(); if (projectileComponent == null) continue; - + projectile.body.ResetDynamics(); projectile.SetTransform(TransformedBarrelPos, - (item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi); + ((item.body.Dir == 1.0f) ? item.body.Rotation : item.body.Rotation - MathHelper.Pi) + + Rand.Range(-degreeOfFailure, degreeOfFailure)); projectile.Use(deltaTime); - - if (failed) - { - Vector2 modifiedVelocity = projectile.body.LinearVelocity; - modifiedVelocity.X *= Rand.Range(0.0f, 0.5f); - modifiedVelocity.Y *= Rand.Range(0.0f, 0.5f); - - projectile.body.LinearVelocity = modifiedVelocity; - projectile.body.ApplyTorque(projectile.body.Mass * Rand.Range(-10.0f, 10.0f)); + projectile.body.ApplyTorque(projectile.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f)); //recoil - //item.body.ApplyLinearImpulse( - // new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * item.body.Mass * -10.0f); - } - else - { + item.body.ApplyLinearImpulse( + new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * item.body.Mass * -50.0f); + + //else + //{ projectileComponent.ignoredBodies = limbBodies; //recoil //item.body.ApplyLinearImpulse( // new Vector2((float)Math.Cos(projectile.body.Rotation), (float)Math.Sin(projectile.body.Rotation)) * -item.body.Mass); - } + //} item.RemoveContained(projectile); diff --git a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs index 39f393c83..5332654d7 100644 --- a/Subsurface/Source/Items/Components/Holdable/RepairTool.cs +++ b/Subsurface/Source/Items/Components/Holdable/RepairTool.cs @@ -104,13 +104,21 @@ namespace Subsurface.Items.Components if (character == null) return false; if (!character.GetInputState(InputType.SecondaryHeld)) return false; - if (DoesUseFail(character)) return false; + //if (DoesUseFail(character)) return false; isActive = true; Vector2 targetPosition = item.body.SimPosition; //targetPosition = targetPosition.X, -targetPosition.Y); + float degreeOfSuccess = DegreeOfSuccess(character); + + if (Rand.Range(0.0f, 1.0f) > degreeOfSuccess * degreeOfSuccess) + { + ApplyStatusEffects(ActionType.OnFailure, 1.0f, character); + return false; + } + targetPosition += new Vector2( (float)Math.Cos(item.body.Rotation), (float)Math.Sin(item.body.Rotation)) * range * item.body.Dir; @@ -118,6 +126,7 @@ namespace Subsurface.Items.Components List ignoredBodies = new List(); foreach (Limb limb in character.AnimController.Limbs) { + if (Rand.Range(0.0f, 1.0f) > degreeOfSuccess) continue; ignoredBodies.Add(limb.body.FarseerBody); } diff --git a/Subsurface/Source/Items/Components/ItemComponent.cs b/Subsurface/Source/Items/Components/ItemComponent.cs index 1888c1c6d..2a1119e5b 100644 --- a/Subsurface/Source/Items/Components/ItemComponent.cs +++ b/Subsurface/Source/Items/Components/ItemComponent.cs @@ -426,24 +426,44 @@ namespace Subsurface.Items.Components return true; } - protected bool DoesUseFail(Character character) + /// + /// Returns 0.0f-1.0f based on how well the character can use the itemcomponent + /// + /// 0.5f if all the skills meet the skill requirements exactly, 1.0f if they're way above and 0.0f if way less + protected float DegreeOfSuccess(Character character) { - foreach (Skill skill in requiredSkills) - { - int characterLevel = character.GetSkillLevel(skill.Name); - if (characterLevel > skill.Level) continue; + if (requiredSkills.Count == 0) return 100.0f; - if (Rand.Int(characterLevel) - skill.Level < 0) - { - item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character); - //Item.ApplyStatusEffects(); - return true; - } + float[] skillSuccess = new float[requiredSkills.Count]; + + for (int i = 0; i < requiredSkills.Count; i++ ) + { + int characterLevel = character.GetSkillLevel(requiredSkills[i].Name); + + skillSuccess[i] = (characterLevel - requiredSkills[i].Level); } - return false; + float average = skillSuccess.Average(); + + return (average+100.0f)/2.0f; } + //public bool CheckFailure(Character character) + //{ + // foreach (Skill skill in requiredSkills) + // { + // int characterLevel = character.GetSkillLevel(skill.Name); + // if (characterLevel > skill.Level) continue; + + // item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character); + // //Item.ApplyStatusEffects(); + // return true; + + // } + + // return false; + //} + public bool HasRequiredContainedItems(bool addMessage) { List requiredContained = requiredItems.FindAll(ri=> ri.Type == RelatedItem.RelationType.Contained); diff --git a/Subsurface/Source/Items/Components/Power/Powered.cs b/Subsurface/Source/Items/Components/Power/Powered.cs index 78d841bf8..2ca91e3d8 100644 --- a/Subsurface/Source/Items/Components/Power/Powered.cs +++ b/Subsurface/Source/Items/Components/Power/Powered.cs @@ -72,7 +72,7 @@ namespace Subsurface.Items.Components { if (powerOnSound == null) { - powerOnSound = Sound.Load("Content/Items/Electricity/powerOn.ogg"); + powerOnSound = Sound.Load("Content/Items/Electricity/powerOn.ogg", false); } if (sparkSounds == null) @@ -81,7 +81,7 @@ namespace Subsurface.Items.Components string dir = Path.GetDirectoryName(item.Prefab.ConfigFile) + "\\"; for (int i = 0; i < 4; i++) { - sparkSounds[i] = Sound.Load("Content/Items/Electricity/zap" + (i + 1) + ".ogg"); + sparkSounds[i] = Sound.Load("Content/Items/Electricity/zap" + (i + 1) + ".ogg", false); } } } diff --git a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs index 6bdbb62c6..18806c7e3 100644 --- a/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs +++ b/Subsurface/Source/Items/Components/Signal/ConnectionPanel.cs @@ -71,6 +71,35 @@ namespace Subsurface.Items.Components return true; } + public override bool Use(float deltaTime, Character character = null) + { + if (character == null || character!=user) return false; + + var powered = item.GetComponent(); + if (powered != null) + { + if (powered.Voltage < 0.1f) return false; + } + + float degreeOfSuccess = DegreeOfSuccess(character); + if (Rand.Range(0.0f, 0.5f) < degreeOfSuccess) return false; + + item.ApplyStatusEffects(ActionType.OnFailure, 1.0f, character); + + //Vector2 baseVel = Rand.Vector(300.0f); + //for (int i = 0; i < 10; i++) + //{ + // var particle = GameMain.ParticleManager.CreateParticle("spark", item.Position, + // baseVel + Rand.Vector(100.0f), 0.0f); + + // if (particle != null) particle.Size *= Rand.Range(0.5f, 1.0f); + //} + + //character.AddDamage(item.SimPosition, DamageType.None, Math.Abs(degreeOfSuccess-100.0f)/10.0f, 0.0f, 3.0f, false); + + return true; + } + public override void Load(XElement element) { base.Load(element); diff --git a/Subsurface/Source/Items/Components/Wearable.cs b/Subsurface/Source/Items/Components/Wearable.cs index 94daa00b9..6b9d18378 100644 --- a/Subsurface/Source/Items/Components/Wearable.cs +++ b/Subsurface/Source/Items/Components/Wearable.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Xna.Framework; +using System; using System.IO; using System.Linq; using System.Xml.Linq; @@ -26,6 +27,34 @@ namespace Subsurface.Items.Components LimbType[] limbType; Limb[] limb; + private float armorValue; + + private Vector2 armorSector; + + [HasDefaultValue(0.0f, false)] + public float ArmorValue + { + get { return armorValue; } + set { armorValue = MathHelper.Clamp(value, 0.0f, 100.0f); } + } + + [HasDefaultValue("0.0,360.0", false)] + public string ArmorSector + { + get { return ToolBox.Vector2ToString(armorSector); } + set + { + armorSector = ToolBox.ParseToVector2(value); + armorSector.X = MathHelper.ToRadians(armorSector.X); + armorSector.Y = MathHelper.ToRadians(armorSector.Y); + } + } + + public Vector2 ArmorSectorLimits + { + get { return armorSector; } + } + public Wearable (Item item, XElement element) : base(item, element) { @@ -76,7 +105,7 @@ namespace Subsurface.Items.Components if (equipLimb == null) continue; //something is already on the limb -> unequip it - if (equipLimb.WearingItem != null && equipLimb.WearingItem != item) + if (equipLimb.WearingItem != null && equipLimb.WearingItem != this) { equipLimb.WearingItem.Unequip(character); } @@ -88,7 +117,7 @@ namespace Subsurface.Items.Components isActive = true; limb[i] = equipLimb; - equipLimb.WearingItem = item; + equipLimb.WearingItem = this; equipLimb.WearingItemSprite = wearableSprite[i]; } } @@ -111,7 +140,7 @@ namespace Subsurface.Items.Components Limb equipLimb = character.AnimController.GetLimb(limbType[i]); if (equipLimb == null) continue; - if (equipLimb.WearingItem != item) continue; + if (equipLimb.WearingItem != this) continue; limb[i] = null; equipLimb.WearingItem = null; diff --git a/Subsurface/Source/Items/Item.cs b/Subsurface/Source/Items/Item.cs index 4481045ba..07bcbdde3 100644 --- a/Subsurface/Source/Items/Item.cs +++ b/Subsurface/Source/Items/Item.cs @@ -1256,7 +1256,6 @@ namespace Subsurface { ic.Remove(); } - itemList.Remove(this); foreach (Item it in itemList) diff --git a/Subsurface/Source/Map/Explosion.cs b/Subsurface/Source/Map/Explosion.cs index 111117337..2946127ce 100644 --- a/Subsurface/Source/Map/Explosion.cs +++ b/Subsurface/Source/Map/Explosion.cs @@ -19,6 +19,8 @@ namespace Subsurface public float CameraShake; + private bool sparks, shockwave, flames; + //public Explosion(Vector2 position, float range, float damage, float structureDamage, float stun = 0.0f, float force = 0.0f) //{ // this.position = position; @@ -36,6 +38,10 @@ namespace Subsurface force = ToolBox.GetAttributeFloat(element, "force", 0.0f); + sparks = ToolBox.GetAttributeBool(element, "sparks", true); + shockwave = ToolBox.GetAttributeBool(element, "shockwave", true); + flames = ToolBox.GetAttributeBool(element, "flames", true); + CameraShake = attack.Range*10.0f; } @@ -48,16 +54,25 @@ namespace Subsurface { Vector2 displayPosition = ConvertUnits.ToDisplayUnits(simPosition); - GameMain.ParticleManager.CreateParticle("shockwave", displayPosition, - Vector2.Zero, 0.0f); + if (shockwave) + { + GameMain.ParticleManager.CreateParticle("shockwave", displayPosition, + Vector2.Zero, 0.0f); + } + for (int i = 0; i < attack.Range * 10; i++) { - GameMain.ParticleManager.CreateParticle("spark", displayPosition, - Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f); - - GameMain.ParticleManager.CreateParticle("explosionfire", displayPosition + Rand.Vector(50f), - Rand.Vector(Rand.Range(50f, 100.0f)), 0.0f); + if (sparks) + { + GameMain.ParticleManager.CreateParticle("spark", displayPosition, + Rand.Vector(Rand.Range(500.0f, 800.0f)), 0.0f); + } + if (flames) + { + GameMain.ParticleManager.CreateParticle("explosionfire", displayPosition + Rand.Vector(50f), + Rand.Vector(Rand.Range(50f, 100.0f)), 0.0f); + } } float displayRange = ConvertUnits.ToDisplayUnits(attack.Range); diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 2c42bc697..822026e1d 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -607,7 +607,6 @@ namespace Subsurface foreach (Item item in Item.itemList) { - System.Diagnostics.Debug.WriteLine(item.ID); foreach (ItemComponent ic in item.components) { ic.OnMapLoaded(); @@ -634,6 +633,8 @@ namespace Subsurface public static void Unload() { if (loaded == null) return; + + Sound.OnGameEnd(); loaded.Remove(); diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 67f8a6358..986e32237 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -436,6 +436,9 @@ namespace Subsurface.Networking userID = inc.ReadInt32(); userPassword = inc.ReadString(); version = inc.ReadString(); +#if DEBUG + version = GameMain.Version.ToString(); +#endif packageName = inc.ReadString(); packageHash = inc.ReadString(); name = inc.ReadString(); diff --git a/Subsurface/Source/Properties.cs b/Subsurface/Source/Properties.cs index e27bdf52a..c6aed3039 100644 --- a/Subsurface/Source/Properties.cs +++ b/Subsurface/Source/Properties.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Globalization; using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Xml.Linq; +using System.ComponentModel; namespace Subsurface @@ -37,12 +39,13 @@ namespace Subsurface this.isSaveable = isSaveable; } } - + class ObjectProperty { readonly PropertyDescriptor property; + readonly PropertyInfo propertyInfo; readonly object obj; - + public string Name { get { return property.Name; } @@ -56,6 +59,7 @@ namespace Subsurface public ObjectProperty(PropertyDescriptor property, object obj) { this.property = property; + propertyInfo = property.ComponentType.GetProperty(property.Name); this.obj = obj; } @@ -65,7 +69,7 @@ namespace Subsurface if (property.PropertyType == typeof(string)) { - property.SetValue(obj, value); + propertyInfo.SetValue(obj, value, null); } else if (property.PropertyType == typeof(float)) { @@ -73,19 +77,19 @@ namespace Subsurface if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal)) { - property.SetValue(obj, floatVal); + propertyInfo.SetValue(obj, floatVal, null); } } else if (property.PropertyType == typeof(bool)) { - property.SetValue(obj, (value.ToLower()=="true")); + propertyInfo.SetValue(obj, (value.ToLower() == "true"), null); } else if (property.PropertyType == typeof(int)) { int intVal = 0; if (int.TryParse(value, out intVal)) { - property.SetValue(obj, intVal); + propertyInfo.SetValue(obj, intVal, null); } } else @@ -114,7 +118,47 @@ namespace Subsurface if (obj == null || property == null) return false; try { - property.SetValue(obj, value); + propertyInfo.SetValue(obj, value, null); + } + catch + { + return false; + } + return true; + } + + public bool TrySetValue(float value) + { + try + { + propertyInfo.SetValue(obj, value, null); + } + catch + { + return false; + } + + return true; + } + + public bool TrySetValue(bool value) + { + try + { + propertyInfo.SetValue(obj, value, null); + } + catch + { + return false; + } + return true; + } + + public bool TrySetValue(int value) + { + try + { + propertyInfo.SetValue(obj, value, null); } catch { @@ -129,7 +173,7 @@ namespace Subsurface try { - return property.GetValue(obj); + return propertyInfo.GetValue(obj, null); } catch { diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 5fde178e5..83e81e44b 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -80,8 +80,7 @@ namespace Subsurface GameMain.ParticleManager.Update((float)deltaTime); StatusEffect.UpdateAll((float)deltaTime); - - + Physics.accumulator = Math.Min(Physics.accumulator, Physics.step * 4); while (Physics.accumulator >= Physics.step) { @@ -147,7 +146,7 @@ namespace Subsurface public void DrawMap(GraphicsDevice graphics, SpriteBatch spriteBatch) { GameMain.LightManager.DrawLightmap(graphics, spriteBatch, cam); - + //---------------------------------------------------------------------------------------- //1. draw the background, characters and the parts of the submarine that are behind them //---------------------------------------------------------------------------------------- diff --git a/Subsurface/Source/Screens/LobbyScreen.cs b/Subsurface/Source/Screens/LobbyScreen.cs index a458f9e78..286a8fecc 100644 --- a/Subsurface/Source/Screens/LobbyScreen.cs +++ b/Subsurface/Source/Screens/LobbyScreen.cs @@ -73,6 +73,7 @@ namespace Subsurface GUIButton button = new GUIButton(new Rectangle(0, 70, 100, 30), "Map", null, Alignment.Left, GUI.Style, leftPanel); button.UserData = PanelTab.Map; button.OnClicked = SelectRightPanel; + SelectRightPanel(button, button.UserData); button = new GUIButton(new Rectangle(0, 110, 100, 30), "Crew", null, Alignment.Left, GUI.Style, leftPanel); button.UserData = PanelTab.Crew; @@ -149,8 +150,6 @@ namespace Subsurface gameMode = GameMain.GameSession.gameMode as SinglePlayerMode; - selectedRightPanel = (int)PanelTab.Crew; - //Map.Unload(); UpdateCharacterLists(); diff --git a/Subsurface/Source/Sounds/AmbientSoundManager.cs b/Subsurface/Source/Sounds/AmbientSoundManager.cs index 84de54632..b2890ef65 100644 --- a/Subsurface/Source/Sounds/AmbientSoundManager.cs +++ b/Subsurface/Source/Sounds/AmbientSoundManager.cs @@ -71,22 +71,22 @@ namespace Subsurface { - startDrone = Sound.Load("Content/Sounds/startDrone.ogg"); + startDrone = Sound.Load("Content/Sounds/startDrone.ogg", false); startDrone.Play(); yield return CoroutineStatus.Running; - waterAmbiences[0] = Sound.Load("Content/Sounds/Water/WaterAmbience1.ogg"); + waterAmbiences[0] = Sound.Load("Content/Sounds/Water/WaterAmbience1.ogg", false); yield return CoroutineStatus.Running; - waterAmbiences[1] = Sound.Load("Content/Sounds/Water/WaterAmbience2.ogg"); + waterAmbiences[1] = Sound.Load("Content/Sounds/Water/WaterAmbience2.ogg", false); yield return CoroutineStatus.Running; - flowSounds[0] = Sound.Load("Content/Sounds/Water/FlowSmall.ogg"); + flowSounds[0] = Sound.Load("Content/Sounds/Water/FlowSmall.ogg", false); yield return CoroutineStatus.Running; - flowSounds[1] = Sound.Load("Content/Sounds/Water/FlowMedium.ogg"); + flowSounds[1] = Sound.Load("Content/Sounds/Water/FlowMedium.ogg", false); yield return CoroutineStatus.Running; - flowSounds[2] = Sound.Load("Content/Sounds/Water/FlowLarge.ogg"); + flowSounds[2] = Sound.Load("Content/Sounds/Water/FlowLarge.ogg", false); yield return CoroutineStatus.Running; XDocument doc = ToolBox.TryLoadXml("Content/Sounds/sounds.xml"); @@ -124,7 +124,7 @@ namespace Subsurface { yield return CoroutineStatus.Running; - Sound sound = Sound.Load(ToolBox.GetAttributeString(element, "file", "")); + Sound sound = Sound.Load(ToolBox.GetAttributeString(element, "file", ""), false); if (sound == null) continue; DamageSoundType damageSoundType = DamageSoundType.None; @@ -155,13 +155,10 @@ namespace Subsurface { UpdateMusic(); - if (startDrone!=null) + if (startDrone!=null && !startDrone.IsPlaying) { - if (!startDrone.IsPlaying) - { - startDrone.Remove(); - startDrone = null; - } + startDrone.Remove(); + startDrone = null; } float ambienceVolume = 0.6f; diff --git a/Subsurface/Source/Sounds/Sound.cs b/Subsurface/Source/Sounds/Sound.cs index ac74d1272..4e831a597 100644 --- a/Subsurface/Source/Sounds/Sound.cs +++ b/Subsurface/Source/Sounds/Sound.cs @@ -21,6 +21,8 @@ namespace Subsurface string filePath; private int alSourceId; + + private bool destroyOnGameEnd; //public float Volume @@ -28,6 +30,25 @@ namespace Subsurface // set { SoundManager.Volume(sourceIndex, value); } //} + private Sound(string file, bool destroyOnGameEnd) + { + filePath = file; + + foreach (Sound loadedSound in loadedSounds) + { + if (loadedSound.filePath == file) oggSound = loadedSound.oggSound; + } + + if (oggSound == null) + { + oggSound = OggSound.Load(file); + } + + this.destroyOnGameEnd = destroyOnGameEnd; + + loadedSounds.Add(this); + } + public string FilePath { get { return filePath; } @@ -43,32 +64,15 @@ namespace Subsurface SoundManager.Init(); } - public static Sound Load(string file) + public static Sound Load(string file, bool destroyOnGameEnd = true) { if (!File.Exists(file)) { DebugConsole.ThrowError("File ''" + file + "'' not found!"); return null; } - - Sound s = new Sound(); - - s.filePath = file; - - foreach (Sound loadedSound in loadedSounds) - { - if (loadedSound.filePath == file) s.oggSound = loadedSound.oggSound; - } - - if (s.oggSound == null) - { - s.oggSound = OggSound.Load(file); - } - - loadedSounds.Add(s); - - return s; + return new Sound(file, destroyOnGameEnd); } public int Play(float volume = 1.0f) @@ -212,12 +216,27 @@ namespace Subsurface //{ // SoundManager.Stop(this); //} + + public static void OnGameEnd() + { + List removableSounds = loadedSounds.FindAll(s => s.destroyOnGameEnd); + + foreach (Sound sound in removableSounds) + { + sound.Remove(); + } + } public void Remove() { loadedSounds.Remove(this); - System.Diagnostics.Debug.WriteLine(AlBufferId); + System.Diagnostics.Debug.WriteLine("Removing sound " + filePath + " (buffer id" + AlBufferId + ")"); + + if (alSourceId>0 && SoundManager.IsPlaying(alSourceId)) + { + SoundManager.Stop(alSourceId); + } foreach (Sound s in loadedSounds) { diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj index 9ee136e1e..ef3785d5f 100644 --- a/Subsurface/Subsurface.csproj +++ b/Subsurface/Subsurface.csproj @@ -335,6 +335,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Subsurface_Solution.sln b/Subsurface_Solution.sln index 786e0b01e..895b06759 100644 --- a/Subsurface_Solution.sln +++ b/Subsurface_Solution.sln @@ -396,7 +396,4 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection EndGlobal diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 72d4d8b016910d7715e59db6581fd5e92d18480a..4ea7d0b8e3cf504adfac8bfcc8ba5e5664143299 100644 GIT binary patch delta 26531 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 delta 22242 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 rbt1nY3