From db7128a475c017bf010ec05fe572568b33deb1fc Mon Sep 17 00:00:00 2001 From: Regalis Date: Tue, 6 Oct 2015 21:18:36 +0300 Subject: [PATCH] Better autopilot, guiframe tweaking, fixed ui scaling, aicontroller bugfixes, human walk/run anim uses HandIK --- .../Content/Characters/Crawler/crawler.xml | 10 +- Subsurface/Content/Characters/Human/human.xml | 2 +- .../Content/Characters/Mantis/mantis.xml | 16 +- .../Content/Items/Electricity/poweritems.xml | 4 +- Subsurface/Content/Items/Engine/engine.xml | 4 +- Subsurface/Content/Items/Medical/medical.xml | 4 +- Subsurface/Content/Items/Pump/pump.xml | 2 +- Subsurface/Content/Items/Reactor/reactor.xml | 2 +- .../Source/Characters/AI/AIController.cs | 8 +- .../Source/Characters/AI/EnemyAIController.cs | 33 +- Subsurface/Source/Characters/AI/ISteerable.cs | 2 +- .../Source/Characters/AI/SteeringManager.cs | 6 +- .../Source/Characters/AI/SteeringPath.cs | 43 +- Subsurface/Source/Characters/AICharacter.cs | 9 +- .../BackgroundSprite/BackgroundSprite.cs | 4 +- Subsurface/Source/Characters/Character.cs | 16 +- .../Characters/HumanoidAnimController.cs | 454 +++++++++--------- .../Source/Characters/Jobs/JobPrefab.cs | 6 +- Subsurface/Source/Characters/Limb.cs | 2 +- Subsurface/Source/DebugConsole.cs | 7 + Subsurface/Source/GameSession/GameSession.cs | 6 + .../Source/Items/Components/ItemComponent.cs | 15 +- .../Source/Items/Components/Machines/Radar.cs | 25 + .../Items/Components/Machines/Steering.cs | 72 ++- .../Items/Components/Power/PowerContainer.cs | 14 +- .../Items/Components/Power/PowerTransfer.cs | 2 - .../Source/Items/Components/Projectile.cs | 2 +- Subsurface/Source/Map/Levels/Level.cs | 9 +- Subsurface/Source/Map/Submarine.cs | 6 +- Subsurface/Source/Networking/GameClient.cs | 8 +- Subsurface/Source/Screens/GameScreen.cs | 14 +- Subsurface/Source/Screens/MainMenuScreen.cs | 5 +- Subsurface/Source/Screens/NetLobbyScreen.cs | 50 +- Subsurface/Source/Sounds/OggStream.cs | 48 +- Subsurface/Source/Sounds/SoundManager.cs | 4 +- Subsurface/Subsurface.csproj.user | 2 +- Subsurface_Solution.v12.suo | Bin 764416 -> 766464 bytes 37 files changed, 533 insertions(+), 383 deletions(-) diff --git a/Subsurface/Content/Characters/Crawler/crawler.xml b/Subsurface/Content/Characters/Crawler/crawler.xml index f34cde953..7d2b58e22 100644 --- a/Subsurface/Content/Characters/Crawler/crawler.xml +++ b/Subsurface/Content/Characters/Crawler/crawler.xml @@ -14,7 +14,7 @@ flip="true"> - + @@ -28,7 +28,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -44,7 +44,7 @@ - + @@ -52,7 +52,7 @@ - + diff --git a/Subsurface/Content/Characters/Human/human.xml b/Subsurface/Content/Characters/Human/human.xml index 5af2065ec..1494045b1 100644 --- a/Subsurface/Content/Characters/Human/human.xml +++ b/Subsurface/Content/Characters/Human/human.xml @@ -3,7 +3,7 @@ - - + - + - + - + @@ -46,7 +46,7 @@ - + @@ -74,7 +74,7 @@ - + @@ -87,6 +87,6 @@ + attackcooldown="3.0"/> diff --git a/Subsurface/Content/Items/Electricity/poweritems.xml b/Subsurface/Content/Items/Electricity/poweritems.xml index 69a93d797..7e4394ebb 100644 --- a/Subsurface/Content/Items/Electricity/poweritems.xml +++ b/Subsurface/Content/Items/Electricity/poweritems.xml @@ -14,7 +14,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/Subsurface/Content/Items/Engine/engine.xml b/Subsurface/Content/Items/Engine/engine.xml index 3cbef74f4..c1daaaa47 100644 --- a/Subsurface/Content/Items/Engine/engine.xml +++ b/Subsurface/Content/Items/Engine/engine.xml @@ -9,7 +9,7 @@ - + @@ -28,7 +28,7 @@ - + diff --git a/Subsurface/Content/Items/Medical/medical.xml b/Subsurface/Content/Items/Medical/medical.xml index b5910f85d..852c38190 100644 --- a/Subsurface/Content/Items/Medical/medical.xml +++ b/Subsurface/Content/Items/Medical/medical.xml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/Subsurface/Content/Items/Pump/pump.xml b/Subsurface/Content/Items/Pump/pump.xml index 0a1ae3556..04a3b4d25 100644 --- a/Subsurface/Content/Items/Pump/pump.xml +++ b/Subsurface/Content/Items/Pump/pump.xml @@ -6,7 +6,7 @@ - + diff --git a/Subsurface/Content/Items/Reactor/reactor.xml b/Subsurface/Content/Items/Reactor/reactor.xml index 41d310058..74546b500 100644 --- a/Subsurface/Content/Items/Reactor/reactor.xml +++ b/Subsurface/Content/Items/Reactor/reactor.xml @@ -21,7 +21,7 @@ - + diff --git a/Subsurface/Source/Characters/AI/AIController.cs b/Subsurface/Source/Characters/AI/AIController.cs index 577f51a56..6694614d4 100644 --- a/Subsurface/Source/Characters/AI/AIController.cs +++ b/Subsurface/Source/Characters/AI/AIController.cs @@ -1,5 +1,6 @@ using Lidgren.Network; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; namespace Subsurface { @@ -21,7 +22,7 @@ namespace Subsurface set { Character.AnimController.TargetMovement = value; } } - public Vector2 Position + public Vector2 SimPosition { get { return Character.AnimController.Limbs[0].SimPosition; } } @@ -44,6 +45,11 @@ namespace Subsurface steeringManager = new SteeringManager(this); } + public virtual void DebugDraw(SpriteBatch spriteBatch) + { + + } + public virtual void OnAttacked(IDamageable attacker, float amount) { } public virtual void SelectTarget(AITarget target) { } diff --git a/Subsurface/Source/Characters/AI/EnemyAIController.cs b/Subsurface/Source/Characters/AI/EnemyAIController.cs index 6c1547203..ce17b51d2 100644 --- a/Subsurface/Source/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Source/Characters/AI/EnemyAIController.cs @@ -6,6 +6,7 @@ using FarseerPhysics; using Lidgren.Network; using Microsoft.Xna.Framework; using FarseerPhysics.Dynamics; +using Microsoft.Xna.Framework.Graphics; namespace Subsurface { @@ -264,6 +265,9 @@ namespace Subsurface public override void OnAttacked(IDamageable attacker, float amount) { + updateTargetsTimer = Math.Min(updateTargetsTimer, 0.1f); + coolDownTimer *= 0.1f; + if (attacker==null || attacker.AiTarget==null) return; AITargetMemory targetMemory = FindTargetMemory(attacker.AiTarget); targetMemory.Priority += amount; @@ -319,7 +323,7 @@ namespace Subsurface Vector2.Normalize(attackPosition - limb.SimPosition)); } - steeringManager.SteeringSeek(attackPosition + (limb.SimPosition-Position), 5.0f); + steeringManager.SteeringSeek(attackPosition + (limb.SimPosition-SimPosition), 5.0f); break; default: @@ -329,6 +333,7 @@ namespace Subsurface if (attackTimer >= limb.attack.Duration) { + wallAttackPos = Vector2.Zero; attackTimer = 0.0f; if (Vector2.Distance(limb.SimPosition, attackPosition)<5.0) coolDownTimer = attackCoolDown; @@ -477,6 +482,32 @@ namespace Subsurface } } + public override void DebugDraw(SpriteBatch spriteBatch) + { + if (Character.IsDead) return; + + Vector2 pos = Character.Position; + pos.Y = -pos.Y; + + if (selectedAiTarget!=null) + { + GUI.DrawLine(spriteBatch, pos, ConvertUnits.ToDisplayUnits(new Vector2(selectedAiTarget.Position.X, -selectedAiTarget.Position.Y)), Color.Red); + + if (wallAttackPos!=Vector2.Zero) + { + GUI.DrawRectangle(spriteBatch, ConvertUnits.ToDisplayUnits(new Vector2(wallAttackPos.X, -wallAttackPos.Y)) - new Vector2(10.0f, 10.0f), new Vector2(20.0f, 20.0f), Color.Red, false); + } + + spriteBatch.DrawString(GUI.Font, targetValue.ToString(), pos - Vector2.UnitY*20.0f, Color.Red); + + } + + spriteBatch.DrawString(GUI.Font, targetValue.ToString(), pos - Vector2.UnitY * 80.0f, Color.Red); + + spriteBatch.DrawString(GUI.Font, "updatetargets: "+updateTargetsTimer, pos - Vector2.UnitY * 100.0f, Color.Red); + spriteBatch.DrawString(GUI.Font, "cooldown: " + coolDownTimer, pos - Vector2.UnitY * 120.0f, Color.Red); + } + public override void FillNetworkData(NetOutgoingMessage message) { message.Write((byte)state); diff --git a/Subsurface/Source/Characters/AI/ISteerable.cs b/Subsurface/Source/Characters/AI/ISteerable.cs index fbea7c827..3a4ec5379 100644 --- a/Subsurface/Source/Characters/AI/ISteerable.cs +++ b/Subsurface/Source/Characters/AI/ISteerable.cs @@ -16,7 +16,7 @@ namespace Subsurface get; } - Vector2 Position + Vector2 SimPosition { get; } diff --git a/Subsurface/Source/Characters/AI/SteeringManager.cs b/Subsurface/Source/Characters/AI/SteeringManager.cs index f63e29f44..7ac461f44 100644 --- a/Subsurface/Source/Characters/AI/SteeringManager.cs +++ b/Subsurface/Source/Characters/AI/SteeringManager.cs @@ -63,7 +63,7 @@ namespace Subsurface private Vector2 DoSteeringSeek(Vector2 target, float speed = 1.0f) { - Vector2 targetVel = target - host.Position; + Vector2 targetVel = target - host.SimPosition; if (targetVel.LengthSquared() < 0.00001f) return Vector2.Zero; @@ -111,12 +111,12 @@ namespace Subsurface float maxDistance = 2.0f; - Vector2 ahead = host.Position + Vector2.Normalize(host.Steering)*maxDistance; + Vector2 ahead = host.SimPosition + Vector2.Normalize(host.Steering)*maxDistance; if (rayCastTimer <= 0.0f) { rayCastTimer = RayCastInterval; - Body closestBody = Submarine.CheckVisibility(host.Position, ahead); + Body closestBody = Submarine.CheckVisibility(host.SimPosition, ahead); if (closestBody == null) { avoidSteering = Vector2.Zero; diff --git a/Subsurface/Source/Characters/AI/SteeringPath.cs b/Subsurface/Source/Characters/AI/SteeringPath.cs index d88ba2106..125fff3e9 100644 --- a/Subsurface/Source/Characters/AI/SteeringPath.cs +++ b/Subsurface/Source/Characters/AI/SteeringPath.cs @@ -5,32 +5,55 @@ namespace Subsurface { class SteeringPath { - private Queue nodes; - - WayPoint currentNode; + private List nodes; + + int currentIndex; public SteeringPath() { - nodes = new Queue(); + nodes = new List(); } public void AddNode(WayPoint node) { if (node == null) return; - nodes.Enqueue(node); + nodes.Add(node); } public WayPoint CurrentNode { - get { return currentNode; } + get + { + if (currentIndex < 0 || currentIndex > nodes.Count - 1) return null; + return nodes[currentIndex]; + } } - public WayPoint GetNode(Vector2 pos, float minDistance = 0.1f) + public List Nodes { - if (nodes.Count == 0) return null; - if (currentNode == null || Vector2.Distance(pos, currentNode.SimPosition) < minDistance) currentNode = nodes.Dequeue(); + get { return nodes; } + } - return currentNode; + public WayPoint NextNode + { + get + { + if (currentIndex+1 < 0 || currentIndex+1 > nodes.Count - 1) return null; + return nodes[currentIndex+1]; + } + } + + public void SkipToNextNode() + { + currentIndex++; + } + + public WayPoint CheckProgress(Vector2 pos, float minSimDistance = 0.1f) + { + if (nodes.Count == 0 || currentIndex>nodes.Count-1) return null; + if (Vector2.Distance(pos, nodes[currentIndex].SimPosition) < minSimDistance) currentIndex++; + + return CurrentNode; } public void ClearPath() diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index 1b6297fc5..90b78a7c7 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -59,6 +59,13 @@ namespace Subsurface aiController.Update(deltaTime); } + public override void DrawFront(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) + { + base.DrawFront(spriteBatch); + + if (GameMain.DebugDraw) aiController.DebugDraw(spriteBatch); + } + public override AttackResult AddDamage(IDamageable attacker, Vector2 position, Attack attack, float deltaTime, bool playSound = false) { AttackResult result = base.AddDamage(attacker, position, attack, deltaTime, playSound); @@ -113,7 +120,7 @@ namespace Subsurface LargeUpdateTimer = Math.Max(0, LargeUpdateTimer - 1); } } - + public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) { if (type == NetworkEventType.KillCharacter) diff --git a/Subsurface/Source/Characters/BackgroundSprite/BackgroundSprite.cs b/Subsurface/Source/Characters/BackgroundSprite/BackgroundSprite.cs index a00c2f2c0..9a80cc56e 100644 --- a/Subsurface/Source/Characters/BackgroundSprite/BackgroundSprite.cs +++ b/Subsurface/Source/Characters/BackgroundSprite/BackgroundSprite.cs @@ -37,7 +37,7 @@ namespace Subsurface get { return drawPosition; } } - public Vector2 Position + public Vector2 SimPosition { get { return position; } } @@ -179,7 +179,7 @@ namespace Subsurface foreach (BackgroundSprite member in Members) { - midPoint += member.Position; + midPoint += member.SimPosition; } midPoint /= Members.Count; diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 4fd273ae8..332f0ce47 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -72,7 +72,7 @@ namespace Subsurface protected bool isDead; - bool isHumanoid; + public readonly bool IsHumanoid; //the name of the species (e.q. human) public readonly string SpeciesName; @@ -200,7 +200,7 @@ namespace Subsurface get { return bleeding; } set { - if (MathUtils.IsValid(value)) return; + if (!MathUtils.IsValid(value)) return; bleeding = Math.Max(value, 0.0f); } } @@ -344,9 +344,9 @@ namespace Subsurface SpeciesName = ToolBox.GetAttributeString(doc.Root, "name", "Unknown"); - isHumanoid = ToolBox.GetAttributeBool(doc.Root, "humanoid", false); + IsHumanoid = ToolBox.GetAttributeBool(doc.Root, "humanoid", false); - if (isHumanoid) + if (IsHumanoid) { AnimController = new HumanoidAnimController(this, doc.Root.Element("ragdoll")); AnimController.TargetDir = Direction.Right; @@ -660,7 +660,7 @@ namespace Subsurface if (closestCharacter != null) { if (closestCharacter != selectedCharacter) selectedCharacter = null; - if (!closestCharacter.isHumanoid) closestCharacter = null; + if (!closestCharacter.IsHumanoid) closestCharacter = null; } closestItem = FindClosestItem(mouseSimPos); @@ -706,7 +706,7 @@ namespace Subsurface { selectedCharacter = null; } - else if (closestCharacter != null && closestCharacter.isDead && closestCharacter.isHumanoid) + else if (closestCharacter != null && closestCharacter.isDead && closestCharacter.IsHumanoid) { selectedCharacter = closestCharacter; } @@ -758,7 +758,7 @@ namespace Subsurface ControlLocalPlayer(deltaTime, cam); } - Control(deltaTime, cam); + if (!(this is AICharacter)) Control(deltaTime, cam); UpdateSightRange(); aiTarget.SoundRange = 0.0f; @@ -820,7 +820,7 @@ namespace Subsurface CharacterHUD.Draw(spriteBatch, this, cam); } - public void DrawFront(SpriteBatch spriteBatch) + public virtual void DrawFront(SpriteBatch spriteBatch) { Vector2 pos = ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); pos.Y = -pos.Y; diff --git a/Subsurface/Source/Characters/HumanoidAnimController.cs b/Subsurface/Source/Characters/HumanoidAnimController.cs index 1cbd69add..fcb959d86 100644 --- a/Subsurface/Source/Characters/HumanoidAnimController.cs +++ b/Subsurface/Source/Characters/HumanoidAnimController.cs @@ -30,14 +30,9 @@ namespace Subsurface public override void UpdateAnim(float deltaTime) { - if (character.IsDead) return; - - Vector2 colliderPos = GetLimb(LimbType.Torso).SimPosition; + if (character.IsDead) return; - if (!MathUtils.IsValid(RefLimb.body.SimPosition)) - { - int a = 1; - } + Vector2 colliderPos = GetLimb(LimbType.Torso).SimPosition; //if (inWater) stairs = null; @@ -57,7 +52,7 @@ namespace Subsurface case Physics.CollisionStairs: if (inWater && TargetMovement.Y < 0.5f) return -1; Structure structure = fixture.Body.UserData as Structure; - if (stairs == null && structure!=null) + if (stairs == null && structure != null) { if (LowestLimb.SimPosition.Y < structure.SimPosition.Y) { @@ -70,7 +65,7 @@ namespace Subsurface } break; case Physics.CollisionPlatform: - Structure platform = fixture.Body.UserData as Structure; + Structure platform = fixture.Body.UserData as Structure; if (IgnorePlatforms || LowestLimb.Position.Y < platform.Rect.Y) return -1; break; case Physics.CollisionWall: @@ -118,12 +113,12 @@ namespace Subsurface if (closestFraction == 1) //raycast didn't hit anything { floorY = (currentHull == null) ? -1000.0f : ConvertUnits.ToSimUnits(currentHull.Rect.Y - currentHull.Rect.Height); - } + } else { floorY = rayStart.Y + (rayEnd.Y - rayStart.Y) * closestFraction; } - + IgnorePlatforms = (TargetMovement.Y < 0.0f); @@ -175,18 +170,20 @@ namespace Subsurface aiming = false; } - + void UpdateStanding() { Vector2 handPos; + //if you're allergic to magic numbers, stop reading now + Limb leftFoot = GetLimb(LimbType.LeftFoot); Limb rightFoot = GetLimb(LimbType.RightFoot); Limb head = GetLimb(LimbType.Head); Limb torso = GetLimb(LimbType.Torso); - Limb waist = GetLimb(LimbType.Waist); + Limb waist = GetLimb(LimbType.Waist); Limb leftHand = GetLimb(LimbType.LeftHand); Limb rightHand = GetLimb(LimbType.RightHand); @@ -198,31 +195,31 @@ namespace Subsurface float walkCycleSpeed = head.LinearVelocity.X * walkAnimSpeed; if (stairs != null) { - TargetMovement = new Vector2(MathHelper.Clamp(TargetMovement.X, -2.0f, 2.0f), TargetMovement.Y) ; + TargetMovement = new Vector2(MathHelper.Clamp(TargetMovement.X, -1.5f, 1.5f), TargetMovement.Y); - if ((TargetMovement.X>0.0f && stairs.StairDirection == Direction.Right) || + if ((TargetMovement.X > 0.0f && stairs.StairDirection == Direction.Right) || TargetMovement.X < 0.0f && stairs.StairDirection == Direction.Left) { - TargetMovement *= 1.35f; + TargetMovement *= 1.7f; + walkCycleSpeed *= 1.7f; } - else + else { - TargetMovement /= 1.2f; - } - - walkCycleSpeed *= 1.5f; + TargetMovement /= 1.0f; + walkCycleSpeed *= 1.5f; + } } Vector2 colliderPos = new Vector2(torso.SimPosition.X, floorY); float walkPosX = (float)Math.Cos(walkPos); float walkPosY = (float)Math.Sin(walkPos); - float runningModifier = (float)Math.Max(Math.Abs(movement.X) / 1.5f, 1.0); + float runningModifier = (float)Math.Max(Math.Abs(TargetMovement.X) / 1.5f, 1.0); Vector2 stepSize = new Vector2( this.stepSize.X * walkPosX * runningModifier, this.stepSize.Y * walkPosY * runningModifier * runningModifier); - + float footMid = waist.SimPosition.X;// (leftFoot.SimPosition.X + rightFoot.SimPosition.X) / 2.0f; int limbsInWater = 0; @@ -231,184 +228,169 @@ namespace Subsurface if (limb.inWater) limbsInWater++; } - TargetMovement *= (1.0f - 0.5f*((float)limbsInWater/(float)Limbs.Count())); + TargetMovement *= (1.0f - 0.5f * ((float)limbsInWater / (float)Limbs.Count())); movement = MathUtils.SmoothStep(movement, TargetMovement, movementLerp); movement.Y = 0.0f; - - - //place the anchors of the head and the torso to make the ragdoll stand - if (onGround && LowestLimb != null && (LowestLimb.SimPosition.Y-floorY < 0.5f || stairs != null) && head !=null) + for (int i = 0; i < 2; i++) { - getUpSpeed = getUpSpeed * (head.SimPosition.Y - colliderPos.Y);//, 0.25f); + Limb leg = GetLimb((i == 0) ? LimbType.LeftThigh : LimbType.RightThigh);// : leftLeg; - if (stairs != null) - { - if (LowestLimb.SimPosition.Y < stairs.SimPosition.Y) IgnorePlatforms = true; - - torso.pullJoint.Enabled = true; - torso.pullJoint.WorldAnchorB = new Vector2( - MathHelper.SmoothStep(torso.SimPosition.X, footMid + movement.X * 0.35f, getUpSpeed * 0.8f), - MathHelper.SmoothStep(torso.SimPosition.Y, colliderPos.Y + TorsoPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 3.0f)); + if (leg.SimPosition.Y < torso.SimPosition.Y) continue; - - head.pullJoint.Enabled = true; - head.pullJoint.WorldAnchorB = new Vector2( - MathHelper.SmoothStep(head.SimPosition.X, footMid + movement.X * 0.4f, getUpSpeed * 0.8f), - MathHelper.SmoothStep(head.SimPosition.Y, colliderPos.Y + HeadPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 3.0f)); - } - else - { - torso.pullJoint.Enabled = true; - torso.pullJoint.WorldAnchorB = - MathUtils.SmoothStep(torso.SimPosition, - new Vector2(footMid + movement.X * 0.3f, colliderPos.Y + TorsoPosition), getUpSpeed); - - head.pullJoint.Enabled = true; - head.pullJoint.WorldAnchorB = - MathUtils.SmoothStep(head.SimPosition, - new Vector2(footMid + movement.X * (0.2f + runningModifier / 10.0f), colliderPos.Y + HeadPosition), getUpSpeed); - - waist.pullJoint.Enabled = true; - waist.pullJoint.WorldAnchorB = waist.SimPosition + movement*0.1f; - //MathUtils.SmoothStep(waist.SimPosition, - //new Vector2(footMid + movement.X * 0.4f, colliderPos.Y + HeadPosition), getUpSpeed); - } - - - //moving horizontally - if (TargetMovement.X != 0.0f) - { - //progress the walking animation - walkPos -= (walkCycleSpeed / runningModifier)*0.8f; - - MoveLimb(leftFoot, - colliderPos + new Vector2( - stepSize.X, - (stepSize.Y > 0.0f) ? stepSize.Y : -0.15f), - 15.0f, true); - - MoveLimb(rightFoot, - colliderPos + new Vector2( - -stepSize.X, - (-stepSize.Y > 0.0f) ? -stepSize.Y : -0.15f), - 15.0f, true); - - leftFoot.body.SmoothRotate(leftLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier); - rightFoot.body.SmoothRotate(rightLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier); - - if (runningModifier>1.0f) - { - if (walkPosY > 0.0f) - { - GetLimb(LimbType.LeftThigh).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * thighTorque); - } - else - { - GetLimb(LimbType.RightThigh).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * thighTorque); - } - } - - if (legTorque>0.0f) - { - if (Math.Sign(walkPosX) != Math.Sign(movement.X)) - { - GetLimb(LimbType.LeftLeg).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier); - } - else - { - GetLimb(LimbType.RightLeg).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier); - } - } - - //calculate the positions of hands - handPos = torso.SimPosition; - handPos.X = -walkPosX * 0.2f;// *runningModifier; - - float lowerY = -0.6f + runningModifier/3.5f; - - handPos.Y = lowerY + (float)(Math.Abs(Math.Sin(walkPos - Math.PI * 1.5f) * 0.05)) / runningModifier; - - Vector2 posAdditon = new Vector2(movement.X*0.07f, 0.0f); - if (stairs!=null) - { - if ((stairs.StairDirection == Direction.Right && movement.X < 0.0f) || - (stairs.StairDirection == Direction.Left && movement.X > 0.0f)) - { - posAdditon.Y -= 0.1f; - } - else - { - posAdditon.Y += 0.1f; - } - } - - if (!rightHand.Disabled) - { - rightHand.body.ApplyTorque(walkPosY * runningModifier * Dir); - MoveLimb(rightHand, torso.SimPosition + posAdditon + - new Vector2( - -handPos.X, - (Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), - 15.0f, true); - } - - if (!leftHand.Disabled) - { - leftHand.body.ApplyTorque(-walkPosY * runningModifier * Dir); - MoveLimb(leftHand, torso.SimPosition + posAdditon + - new Vector2( - handPos.X, - (Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), - 15.0f, true); - } - - } - else - { - float movementFactor = (movement.X / 4.0f) * movement.X * Math.Sign(movement.X); - - Vector2 footPos = new Vector2( - colliderPos.X + movementFactor - Dir * 0.05f, - colliderPos.Y - 0.2f - Math.Abs(movementFactor)); - - MoveLimb(leftFoot, footPos, 2.5f); - MoveLimb(rightFoot, footPos, 2.5f); - - leftFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 5.0f); - rightFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 5.0f); - - if (!rightHand.Disabled) - { - // MoveLimb(rightHand, handPos, 0.05f, true); - //rightHand.body.ApplyLinearImpulse((handPos - rightHand.Position)); - rightHand.body.SmoothRotate(0.0f, 5.0f); - - var rightArm = GetLimb(LimbType.RightArm); - rightArm.body.SmoothRotate(0.0f, 20.0f); - } - - if (!leftHand.Disabled) - { - //MoveLimb(leftHand, handPos, 0.05f, true); - //leftHand.body.ApplyLinearImpulse((handPos - leftHand.Position)); - leftHand.body.SmoothRotate(0.0f, 5.0f); - - var leftArm = GetLimb(LimbType.LeftArm); - leftArm.body.SmoothRotate(0.0f, 20.0f); - } - } + leg.body.ApplyTorque(-Dir * leg.Mass * 10.0f); } - //for (int i = 0; i < 2; i++) - //{ - // Limb leg = (i == 0) ? rightLeg : leftLeg; + //place the anchors of the head and the torso to make the ragdoll stand - // if (leg.SimPosition.Y < waist.SimPosition.Y) continue; + if (LowestLimb == null) return; + + if (!onGround || (LowestLimb.SimPosition.Y - floorY > 0.5f && stairs == null)) return; + + getUpSpeed = getUpSpeed * (head.SimPosition.Y - colliderPos.Y); + + if (stairs != null) + { + if (LowestLimb.SimPosition.Y < stairs.SimPosition.Y) IgnorePlatforms = true; + + torso.pullJoint.Enabled = true; + torso.pullJoint.WorldAnchorB = new Vector2( + MathHelper.SmoothStep(torso.SimPosition.X, footMid + movement.X * 0.35f, getUpSpeed * 0.8f), + MathHelper.SmoothStep(torso.SimPosition.Y, colliderPos.Y + TorsoPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 2.0f)); + + + head.pullJoint.Enabled = true; + head.pullJoint.WorldAnchorB = new Vector2( + MathHelper.SmoothStep(head.SimPosition.X, footMid + movement.X * 0.4f, getUpSpeed * 0.8f), + MathHelper.SmoothStep(head.SimPosition.Y, colliderPos.Y + HeadPosition - Math.Abs(walkPosX * 0.05f), getUpSpeed * 2.0f)); + + waist.pullJoint.Enabled = true; + waist.pullJoint.WorldAnchorB = waist.SimPosition;// +movement * 0.3f; + } + else + { + torso.pullJoint.Enabled = true; + torso.pullJoint.WorldAnchorB = + MathUtils.SmoothStep(torso.SimPosition, + new Vector2(footMid + movement.X * 0.3f, colliderPos.Y + TorsoPosition), getUpSpeed); + + + head.pullJoint.Enabled = true; + head.pullJoint.WorldAnchorB = + MathUtils.SmoothStep(head.SimPosition, + new Vector2(footMid + movement.X * 0.3f, colliderPos.Y + HeadPosition), getUpSpeed*1.2f); + + waist.pullJoint.Enabled = true; + waist.pullJoint.WorldAnchorB = waist.SimPosition + movement * 0.1f; + //MathUtils.SmoothStep(waist.SimPosition, + //new Vector2(footMid + movement.X * 0.4f, colliderPos.Y + HeadPosition), getUpSpeed); + } + + + //moving horizontally + if (TargetMovement.X != 0.0f) + { + //progress the walking animation + walkPos -= (walkCycleSpeed / runningModifier) * 0.8f; + + MoveLimb(leftFoot, + colliderPos + new Vector2( + stepSize.X, + (stepSize.Y > 0.0f) ? stepSize.Y : -0.15f), + 15.0f, true); + + MoveLimb(rightFoot, + colliderPos + new Vector2( + -stepSize.X, + (-stepSize.Y > 0.0f) ? -stepSize.Y : -0.15f), + 15.0f, true); + + leftFoot.body.SmoothRotate(leftLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier); + rightFoot.body.SmoothRotate(rightLeg.body.Rotation + MathHelper.PiOver2 * Dir * 1.6f, 20.0f * runningModifier); + + if (runningModifier > 1.0f) + { + if (walkPosY > 0.0f) + { + GetLimb(LimbType.LeftThigh).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * thighTorque); + } + else + { + GetLimb(LimbType.RightThigh).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * thighTorque); + } + } + + if (legTorque > 0.0f) + { + if (Math.Sign(walkPosX) != Math.Sign(movement.X)) + { + GetLimb(LimbType.LeftLeg).body.ApplyTorque(-walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier); + } + else + { + GetLimb(LimbType.RightLeg).body.ApplyTorque(walkPosY * Dir * Math.Abs(movement.X) * legTorque / runningModifier); + } + } + + //calculate the positions of hands + handPos = torso.SimPosition; + handPos.X = -walkPosX * 0.4f; + + float lowerY = -1.0f + (runningModifier - 1.0f) * 0.8f; + + handPos.Y = lowerY + (float)(Math.Abs(Math.Sin(walkPos - Math.PI * 1.5f) * 0.15 * runningModifier)); + + Vector2 posAddition = new Vector2(-movement.X * 0.015f * runningModifier, 0.0f); + + if (!rightHand.Disabled) + { + HandIK(rightHand, torso.SimPosition + posAddition + + new Vector2( + -handPos.X, + (Math.Sign(walkPosX) == Math.Sign(Dir)) ? handPos.Y : lowerY), 0.7f*runningModifier); + } + + if (!leftHand.Disabled) + { + HandIK(leftHand, torso.SimPosition + posAddition + + new Vector2( + handPos.X, + (Math.Sign(walkPosX) == Math.Sign(-Dir)) ? handPos.Y : lowerY), 0.7f * runningModifier); + } + + } + else + { + float movementFactor = (movement.X / 4.0f) * movement.X * Math.Sign(movement.X); + + Vector2 footPos = new Vector2( + colliderPos.X, + colliderPos.Y - 0.2f); + + MoveLimb(leftFoot, footPos, 2.5f); + MoveLimb(rightFoot, footPos, 2.5f); + + leftFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 5.0f); + rightFoot.body.SmoothRotate(Dir * MathHelper.PiOver2, 5.0f); + + if (!rightHand.Disabled) + { + rightHand.body.SmoothRotate(0.0f, 5.0f); + + var rightArm = GetLimb(LimbType.RightArm); + rightArm.body.SmoothRotate(0.0f, 20.0f); + } + + if (!leftHand.Disabled) + { + leftHand.body.SmoothRotate(0.0f, 5.0f); + + var leftArm = GetLimb(LimbType.LeftArm); + leftArm.body.SmoothRotate(0.0f, 20.0f); + } + } - // //leg.body.ApplyTorque(Dir * leg.Mass * 50.0f); - //} } @@ -416,23 +398,23 @@ namespace Subsurface { movement = MathUtils.SmoothStep(movement, TargetMovement, movementLerp); - if (inWater && movement.LengthSquared()>0.00001f) + if (inWater && movement.LengthSquared() > 0.00001f) { movement = Vector2.Normalize(movement); } - + RefLimb.pullJoint.Enabled = true; RefLimb.pullJoint.WorldAnchorB = - RefLimb.SimPosition + movement*0.15f; + RefLimb.SimPosition + movement * 0.15f; RefLimb.body.SmoothRotate(0.0f); foreach (Limb l in Limbs) { - if (l==RefLimb) continue; + if (l == RefLimb) continue; l.body.SetTransform(RefLimb.SimPosition, RefLimb.Rotation); } - //new Vector2(movement.X, floorY + HeadPosition), 0.5f); + //new Vector2(movement.X, floorY + HeadPosition), 0.5f); } void UpdateSwimming() @@ -447,20 +429,20 @@ namespace Subsurface if (currentHull != null && (currentHull.Rect.Y - currentHull.Surface > 50.0f) && !head.inWater) { - surfaceLimiter = (ConvertUnits.ToDisplayUnits(head.SimPosition.Y)-surfaceY); + surfaceLimiter = (ConvertUnits.ToDisplayUnits(head.SimPosition.Y) - surfaceY); surfaceLimiter = Math.Max(1.0f, surfaceLimiter); if (surfaceLimiter > 20.0f) return; } - Limb torso = GetLimb(LimbType.Torso); - Limb leftHand = GetLimb(LimbType.LeftHand); - Limb rightHand = GetLimb(LimbType.RightHand); + Limb torso = GetLimb(LimbType.Torso); + Limb leftHand = GetLimb(LimbType.LeftHand); + Limb rightHand = GetLimb(LimbType.RightHand); + + Limb leftFoot = GetLimb(LimbType.LeftFoot); + Limb rightFoot = GetLimb(LimbType.RightFoot); + Limb leftLeg = GetLimb(LimbType.LeftLeg); + Limb rightLeg = GetLimb(LimbType.RightLeg); - Limb leftFoot = GetLimb(LimbType.LeftFoot); - Limb rightFoot = GetLimb(LimbType.RightFoot); - Limb leftLeg = GetLimb(LimbType.LeftLeg); - Limb rightLeg = GetLimb(LimbType.RightLeg); - float rotation = MathHelper.WrapAngle(torso.Rotation); rotation = MathHelper.ToDegrees(rotation); if (rotation < 0.0f) rotation += 360; @@ -475,12 +457,12 @@ namespace Subsurface float targetSpeed = TargetMovement.Length(); if (targetSpeed > 0.0f) TargetMovement /= targetSpeed; - + if (targetSpeed > 0.1f) { if (!aiming) { - torso.body.SmoothRotate(MathUtils.VectorToAngle(TargetMovement)-MathHelper.PiOver2); + torso.body.SmoothRotate(MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2); } } else @@ -526,7 +508,7 @@ namespace Subsurface movement.Y -= 0.05f; head.body.ApplyForce((new Vector2(movement.X, - movement.Y / surfaceLimiter + 0.2f) - head.body.LinearVelocity * 0.2f) * + movement.Y / surfaceLimiter + 0.2f) - head.body.LinearVelocity * 0.2f) * 30.0f * head.body.Mass); torso.body.ApplyForce((new Vector2(movement.X, @@ -546,7 +528,7 @@ namespace Subsurface transformedFootPos, Matrix.CreateRotationZ(torso.body.Rotation)); - if (Math.Abs(MathUtils.GetShortestAngle(torso.Rotation, rightThigh.Rotation))<0.3f) + if (Math.Abs(MathUtils.GetShortestAngle(torso.Rotation, rightThigh.Rotation)) < 0.3f) { MoveLimb(rightFoot, footPos - transformedFootPos, 1.0f); } @@ -554,14 +536,14 @@ namespace Subsurface { MoveLimb(leftFoot, footPos + transformedFootPos, 1.0f); } - + handPos = (torso.SimPosition + head.SimPosition) / 2.0f; //if (!rightHand.Disabled) rightHand.body.ApplyTorque(leftHand.body.Mass * Dir); //if (!leftHand.Disabled) leftHand.body.ApplyTorque(leftHand.body.Mass * Dir); - + //at the surface, not moving sideways -> hands just float around - if (!headInWater && TargetMovement.X == 0.0f && TargetMovement.Y>0) + if (!headInWater && TargetMovement.X == 0.0f && TargetMovement.Y > 0) { handPos.X = handPos.X + Dir * 0.6f; @@ -612,12 +594,12 @@ namespace Subsurface //MoveLimb(leftHand, handPos + leftHandPos,1.5f); HandIK(leftHand, handPos + leftHandPos, 0.5f); - } + } } void UpdateClimbing() { - if (character.SelectedConstruction == null || character.SelectedConstruction.GetComponent()==null) + if (character.SelectedConstruction == null || character.SelectedConstruction.GetComponent() == null) { Anim = Animation.None; return; @@ -630,15 +612,15 @@ namespace Subsurface Vector2 footPos, handPos; - Limb leftFoot = GetLimb(LimbType.LeftFoot); - Limb rightFoot = GetLimb(LimbType.RightFoot); - Limb head = GetLimb(LimbType.Head); - Limb torso = GetLimb(LimbType.Torso); + Limb leftFoot = GetLimb(LimbType.LeftFoot); + Limb rightFoot = GetLimb(LimbType.RightFoot); + Limb head = GetLimb(LimbType.Head); + Limb torso = GetLimb(LimbType.Torso); - Limb waist = GetLimb(LimbType.Waist); + Limb waist = GetLimb(LimbType.Waist); - Limb leftHand = GetLimb(LimbType.LeftHand); - Limb rightHand = GetLimb(LimbType.RightHand); + Limb leftHand = GetLimb(LimbType.LeftHand); + Limb rightHand = GetLimb(LimbType.RightHand); Vector2 ladderSimPos = ConvertUnits.ToSimUnits( character.SelectedConstruction.Rect.X + character.SelectedConstruction.Rect.Width / 2.0f, @@ -668,7 +650,7 @@ namespace Subsurface rightHand.body.ApplyTorque(Dir * 2.0f); footPos = new Vector2( - handPos.X - Dir*0.05f, + handPos.X - Dir * 0.05f, head.SimPosition.Y - stepHeight * 2.7f - ladderSimPos.Y - 0.7f); //if (movement.Y < 0) footPos.Y += 0.05f; @@ -712,7 +694,7 @@ namespace Subsurface // - reached the top or bottom of the ladder if (Math.Abs(torso.LinearVelocity.Y) > 5.0f || TargetMovement.X != 0.0f || - (TargetMovement.Y < 0.0f && ConvertUnits.ToSimUnits(trigger.Height) + handPos.Y < HeadPosition*1.5f) || + (TargetMovement.Y < 0.0f && ConvertUnits.ToSimUnits(trigger.Height) + handPos.Y < HeadPosition * 1.5f) || (TargetMovement.Y > 0.0f && handPos.Y > 0.3f)) { Anim = Animation.None; @@ -721,7 +703,7 @@ namespace Subsurface } } - + //float punchTimer; //bool punching; @@ -777,12 +759,12 @@ namespace Subsurface transformedHandlePos[0] = Vector2.Transform(handlePos[0], itemTransfrom); transformedHandlePos[1] = Vector2.Transform(handlePos[1], itemTransfrom); - Limb head = GetLimb(LimbType.Head); - Limb torso = GetLimb(LimbType.Torso); - Limb leftHand = GetLimb(LimbType.LeftHand); - Limb rightHand = GetLimb(LimbType.RightHand); + Limb head = GetLimb(LimbType.Head); + Limb torso = GetLimb(LimbType.Torso); + Limb leftHand = GetLimb(LimbType.LeftHand); + Limb rightHand = GetLimb(LimbType.RightHand); - Vector2 itemPos = aim ? aimPos : holdPos; + Vector2 itemPos = aim ? aimPos : holdPos; float itemAngle; if (stunTimer <= 0.0f && aim && itemPos != Vector2.Zero) @@ -810,7 +792,7 @@ namespace Subsurface { itemAngle = (torso.body.Rotation + holdAngle * Dir); } - + Vector2 shoulderPos = limbJoints[2].WorldAnchorA; Vector2 transformedHoldPos = shoulderPos; @@ -847,7 +829,7 @@ namespace Subsurface } Vector2 bodyVelocity = torso.body.LinearVelocity / 60.0f; - + item.body.ResetDynamics(); item.body.SetTransform(MathUtils.SmoothStep(item.body.SimPosition, transformedHoldPos + bodyVelocity, 0.5f), itemAngle); @@ -859,7 +841,7 @@ namespace Subsurface Limb hand = (i == 0) ? rightHand : leftHand; HandIK(hand, transformedHoldPos + transformedHandlePos[i]); - } + } } private void HandIK(Limb hand, Vector2 pos, float force = 1.0f) @@ -883,20 +865,22 @@ namespace Subsurface float armAngle = MathUtils.SolveTriangleSSS(a, b, c); float handAngle = MathUtils.SolveTriangleSSS(b, a, c); - arm.body.SmoothRotate((ang2 - armAngle * Dir), 20.0f*force); - hand.body.SmoothRotate((ang2 + handAngle * Dir), 100.0f*force); + arm.body.SmoothRotate((ang2 - armAngle * Dir), 20.0f * force); + hand.body.SmoothRotate((ang2 + handAngle * Dir), 100.0f * force); } public override void Flip() { base.Flip(); + walkPos = -walkPos; + Limb torso = GetLimb(LimbType.Torso); Vector2 difference; Matrix torsoTransform = Matrix.CreateRotationZ(torso.Rotation); - + for (int i = 0; i < character.SelectedItems.Length; i++) { if (character.SelectedItems[i] != null) @@ -926,7 +910,7 @@ namespace Subsurface l.body.SetTransform(torso.SimPosition + Vector2.Transform(difference, -torsoTransform), -l.body.Rotation); break; default: - if (!inWater) l.body.SetTransform(l.body.SimPosition, + if (!inWater) l.body.SetTransform(l.body.SimPosition, MathUtils.WrapAnglePi(l.body.Rotation * (l.DoesFlip ? -1.0f : 1.0f))); break; } diff --git a/Subsurface/Source/Characters/Jobs/JobPrefab.cs b/Subsurface/Source/Characters/Jobs/JobPrefab.cs index af0919b85..004bdb8d3 100644 --- a/Subsurface/Source/Characters/Jobs/JobPrefab.cs +++ b/Subsurface/Source/Characters/Jobs/JobPrefab.cs @@ -103,7 +103,9 @@ namespace Subsurface { int width = 500, height = 400; - GUIFrame frame = new GUIFrame(new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), GUI.Style); + GUIFrame backFrame = new GUIFrame(Rectangle.Empty, Color.Black*0.5f); + + GUIFrame frame = new GUIFrame(new Rectangle(GameMain.GraphicsWidth / 2 - width / 2, GameMain.GraphicsHeight / 2 - height / 2, width, height), GUI.Style, backFrame); frame.Padding = new Vector4(30.0f, 30.0f, 30.0f, 30.0f); new GUITextBlock(new Rectangle(0,0,100,20), name, GUI.Style, Alignment.TopLeft, Alignment.TopLeft, frame, false, GUI.LargeFont); @@ -142,7 +144,7 @@ namespace Subsurface - return frame; + return backFrame; } public static void LoadAll(List filePaths) diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index f74c5b15d..be0580bb6 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -193,7 +193,7 @@ namespace Subsurface body.CollidesWith = Physics.CollisionAll & ~Physics.CollisionCharacter & ~Physics.CollisionMisc; } - impactTolerance = ToolBox.GetAttributeFloat(element, "impacttolerance", 10.0f); + impactTolerance = ToolBox.GetAttributeFloat(element, "impacttolerance", character.IsHumanoid ? 15.0f : 50.0f); body.UserData = this; diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index 8cff35e83..796d37b65 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -212,6 +212,13 @@ namespace Subsurface case "editchar": GameMain.EditCharacterScreen.Select(); break; + case "heal": + if (Character.Controlled!=null) + { + Character.Controlled.Health = Character.Controlled.MaxHealth; + Character.Controlled.Bleeding = 0.0f; + } + break; case "freecamera": case "freecam": Character.Controlled = null; diff --git a/Subsurface/Source/GameSession/GameSession.cs b/Subsurface/Source/GameSession/GameSession.cs index 641f711a7..7e9df144b 100644 --- a/Subsurface/Source/GameSession/GameSession.cs +++ b/Subsurface/Source/GameSession/GameSession.cs @@ -111,6 +111,12 @@ namespace Subsurface this.level = level; + if (submarine==null) + { + DebugConsole.ThrowError("Couldn't start game session, submarine not selected"); + return; + } + if (reloadSub || Submarine.Loaded != submarine) submarine.Load(); if (level != null) diff --git a/Subsurface/Source/Items/Components/ItemComponent.cs b/Subsurface/Source/Items/Components/ItemComponent.cs index 2d4da696e..5b75efbb1 100644 --- a/Subsurface/Source/Items/Components/ItemComponent.cs +++ b/Subsurface/Source/Items/Components/ItemComponent.cs @@ -207,11 +207,16 @@ namespace Subsurface.Items.Components statusEffects.Add(StatusEffect.Load(subElement)); break; case "guiframe": + string rectStr = ToolBox.GetAttributeString(subElement, "rect", "0.0,0.0,0.5,0.5"); + + string[] components = rectStr.Split(','); + if (components.Length < 4) continue; + Vector4 rect = ToolBox.GetAttributeVector4(subElement, "rect", Vector4.One); - rect.X *= GameMain.GraphicsWidth; - rect.Y *= GameMain.GraphicsHeight; - rect.Z *= GameMain.GraphicsWidth; - rect.W *= GameMain.GraphicsHeight; + if (components[0].Contains(".")) rect.X *= GameMain.GraphicsWidth; + if (components[1].Contains(".")) rect.Y *= GameMain.GraphicsHeight; + if (components[2].Contains(".")) rect.Z *= GameMain.GraphicsWidth; + if (components[3].Contains(".")) rect.W *= GameMain.GraphicsHeight; Vector4 color = ToolBox.GetAttributeVector4(subElement, "color", Vector4.One); @@ -228,7 +233,7 @@ namespace Subsurface.Items.Components guiFrame = new GUIFrame( new Rectangle((int)rect.X, (int)rect.Y, (int)rect.Z, (int)rect.W), - new Color(color.X, color.Y, color.Z, color.W), alignment, GUI.Style); + new Color(color.X, color.Y, color.Z) * color.W, alignment, GUI.Style); //guiFrame.Alpha = color.W; break; diff --git a/Subsurface/Source/Items/Components/Machines/Radar.cs b/Subsurface/Source/Items/Components/Machines/Radar.cs index b542a6f9b..25cecb794 100644 --- a/Subsurface/Source/Items/Components/Machines/Radar.cs +++ b/Subsurface/Source/Items/Components/Machines/Radar.cs @@ -172,6 +172,31 @@ namespace Subsurface.Items.Components quest.RadarPosition, displayScale, center, (rect.Width * 0.55f)); } } + + if (!GameMain.DebugDraw) return; + + var steering = item.GetComponent(); + if (steering == null || steering.SteeringPath == null) return; + + Vector2 prevPos = Vector2.Zero; + + foreach (WayPoint wp in steering.SteeringPath.Nodes) + { + Vector2 pos = (wp.Position - Submarine.Loaded.Position) * displayScale; + if (pos.Length() > radius) continue; + + pos.Y = -pos.Y; + pos += center; + + GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X -3 / 2, (int)pos.Y - 3, 6, 6), (steering.SteeringPath.CurrentNode==wp) ? Color.LightGreen : Color.Green, false); + + if (prevPos!=Vector2.Zero) + { + GUI.DrawLine(spriteBatch, pos, prevPos, Color.Green); + } + + prevPos = pos; + } } private void DrawMarker(SpriteBatch spriteBatch, string label, Vector2 position, float scale, Vector2 center, float radius) diff --git a/Subsurface/Source/Items/Components/Machines/Steering.cs b/Subsurface/Source/Items/Components/Machines/Steering.cs index c028307ee..c73ad1387 100644 --- a/Subsurface/Source/Items/Components/Machines/Steering.cs +++ b/Subsurface/Source/Items/Components/Machines/Steering.cs @@ -12,6 +12,8 @@ namespace Subsurface.Items.Components { class Steering : Powered { + private const float AutopilotRayCastInterval = 5.0f; + private Vector2 currVelocity; private Vector2 targetVelocity; @@ -24,6 +26,8 @@ namespace Subsurface.Items.Components private float networkUpdateTimer; private bool valueChanged; + private float autopilotRayCastTimer; + bool AutoPilot { get { return autoPilot; } @@ -37,7 +41,7 @@ namespace Subsurface.Items.Components { if (pathFinder==null) pathFinder = new PathFinder(WayPoint.WayPointList, false); steeringPath = pathFinder.FindPath( - ConvertUnits.ToSimUnits(Level.Loaded.Position), + ConvertUnits.ToSimUnits(Submarine.Loaded.Position), ConvertUnits.ToSimUnits(Level.Loaded.EndPosition)); } } @@ -59,6 +63,11 @@ namespace Subsurface.Items.Components get { return targetVelocity; } } + public SteeringPath SteeringPath + { + get { return steeringPath; } + } + public Steering(Item item, XElement element) : base(item, element) { @@ -81,21 +90,7 @@ namespace Subsurface.Items.Components // ConvertUnits.ToSimUnits(Level.Loaded.EndPosition)); //} - steeringPath.GetNode(Vector2.Zero, 20.0f); - - if (steeringPath.CurrentNode!=null) - { - float prediction = 10.0f; - - Vector2 futurePosition = Submarine.Loaded.Speed * prediction; - - Vector2 targetSpeed = (steeringPath.CurrentNode.Position - futurePosition); - - //float dist = targetSpeed.Length(); - targetSpeed = Vector2.Normalize(targetSpeed); - - TargetVelocity = targetSpeed*100.0f; - } + UpdateAutoPilot(deltaTime); } else if (valueChanged) { @@ -160,6 +155,51 @@ namespace Subsurface.Items.Components } } + private void UpdateAutoPilot(float deltaTime) + { + autopilotRayCastTimer -= deltaTime; + + steeringPath.CheckProgress(ConvertUnits.ToSimUnits(Submarine.Loaded.Position), 10.0f); + + if (autopilotRayCastTimer<=0.0f && steeringPath.NextNode != null) + { + Vector2 diff = steeringPath.NextNode.Position - Submarine.Loaded.Position; + + bool nextVisible = true; + for (int x = -1; x < 2; x += 2) + { + for (int y = -1; y < 2; y += 2) + { + Vector2 cornerPos = + new Vector2(Submarine.Borders.Width * x, Submarine.Borders.Height * y) / 2.0f; + + cornerPos = ConvertUnits.ToSimUnits(cornerPos*1.2f); + + if (Submarine.PickBody(cornerPos, cornerPos + diff, null, Physics.CollisionLevel) == null) continue; + + nextVisible = false; + x = 2; + y = 2; + } + } + + if (nextVisible) steeringPath.SkipToNextNode(); + + autopilotRayCastTimer = AutopilotRayCastInterval; + } + + if (steeringPath.CurrentNode != null) + { + float prediction = 5.0f; + + Vector2 futurePosition = Submarine.Loaded.Speed * prediction; + Vector2 targetSpeed = ((steeringPath.CurrentNode.Position - Submarine.Loaded.Position) - futurePosition); + + targetSpeed = Vector2.Normalize(targetSpeed); + TargetVelocity = targetSpeed * 100.0f; + } + } + public override void ReceiveSignal(string signal, Connection connection, Item sender, float power=0.0f) { if (connection.Name == "velocity_in") diff --git a/Subsurface/Source/Items/Components/Power/PowerContainer.cs b/Subsurface/Source/Items/Components/Power/PowerContainer.cs index 73e8303a0..1e1fb6d4e 100644 --- a/Subsurface/Source/Items/Components/Power/PowerContainer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerContainer.cs @@ -184,24 +184,24 @@ namespace Subsurface.Items.Components public override void DrawHUD(SpriteBatch spriteBatch, Character character) { - int width = 300, height = 200; - int x = GameMain.GraphicsWidth / 2 - width / 2; - int y = GameMain.GraphicsHeight / 2 - height / 2; + GuiFrame.Draw(spriteBatch); - GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); + int x = GuiFrame.Rect.X; + int y = GuiFrame.Rect.Y; + //GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); spriteBatch.DrawString(GUI.Font, "Charge: " + (int)charge + "/" + (int)capacity + " (" + (int)((charge / capacity) * 100.0f) + " %)", new Vector2(x + 30, y + 30), Color.White); - spriteBatch.DrawString(GUI.Font, "Recharge rate: " + (rechargeSpeed / maxRechargeSpeed), new Vector2(x + 30, y + 100), Color.White); - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 50, y + 150, 40, 40), "+")) + spriteBatch.DrawString(GUI.Font, "Recharge rate: " + (int)((rechargeSpeed / maxRechargeSpeed)*100.0f)+" %", new Vector2(x + 30, y + 100), Color.White); + if (GUI.DrawButton(spriteBatch, new Rectangle(x + 200, y + 90, 40, 40), "+")) { rechargeSpeed = Math.Min(rechargeSpeed + maxRechargeSpeed*0.1f, maxRechargeSpeed); item.NewComponentEvent(this, true); } - if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 150, 40, 40), "-")) + if (GUI.DrawButton(spriteBatch, new Rectangle(x + 250, y + 90, 40, 40), "-")) { rechargeSpeed = Math.Max(rechargeSpeed - maxRechargeSpeed * 0.1f, 0.0f); item.NewComponentEvent(this, true); diff --git a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs index 529e466c5..1661d73b5 100644 --- a/Subsurface/Source/Items/Components/Power/PowerTransfer.cs +++ b/Subsurface/Source/Items/Components/Power/PowerTransfer.cs @@ -146,8 +146,6 @@ namespace Subsurface.Items.Components GuiFrame.Draw(spriteBatch); - GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true); - spriteBatch.DrawString(GUI.Font, "Power: " + (int)(-currPowerConsumption), new Vector2(x + 30, y + 30), Color.White); spriteBatch.DrawString(GUI.Font, "Load: " + (int)powerLoad, new Vector2(x + 30, y + 100), Color.White); } diff --git a/Subsurface/Source/Items/Components/Projectile.cs b/Subsurface/Source/Items/Components/Projectile.cs index eb1864165..80197fed8 100644 --- a/Subsurface/Source/Items/Components/Projectile.cs +++ b/Subsurface/Source/Items/Components/Projectile.cs @@ -142,7 +142,7 @@ namespace Subsurface.Items.Components Limb limb; Structure structure; if ((limb = (f2.Body.UserData as Limb)) != null) - { + { attackResult = attack.DoDamage(null, limb.character, item.SimPosition, 1.0f); } else if ((structure = (f2.Body.UserData as Structure)) != null) diff --git a/Subsurface/Source/Map/Levels/Level.cs b/Subsurface/Source/Map/Levels/Level.cs index 9445e49c0..e175708ca 100644 --- a/Subsurface/Source/Map/Levels/Level.cs +++ b/Subsurface/Source/Map/Levels/Level.cs @@ -818,17 +818,18 @@ int currentTargetIndex = 1; public void Draw(SpriteBatch spriteBatch) { - Vector2 pos = endPosition; - pos.X += Position.X; + Vector2 pos = endPosition; pos.Y = -pos.Y - Position.Y; if (GameMain.GameScreen.Cam.WorldView.Y < -pos.Y-512) return; - float x = GameMain.GameScreen.Cam.WorldView.X-512.0f; + 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); spriteBatch.Draw(shaftTexture, - new Rectangle((int)(MathUtils.Round(x, 512.0f)), (int)pos.Y, width, 512), + new Rectangle((int)(MathUtils.Round(pos.X, 512.0f) + Position.X % 512) , (int)pos.Y, width, 512), new Rectangle(0, 0, width, 256), Color.White, 0.0f, Vector2.Zero, diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 90344ebef..54ee2a618 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -241,7 +241,7 @@ namespace Subsurface } } - public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List ignoredBodies = null) + public static Body PickBody(Vector2 rayStart, Vector2 rayEnd, List ignoredBodies = null, Category? collisionCategory = null) { @@ -251,7 +251,9 @@ namespace Subsurface { if (fixture == null || fixture.CollisionCategories == Category.None || - fixture.CollisionCategories == Physics.CollisionMisc) return -1; + fixture.CollisionCategories == Physics.CollisionMisc) return -1; + + if (collisionCategory != null && !fixture.CollisionCategories.HasFlag((Category)collisionCategory)) return -1; if (ignoredBodies != null && ignoredBodies.Contains(fixture.Body)) return -1; diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 299c145ee..dd3ecae38 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -388,7 +388,10 @@ namespace Subsurface.Networking string mapName = inc.ReadString(); string mapHash = inc.ReadString(); - GameMain.NetLobbyScreen.TrySelectMap(mapName, mapHash); + if (!GameMain.NetLobbyScreen.TrySelectMap(mapName, mapHash)) + { + yield return CoroutineStatus.Success; + } yield return CoroutineStatus.Running; @@ -397,7 +400,8 @@ namespace Subsurface.Networking TimeSpan duration = new TimeSpan(0, (int)durationMinutes, 0); Rand.SetSyncedSeed(seed); //int gameModeIndex = inc.ReadInt32(); - GameMain.GameSession = new GameSession(Submarine.Loaded, "", GameMain.NetLobbyScreen.SelectedMode); + + GameMain.GameSession = new GameSession(GameMain.NetLobbyScreen.SelectedMap, "", GameMain.NetLobbyScreen.SelectedMode); yield return CoroutineStatus.Running; diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 58f5cdfd2..90a781394 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -265,7 +265,17 @@ namespace Subsurface } Hull.renderer.Render(graphics, cam, renderTargetAir, Cam.ShaderTransform); - + + spriteBatch.Begin(SpriteSortMode.BackToFront, + BlendState.AlphaBlend, SamplerState.LinearWrap, + null, null, null, + cam.Transform); + + Submarine.DrawFront(spriteBatch); + + spriteBatch.End(); + + if (GameMain.GameSession != null && GameMain.GameSession.Level != null) { GameMain.GameSession.Level.Render(graphics, cam); @@ -289,8 +299,6 @@ namespace Subsurface null, null, null, cam.Transform); - Submarine.DrawFront(spriteBatch); - foreach (Character c in Character.CharacterList) c.DrawFront(spriteBatch); if (GameMain.GameSession != null && GameMain.GameSession.Level != null) diff --git a/Subsurface/Source/Screens/MainMenuScreen.cs b/Subsurface/Source/Screens/MainMenuScreen.cs index 4665bb1eb..6529e55db 100644 --- a/Subsurface/Source/Screens/MainMenuScreen.cs +++ b/Subsurface/Source/Screens/MainMenuScreen.cs @@ -34,12 +34,11 @@ namespace Subsurface - buttonsTab = new GUIFrame(new Rectangle(50, 200, 200, 500), Color.Transparent, Alignment.Left); + buttonsTab = new GUIFrame(new Rectangle(50, 0, 200, 360), Color.Transparent, Alignment.Left | Alignment.CenterY); //menuTabs[(int)Tabs.Main].Padding = GUI.style.smallPadding; Rectangle panelRect = new Rectangle( - GameMain.GraphicsWidth / 2 - 250, - buttonsTab.Rect.Y, + 290, buttonsTab.Rect.Y, 500, 360); GUIButton button = new GUIButton(new Rectangle(0, 0, 0, 30), "Tutorial", Alignment.CenterX, GUI.Style, buttonsTab); diff --git a/Subsurface/Source/Screens/NetLobbyScreen.cs b/Subsurface/Source/Screens/NetLobbyScreen.cs index e115819cb..dbec38b8d 100644 --- a/Subsurface/Source/Screens/NetLobbyScreen.cs +++ b/Subsurface/Source/Screens/NetLobbyScreen.cs @@ -102,7 +102,7 @@ namespace Subsurface public string DurationText() { - return "Game duration: " + GameDuration + " min"; + return "Duration: " + GameDuration.Minutes + " min"; } public NetLobbyScreen() @@ -138,6 +138,7 @@ namespace Subsurface new Rectangle((int)(panelRect.Width * 0.7f + 20), 0, (int)(panelRect.Width * 0.3f - 20), (int)(panelRect.Height * 0.6f)), GUI.Style, menu); + playerFrame.Padding = new Vector4(20.0f, 20.0f, 20.0f, 20.0f); //player list ------------------------------------------------------------------ @@ -153,7 +154,7 @@ namespace Subsurface int columnWidth = infoFrame.Rect.Width / 5 - 30; int columnX = 0; - new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Selected submarine:", GUI.Style, infoFrame); + new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 30), "Submarine:", GUI.Style, infoFrame); subList = new GUIListBox(new Rectangle(columnX, 150, columnWidth, infoFrame.Rect.Height - 150 - 80), Color.White, GUI.Style, infoFrame); subList.OnSelected = SelectMap; @@ -180,7 +181,7 @@ namespace Subsurface //gamemode ------------------------------------------------------------------ - new GUITextBlock(new Rectangle(columnX, 120, 0, 30), "Selected game mode: ", GUI.Style, infoFrame); + new GUITextBlock(new Rectangle(columnX, 120, 0, 30), "Game mode: ", GUI.Style, infoFrame); modeList = new GUIListBox(new Rectangle(columnX, 150, columnWidth, infoFrame.Rect.Height - 150 - 80), GUI.Style, infoFrame); @@ -204,7 +205,8 @@ namespace Subsurface var modeDescription = new GUITextBlock( new Rectangle(columnX, 150, (int)(columnWidth * 1.5f), infoFrame.Rect.Height - 150 - 80), - "", Color.Black*0.3f, Color.White, Alignment.TopLeft, Alignment.TopLeft, GUI.Style, infoFrame, true); + "", GUI.Style, Alignment.TopLeft, Alignment.TopLeft, infoFrame, true, GameMain.GraphicsWidth>1024 ? GUI.Font : GUI.SmallFont); + modeDescription.Color = Color.Black * 0.3f; modeList.UserData = modeDescription; @@ -213,7 +215,7 @@ namespace Subsurface //duration ------------------------------------------------------------------ GUITextBlock durationText = new GUITextBlock(new Rectangle(columnX, 120, columnWidth, 20), - "Game duration: ", GUI.Style, Alignment.Left, Alignment.TopLeft, infoFrame); + "Duration: ", GUI.Style, Alignment.Left, Alignment.TopLeft, infoFrame); durationText.TextGetter = DurationText; durationBar = new GUIScrollBar(new Rectangle(columnX, 150, columnWidth, 20), @@ -272,7 +274,7 @@ namespace Subsurface if (IsServer && GameMain.Server != null) { - GUIButton startButton = new GUIButton(new Rectangle(0, 0, 200, 30), "Start", Alignment.BottomRight, GUI.Style, infoFrame); + GUIButton startButton = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", Alignment.BottomRight, GUI.Style, infoFrame); startButton.OnClicked = GameMain.Server.StartGameClicked; startButton.UserData = "startButton"; @@ -285,7 +287,7 @@ namespace Subsurface if (playerFrame.children.Find(c => c.UserData as string == "playyourself") == null) { - var playYourself = new GUITickBox(new Rectangle(-30, -30, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); + var playYourself = new GUITickBox(new Rectangle(-10, -10, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); playYourself.Selected = GameMain.Server.CharacterInfo != null; playYourself.OnSelected = TogglePlayYourself; playYourself.UserData = "playyourself"; @@ -307,34 +309,34 @@ namespace Subsurface if (IsServer && GameMain.Server != null) { - var playYourself = new GUITickBox(new Rectangle(-30, -30, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); + var playYourself = new GUITickBox(new Rectangle(-10, -10, 20, 20), "Play yourself", Alignment.TopLeft, playerFrame); playYourself.Selected = GameMain.Server.CharacterInfo != null; playYourself.OnSelected = TogglePlayYourself; playYourself.UserData = "playyourself"; } - new GUITextBlock(new Rectangle(60, 0, 200, 30), "Name: ", GUI.Style, playerFrame); + new GUITextBlock(new Rectangle(60, 30, 200, 30), "Name: ", GUI.Style, playerFrame); - GUITextBox playerName = new GUITextBox(new Rectangle(60, 30, 0, 20), + GUITextBox playerName = new GUITextBox(new Rectangle(60, 55, 0, 20), Alignment.TopLeft, GUI.Style, playerFrame); playerName.Text = characterInfo.Name; playerName.OnEnter += ChangeCharacterName; - new GUITextBlock(new Rectangle(0, 70, 200, 30), "Gender: ", GUI.Style, playerFrame); + new GUITextBlock(new Rectangle(0, 100, 200, 30), "Gender: ", GUI.Style, playerFrame); - GUIButton maleButton = new GUIButton(new Rectangle(0, 100, 70, 20), "Male", + GUIButton maleButton = new GUIButton(new Rectangle(70, 100, 60, 20), "Male", Alignment.TopLeft, GUI.Style, playerFrame); maleButton.UserData = Gender.Male; maleButton.OnClicked += SwitchGender; - GUIButton femaleButton = new GUIButton(new Rectangle(90, 100, 70, 20), "Female", + GUIButton femaleButton = new GUIButton(new Rectangle(140, 100, 60, 20), "Female", Alignment.TopLeft, GUI.Style, playerFrame); femaleButton.UserData = Gender.Female; femaleButton.OnClicked += SwitchGender; new GUITextBlock(new Rectangle(0, 150, 200, 30), "Job preferences:", GUI.Style, playerFrame); - jobList = new GUIListBox(new Rectangle(0, 180, 250, 0), GUI.Style, playerFrame); + jobList = new GUIListBox(new Rectangle(0, 180, 0, 0), GUI.Style, playerFrame); jobList.Enabled = false; @@ -393,12 +395,12 @@ namespace Subsurface { if (GameMain.Server != null) GameMain.Server.UpdateNetLobby(obj); - Submarine sub = (Submarine)obj; + //Submarine sub = (Submarine)obj; //submarine already loaded - if (Submarine.Loaded != null && sub.FilePath == Submarine.Loaded.FilePath) return true; + //if (Submarine.Loaded != null && sub.FilePath == Submarine.Loaded.FilePath) return true; - sub.Load(); + //sub.Load(); return true; } @@ -538,7 +540,7 @@ namespace Subsurface GUIComponent existing = playerFrame.FindChild("playerhead"); if (existing != null) playerFrame.RemoveChild(existing); - GUIImage image = new GUIImage(new Rectangle(0, 0, 30, 30), characterInfo.HeadSprite, Alignment.TopLeft, playerFrame); + GUIImage image = new GUIImage(new Rectangle(0, 40, 30, 30), characterInfo.HeadSprite, Alignment.TopLeft, playerFrame); image.UserData = "playerhead"; } @@ -609,7 +611,7 @@ namespace Subsurface if (jobPrefab == null) return false; jobInfoFrame = jobPrefab.CreateInfoFrame(); - GUIButton closeButton = new GUIButton(new Rectangle(0,0,100,20), "Close", Alignment.BottomRight, GUI.Style, jobInfoFrame); + GUIButton closeButton = new GUIButton(new Rectangle(0,0,100,20), "Close", Alignment.BottomRight, GUI.Style, jobInfoFrame.children[0]); closeButton.OnClicked = CloseJobInfo; return true; } @@ -663,17 +665,17 @@ namespace Subsurface Submarine map = Submarine.SavedSubmarines.Find(m => m.Name == mapName); if (map == null) { - DebugConsole.ThrowError("The map ''" + mapName + "'' has been selected by the server."); - DebugConsole.ThrowError("Matching map not found in your map folder."); + new GUIMessageBox("Submarine not found!","The submarine ''" + mapName + "'' has been selected by the server. Matching file not found in your map folder."); return false; } else { if (map.MD5Hash.Hash != md5Hash) { - DebugConsole.ThrowError("Your version of the map file ''" + map.Name + "'' doesn't match the server's version!"); - DebugConsole.ThrowError("Your file: " + map.Name + "(MD5 hash : " + map.MD5Hash.Hash + ")"); - DebugConsole.ThrowError("Server's file: " + mapName + "(MD5 hash : " + md5Hash + ")"); + new GUIMessageBox("Submarine not found!", + "Your version of the map file ''" + map.Name + "'' doesn't match the server's version!" + +"\nYour file: " + map.Name + "(MD5 hash : " + map.MD5Hash.Hash + ")" + +"\nServer's file: " + mapName + "(MD5 hash : " + md5Hash + ")"); return false; } else diff --git a/Subsurface/Source/Sounds/OggStream.cs b/Subsurface/Source/Sounds/OggStream.cs index 8050ecc4e..ae4be34ae 100644 --- a/Subsurface/Source/Sounds/OggStream.cs +++ b/Subsurface/Source/Sounds/OggStream.cs @@ -69,7 +69,7 @@ namespace Subsurface.Sounds internal readonly int alSourceId; internal readonly int[] alBufferIds; - readonly int alFilterId; + //readonly int alFilterId; readonly Stream underlyingStream; internal VorbisReader Reader { get; private set; } @@ -99,15 +99,15 @@ namespace Subsurface.Sounds if (ALHelper.Efx.IsInitialized) { - alFilterId = ALHelper.Efx.GenFilter(); - ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass); - ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1); - LowPassHFGain = 1; + //alFilterId = ALHelper.Efx.GenFilter(); + //ALHelper.Efx.Filter(alFilterId, EfxFilteri.FilterType, (int)EfxFilterType.Lowpass); + //ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGain, 1); + //ALHelper.Efx.BindFilterToSource(alSourceId, alFilterId); + //LowPassHFGain = 1; } underlyingStream = stream; - Volume = 1; IsLooped = true; } @@ -154,7 +154,7 @@ namespace Subsurface.Sounds } } - public void Play() + public void Play(float volume) { var state = AL.GetSourceState(alSourceId); @@ -172,6 +172,8 @@ namespace Subsurface.Sounds // LogHandler("{", logX++, logY); //#endif AL.SourcePlay(alSourceId); + this.Volume = volume; + try { ALHelper.Check(); @@ -229,20 +231,20 @@ namespace Subsurface.Sounds } } - float lowPassHfGain; - public float LowPassHFGain - { - get { return lowPassHfGain; } - set - { - if (ALHelper.Efx.IsInitialized) - { - ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = value); - ALHelper.Efx.BindFilterToSource(alSourceId, alFilterId); - ALHelper.Check(); - } - } - } + //float lowPassHfGain; + //public float LowPassHFGain + //{ + // get { return lowPassHfGain; } + // set + // { + // if (ALHelper.Efx.IsInitialized) + // { + // ALHelper.Efx.Filter(alFilterId, EfxFilterf.LowpassGainHF, lowPassHfGain = value); + // ALHelper.Efx.BindFilterToSource(alSourceId, alFilterId); + // ALHelper.Check(); + // } + // } + //} float volume; public float Volume @@ -288,8 +290,8 @@ namespace Subsurface.Sounds AL.DeleteSource(alSourceId); AL.DeleteBuffers(alBufferIds); - if (ALHelper.Efx.IsInitialized) - ALHelper.Efx.DeleteFilter(alFilterId); + //if (ALHelper.Efx.IsInitialized) + // ALHelper.Efx.DeleteFilter(alFilterId); ALHelper.Check(); #if TRACE diff --git a/Subsurface/Source/Sounds/SoundManager.cs b/Subsurface/Source/Sounds/SoundManager.cs index 06cf5f7ff..62c89c6ae 100644 --- a/Subsurface/Source/Sounds/SoundManager.cs +++ b/Subsurface/Source/Sounds/SoundManager.cs @@ -324,9 +324,7 @@ namespace Subsurface.Sounds oggStreamer.AddStream(oggStream); - oggStream.Volume = volume; - - oggStream.Play(); + oggStream.Play(volume); return oggStream; } diff --git a/Subsurface/Subsurface.csproj.user b/Subsurface/Subsurface.csproj.user index c2dd67340..d8060d791 100644 --- a/Subsurface/Subsurface.csproj.user +++ b/Subsurface/Subsurface.csproj.user @@ -9,7 +9,7 @@ en-US false - ShowAllFiles + ProjectFiles diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 1a110377f37c92824c87bfafd9118e44107f080d..3097c7716b78474648ab5ac7207920f765a5bc7e 100644 GIT binary patch delta 18162 zcmeHv3s{uZy8o>2GT&tY2Sh+58OIS(5eG!Jnc{$Cri6IOQpxa+ii(J4rh(QrD^p}_ zUh@{BdoXhsq4AlSAz4|OqP5H1Y$My1+sut-Zo8=e-}o%5XM`Jd0{$Ga}y zx32GHt#_@l`2G0ezsHw22MVU9$7(V;5D7!{@|7!Bc&Z4D0wRFJKnvs_1ziDJ0;~kq z0TIBhjArc@TE0+{&)k>T%%H~5hB4Wu!>kA1H1H4W=mQiZ?Ovb(coN7!+6vGiKsSW>sE!5d5nc|u7bq3-g34+?`RTzb zRaK0argjWg@#>A^5^cML7WY75cOrK+;2S5*Mtg)80q$a{=YMI)_|W{+knxI}582rN z_91hBqjj%{2b;n?emiF1 zD_{<0=tWR+2M2U-JshE@0Si*`(v@Kd-+}Po-1h`T7wtjlBvOJgi$@SPBkTm71@O1` zAU+b|5x`pr*MYVJ76Si5d>_Eys|P)Yv@@V@052l^2T{WEYMuoxHw zOp#5dYS2f4Lx2JtWbWmGVWSEV+zxz?BK`^bI_O!@^}s(6eg!lejh%q-GYH3n<^b~$ zejMnGFmDpCIt*bQ?@k4En%tKI`>Qc{r3*lN`w6YwIjvi=``mMair8HDH$hj-htRGq z!8E^6=)B!wt=CF*+y6d3i~1!#a~DTBwmYKgTX}3kXj~LJKNGzjhyic`(Lfro3K#|a zfV{21`v{ZECOAfV5W5Y?0`9?R>;ioRxj}#e3<45>2Y}~*X#m*V^fC~MaCgwpf%AYD zcmmjf^eyy?O^9yCXXX@=<^$`1jzCK^awzC9yf%?8*@SRApS<=+ejG_LKr6rmbOc^N zFu+8~?S!^PFC+dZ#6JhE1YSe<2rwDp3!n^iDZr~$K{o?4(5q0;2aul)ng}``Y2y+8 z4B_se9{}?K8Ewc19gX|~(0Jq*f*uF%V_>955%?O3gFzPn6$t+YupxX5bU3IPg@}Ut za#GB8M^e3|G${Sw;zIX#Laf`76y;6{HE&N(t8e2j>m||VCzwN8gA%VXFcr=hvfTRw zC!I$?U5mW3>+>HFmX+rSrSUey79uvVstI<OxfwSstVTR2G9;1Ty z6xVjw$%Yn&tuqsZ?e;OpS?R^s+^>ZuxX)i4teM`zWOA{+#>ei$Z?|o?U2c#)`&qi$ z0SnG@bm>|)74B!nYz}?1pB0(QA&(8IH2*C&UoJ$eRpVQkb(A*QA_aHZI>~SZuph$R zWqlzpk<6yv3)Y=@9s3rBii6#+2?=x_0ga79<~`TH&`KOGjcJ}_i2|orp-H?|V_TSK zQo~DTom@{yVdPvTg&CV;*aAj2iN#6{%|A2>B{rDx+T=LRWLiu2cVnI0<>7X95?&kI z{8cJ+vL;z}GPG+nGACdELITTD`8;3OA9Fvn?J1Lc{y#e#jyP7&s^cXaCZ!6KQk}?b zVN@2xBzMfGkw%Kns+l~`KWMizMe;5Xgz7A2!^jDgwhIN0 zVs@3vBk`AyCRYf}rslVgrtBL{C5H~b)T>H z72qy3veYxkIemSu5m#Yb%0fBgxE<%Se6#TrlXU(U=7#G;#XlP+T2v&oT3O;WTpL)8 z?D?EYMUR2w)4@QkfkL1R@jNhd2paMZ;u; zpr?Uz2tNxdprB&VUBH9DOdtq(RiJkRA0RvlxDDZBz&PMd;5{G&2uI#}&<5ZP@EXts z$O9^o_hAtNUjbhNOOUV)^e$j5S~?Zjg7Di&j{!y_JRJx^qc(x^-d2Eq1YBr}uLf0- z9}apE_!E!`Tmg7pCxEwsNhrG?%4E5exjY3=~&UCk7Qw(zygH4zp9kafG1sU{=!mgYHu z7OpCg!k@*&4zZa={&7~Kctd5uSCe5s$&LqljxxJ%wLtxx40^R`eNfbFePFtbBL0UZ zpy);s_+2G{uLFKr0>JUti@^V|1aL0ADgrAp{2wCzTP5IYe8VMx_qMqNWFhU>B*1#3 z2+-MD^(Nz{@7SlZCqTfGbO3A=owb-d8XX1UBQWo`qQh`p6r*7>Llda*TX9+SC}9?} z_FdSf#XFC9KV9=TDLiu6nLpB^(Lxc+rqp|wi)>dUm0XjRP~)BuVUu6|KV}y`{?U9G zg+s-`jQYte(E@(vn`8b^LZlh(i4;DSt7E0v%({AB*W$JJ&1>gqJM4p?^&5v1dtK~9 zHJv1v*Di#3FEYVh+z-ZOi(Tc~mTz~ji4hgn3$QR~_IU&}#uZcJ^)LKQSmqPdp2BgF zikA!M>jtr&c~gV{Z;&Lg)xflew6{v?K|Oj1?|9bpV%A|D;eAjLJmZ+{MH^NGY#_1kSu$;VKn*np zEf!wXJSBq5yc-=XlYK6~l_ed6HbP0w0yY7aSCgZ2UO==8*beLfUIeNE1K0_?1ndG{ z26h9l0DFK}ff`^hPz$^U>;qm0-T>YN_5);NLWIx%L%o?`qs={~;*}+i(j;i5Bq>IU z#)9(NJQ;;Hc^QK?UNl)8N|iUOVaAkXVHvZ$xN}?g**`3K zQ>du=ciwMz{SEtV%=VBc)b>XETH$XZeG+KyL~RF~1E_~hx@?`^YU08xKNQaH{*0~Y zt#2M$MPsvBDBaagdWMbRJl=~c=Rq>>-7jpEJt1;z9QQ0O1NiVR2e>D<1mG&Q6yPpC zz60ab7#<>TW8ON!OzeQx)#w@_yw51aB6l{r9EG5Ij*00)2h%liHb03E^DQ+0m^e_d z|CmnahfBlV`$OZ{V4Cw+u_(}u_eKEx$)&v^!T@TRVYV4ljteB0=I)o)V_k5K$KB_1 z4{7WvByqp|wd8;@D8H@#LQLMz1(k~b!KJ;B?;08fo0V*1#4S>C^KXpvW5fVP39%|x z+=6(Rd7txZLBnnqv2wR%GKcz4d~u=qS5%nUv|c}tfX2Q;=Bevn7|fnC?7Dbdp(9Jx z0mgv-;#g+2-M?mHc-kXDXD5CB$AmU#S5v$8LO9jkCOW+_qToF)3X=RVy*e&9_?Kt zjG)Rhs@0f0RKOBSc8K3IHkH^}aRBA_knP5_<>Hgf!?-1i75VOYyJR@pO7*NX7cw6Q znJ>MJyw1?vY#i;KDY&TQPC=)V?dAw$yi;7yXzU23Bh{QyL#*ZdKC%uvwdY?WJ1*|- zwuG0`tY=uXJF8Cs73K@?5=+uE$=X$JYpq#YIIi>AcH@FGp9opdWl03R&`;<9CuN9S z4-e@h?)$^K7>*>dUaLMJGUiua&JAh^)qSB@DL@n+XA5XiYc!_vvSg<{8?{L5$&ZgF z|8sBhmU~`PJYdob+Vy%qwsp1$`y+*i&$(_Zm`$OsD0zI1IM(gb;;WifGzPv1! zYSs!aZ@MVZxN%B|bzH?-@!Tr+ZQqY-@v8USV#y~mMsk?+He*9+?-kb9aMcJk%o{HX z)ivV1%sOz*sSchGzFo6^Sz7YJ*>Fw$$I`l66W1 zZ41<_)ahUBL(hKE<}T}iQP1LIjCc0%8V;fcPnzyBT*Jj0jmDjlGmMM~X(F>`clcrc z5_TkT=2!9IkVo5w;BTSI%{It|)jiMQ8sOFdmRv z-(y8M7zk~a7Tzq}x+xq9+6K6(Dc<>-onvvdC`fJ-(xWNoYRM^A-)K?P7g;VK6-aOP z8rL2D5x)%>01Rx(8w8pG+yP_)qkt@62rv{F1`G%81V#XN0e1r<0bb?-DB=|W0b^v- zNYe`l@OHfqE%3*taPKC{)7Lf&e}V8c6yyb+4q6R56Eq(v09rwyXM^4cP~BiL%dq7^ z7`^+zpgZ`|=?cr|a_OSRcv+_nv$Ysw)@JxaEQ4~&_td>}>7zB$P9INF!=IRq7WZc% z6fs=rZ1kQh?qiXWUzqMEPusP#q&ncKRcKpP-Tzh5HJ&W{6J*9R;i`}D(!%E9( z(Pg2?yGFz&5Zyn8#hPcJ=paX$xS3lJI-e$HsXZ`Pan~#0en{?!q??;3%g;mGxQ%b0 z7CXWz^fF|y9>&4rkT8~;#ri-`f2ojV(478K5gSC`fGAJn`-a;YJ#d?}FkC{P`SYRs zcth{JFCIH~Z~ty(d%OCynUSSav2wjwMXV8i! zUA<12z&yLT7P!b;04?CTo3EC4^Vxivo2&@m9sy3g!q$Fop5-kwCe&ZKab>T_1WNb> zDt*8XVZZfU=Ac#k=U=?*i`B(rFC~2y#G7Ly*NZ|8C7x$dM${YP-?1X^#^6iZTE^7r z=+eyQ!xB)430>t8Lw~NIA8aCELn~L+6g1PK_G-$JV;tp1{1Y%Z>yiY(s1r0z$!hjBlUk2JB zoCtaes6syXrdpB4#g{)V5a%0@FOl~QC{N?M;3&fVo8ml;KMurC;Jr-%kB4!uPk6J! zvXL>#f2O~( z;TIgo{et7bf^1Eb8Td}D!E$6Zb5P?dX0txq_wu&rRiC{4?S@CrweK_NX}@jCRi&qx z!7hteG|oq4gGBgTr-|s>wYe|~2a3xW1%IdZHTvq(Ugmup25hnJV#>e=9o@fqRP!sD z?1ywmYBM>^9yW6h-%IuTQK)}bf-!#nXR6OodaaV+9e|}ws3dqA#OJL)RE~M-l?k4r zCpWkKs^Fc+2K(FpUW3?`(c#f@d(UtzX@(s7BJ7Py=l1A__H6n~*j;zh#(6O0*l zMy~I~LA2aqv4;8Q;EvU|v=B%2Zqu=S+Q~n>{>nd$Sxdwf%o`;MziFcSGwa_T-ulfK zk7hpE;a|PeklCh= zZSL)sxVybeAFwv%tNn*_c|YPSTyF^2LXX!c&_D0h)mAquXrG#<%1L^BsOHny@$;tV z-7>LP_Ut+18vAMfqmr6nOBmH$W~qb~OcZ4WnyqwixEN%0M|C^Yt#RfZFSTnkfO*=F z^snZeFcAe@hv!hqeOMgc+OqANuT)uU2amaQsN|*LCwy=DPg`na2+iw#EbaN}jQBrY zA)N>@LnJT2mIS;Dt9XjLdhmFi;M)INIQ>@_PN7gjH!PekVyO9gHFP>IE*%;4=#ct} z@7MwdRjuf8&vMak6}$XhSir13YY!e1gZIpy_x6|-7al&eo{Z0g+r5Ge6BK55Z;psE zQhG~oFp@IGxc^VrxBOh=>iU-ZMJ6CV5#YvczeN`q)5_#)=!ZsnY{yL!F#tPRHQsANj|@Ry9O3! zgyl%5M6%r{1$ge2B8`|y(y_tb2)tTq*1ff;6&^<_{l<)qdzpEsQhiV=Y!i_@(%-D+ ze{IioYvFDugc@c4kPZaP<2S4ie4l20FHJNL-C=LF{EAWkz2p#luGR7nlBs06Vxy8V zvP1zx4WKL0INextS(+qL-Du?0+0+44vO(lVr1RxkOfaKxlr1GxuSW!y%J}{-7US(_yh{xF*ukxu~Nd4c8v5nqrx6aB{gV@mr4rd zB+CDXIf^PR%H1T?sS!p*j&xF_aYfQlI+&~^8O1fcYl+LG7~h05DxD*DriLOZ&KNO4 z-r9$99+77l)-TPy1d3ZB?=*5MM(R-@2k5O8YJlt?a zDa+eY;$o>S3pdzN`AQp#&w~>=^gH>qM(0vwFk7BE1_#2xEl9 zyj7u+X!AhNZq07w#hX_#D*2a^NQeF`Mp7jyW*R&&4XY~Fq=KQw4rqTC8e{mV21f&EZiDp_@5OajDmJ5W@E-YbE!-V z`m0f7t5GDww%FXjjM{t&6TYKB$))^O@b^8o&O8@I7UIMsq`TUSUQQQ7jm$0PD&}_e zg!rWJYO63-6}1b{mc@sZY$JQ8c{55XmQq9`<#BVZ6#^{Lxw(8#x6545NVsf9ugcAJ zviBg`Dk*~Zh@^UFU|Nr1CJGdZY768TTK2lMgHoQCRO3XwR2mQ=|Af3dU3awlRe3l6 znjpKa6T!kU^50wjywEZ4Tt%STu5vOJ_hvTA=?+m_&=+j(Gz)P)C1UL9FQ>8JNjSk5 z=19uvidq^&^hl%U2zfvA+y!piCdnZ_dA#lCB_xDStb)qefQ7o@n5Wb$bCQO3YZrCOx?7Up~-zgj7QOl<_;Wge1MBgml~5A=S3 zF(|ca5TXO}+ZJkAuh_gPitas*bbBjvmXS3;sZ_k@Fo);rm0m`#ECs6r;h+LP+64t$ zsoF1O2OWBqS&gKj%7HfI(#*L=Zn3f&+T*y4?=LEqjE-!E^Co7oa!jVuY3dTPPE+HJ z9p5P#%$;;|GG(P{$wuB%WtB{}X<7g^wlPbFwM1#O_~g~2m{oVpLk^?=56Z5Vo&dNl z8`dfVX^)FV7=#G1#2qw+1<} zYIz$f-l4}E&MdV~qZ5P7Ba9Jc%2tT)_uL$8QO?N}a!yV$Qbwt@Ehu}Kq8jRB>P5|6 z+b5ZvW6g2KxaX7&jGSwPPHD zss-8lYOzM_R`sYxp)(+XV_r6^l)qERHMYL5jKKHdEPyHtq!6R+QRRe4<$u#cjF27b z8HKVIsZ))qdsL6+PK=A7oHP^~Tdy2t-ugceO1)cpq^oLB1N{-n3+&2u_u(H zB8B`_Mp37EQHgJB_G`0|`MFZXyp5_rY4a2e-$`XF%1OcOxL#6{jREJ>os1gyh@B}Y zUX3+|ey2Vs(om-y>1W&Cr<8rruM?D>~T(THtMNug$@p7XS0Y#+T)rQS|Q3bbMhxnDa&vEi_E z5gx6r;vJ}(JzvXF)VK?7uHIACebKZ#$Q(yGv(zxEj8z@Rq|NFYnJTYWt8FpU@zHV^d;?)d+!5`4nMx)pY2@4h#+X#E)#3Q}bv4;Y z&eYzHrbEw(QO3}ZwUaWL>%q_uI?%-aGqhbIZ5#pl%lu5M5-2CbTtIcNXg1pMw)z<5 z{}qcT=PQ_)UT3v8sO%{v(ulmEVM$SQlX;YH{$E_69~0Oa|CH%&eXhIs=15vILkxur zF$`;{RkSf(=||4dSVTNmE`;D(7pCg8sE1PBJ6akgMsSWT(9S?<2--N@@`JT+5Y@I+ z&!BCN&DUa>k*4Z!=B6{PGaXtZh8QUev|7-G)cBq@&zM)GErnC< zoHml(O&eqML|%%O7Nb6R%C1ic%r(t1O*f4-%`jz~9KL4fC+hD94)=G3cgN(U!_j&a z4!RZ@O3N^w5|V*0=HQ$0rd$*E)g=<^rQfCZoD^DnxwdV_=Jiy4Udy5UH-*lY_pmFm z;v?Dg>yGR0-W{6Yxu|(5Cs;RA@4gJQ?}`g}fKFIQn}FeV|c4OkXVaOT|xfdg7v8fBZ}*0XMw6;`Y_8h^HZx zgw%AzyW)-hrkj0f={O2V#@+QlAlLs@cVpvS`n>}EGe@6H&Rks~+h|?UW=@`rixU&a zPN!Kmy$gHp-*O(&#wq&5YlQ^R%ZYyvIGsIb@B_aQ{#&O9yP1RN`3LletwLh)jQe^$qukx~pJTq;_EBoVEe^m2poK+Ki90ze$M_qyL)Rip*jg3Q3@Wf z5BIss96#wQo5B5K3l==kKecs*E}+jn>NNJ{=g(!yUjfuYpdx-I%wT)o65>21V*%*5~6@N0|w>0EOU z_#P^59`bq&trJe~1t zicL?1iNT@7Pa6D>y(SF-F2(5^Ig>`RG-55pI4TpMe;=BzFQknH`aS%}w~IxEFMGxW zRM>4IrN&tzXw+=IC3T3@TL)igDi0G-Bcmq)G&oX^VE$7m1E)~!1v-o)U7VipZ7HRZ z_^^J7g748IxV-pSy&wCr(C$Ip7vp~-YWn+6b*mqPIu1lS_nAN`<2ouWdPwiiMp5b! zF@qlLh<)|wWqJp)ebyOf(fe*||PnPQHhhAJVn!ZlZC z>@+RvCEQLhO&3UbMyoce_iFgpO;qPP=JKeqa zvz9E98eYSGf5X>WINMCsUu$VB$5*|^?O;Bto$Y>MX*dbJ^gHESZ%#<+N;T)TyF!0F znejRAuX*!ZS@JPoTsF+6a^KM`)x9amO7k0WAvvDZkE|G!*EqZ_rc{QCO$IK_mjH=ybni$qWSwx{1U&EC0&-+?!An>Xd!vgd}ilfCIm zk5BoB_q=L@uQz|5(RxR5=HwggfO2&WmfA*d9rp7!Zy>i2bhtq8>N9g>FVF}7v_X3n zHO29DnNIh?^j&8)5(XWK->M?;4qV2)mQ1`$U7xx(lpSjRj4(Hfe#7YF8!Z1PK}kaGLHCZQ zm5(Xi{Z{daF2rB6h{{_1W~#XblH-~sq>|07Mv^T9PAZ>m!~MN>LQ8oz3Or4pR0+}K zYJm+ZY$o2%(^LIk_r4Wk6g~4a)(Kl?YB7}Zf@G!L+w`RrX=uHbrh6WAxTShCCGC@} zIH!~-XEW|`RgTs|vHLTTctq$Ez}tScOO$a$NUA7?ZLWUGQUe=%AFMyF2=Oa<4GD5& ziyohJ%8R(U-?7x~?JHl){l>Ey=C|RJI)-Yd;OAD2hovC8ut6V4HB-gzKCdnRiq8H? zA54iewQZEQPz=R2IR72LJK(WgSfTfG53R2uwpH&&C8?@zytGBXjkyz!MpLvGSKfYH z4Y*303az~QrDv_~@@(bn0FPed`4e>1h97TelWV%>Alo)Q$Fm8|tlXumET-}cQYg8GSvrZS zxAvmFA7Q6x?IPVoUktN^C`|+C8E%2A^BGIA_oR;L;tP};x<&RPCDBN%*3%`e0t3$n zzrrZmr7vp9`%zJ|7GnF8eW0>S>V_MJxuT{-XHD(ijLH&^>T`{`2la!2G}Ug&Gd9n) ze6ASrDVB@OKtfL(&(sRB)T>Glp(BZ`Gaavjb9--?+?vV?)fg(;VoBwb!Ea%f3mJU- zY@@H9!Gb@15^jElB#QCBJd`zG=#n9w)PI0iZI(8|GtnFu$Zz2CZgSd@5^AwCtD%)U z_15Ivf(xz>*6NW|KAA-YrbA%H;+N945vKUDN*q3y3!MB`r5y?p%AJx^<~frC(5 zD8T7df2q0tQfpt*?6f-C5x9xs9*vAqHQ8SZkh$OLFC}EVP3%y!l38KU< zQYfxuElRMoBj+O)3-ySxIH@?n5=+?$7A$LHECDiI+G4>e6wf}h+!8|XcCd7({B62M z`71>$MU`4YDVlf*qb)6sSK}dR8+It;xa1ku=HfS;$if0rsWt}H(K(kaSI$GCFPb(3R-4K zq^x*LdpbVAGJ>uQgk1Pq?c97dwn%h(OfZZ7WFaellupUqgs$8}e^>^y;KHe6%g{GVW)5_-9l hWeTAsJ*aqyjZ(3nJAsxA?C4H86MA|eS@w}iH+qlD3U zP}R6}T&fzO+3ILdsMDe@p?cF)Q|)n7TTL~bQsw_!GZE3tIX$<}`+wihyM4Y{Yp=EU z+G{=QSW(pV&%5mQfZUTq~ z{-7(65uSq5$H9FW>%L6s`zpBuM2CHqCj3| zrB%IOlS|Vk3KHmm#D>6K13Yp^7mJP*D^-0N_8LC3@Y1c(HwU>3sv0K(xnARGLd z0QkQJ8fe0tx9jv&xW2Xlbg;Y7z**s2pFQN9;hV>LJFofPF|I>h-zTW{ z7oNMAB`Lfrzr8QGYB7u0Y~3g5*5Ryz6(6u#wpx>!u-SSt&}nTa>7nzPBv3(+F>sIL zQbk>-_10$Rn?gHh)h&GGC>q*DP?KM0?oT_nT8}U!w+qRwnhRCGeO~tFHH@{CKCS(6 zJvWREU}na1RZ%-ajxeLx`VE=2lE_+@NzRs^2kCLWSqYOz!^A4i$G5c6Lw(q-hPrjI zP{C-dXw0OFCyXjNR!RY6Un2$RTUxTY%vsn4a-LYuocZHyn{7Wp)Di4FbIoC)6gr!| zzzaiFv$@Q8Hm26j2IbCS%bfW;@MLc(l#X0y5tJJaF+PH)#^3j3RX7_!Zw_QpG@}h0 zAWRTwz;>~P(=M3h?x@1G`i*w1Re-Z_ob+m_P|hg74-3^p`>=A6%f@LtXj8sIg4gd$ zG*=O;vvuXZ@G69R@||lIcj>ky7%XSuSjic>!&4k*)s8YDtyT_NAqPA48zTghP%@NR zg+11j6|7_=vnjgm2k|^B8P9AM-F8Jd4=L@337pB!i+Q)9c3dQhaEGFjbK$-Qw^GfoI; zxb5)lTX2)X7;plt2M>Xb_`abIJYV7=uI5j`{S#cC@M-v8g8vHXwuF=OOX~c!q$lz#=5XUkE}XP4JOK zP>k?n2yY1GGKLXbQkMqTId*N>gegHv8qknZAkH1ju?|^WrJ07O* zN=*;w56oq!nQOfeE%7mr-f6vXgwfUax6Lcr^S0el?+@GzE z=g;tK1>(HEJ9jc`#XX5O3KaFdDM3#tVsD_W^5Ke|TeC*on(Sreu(adg%VoEiZau&%G?&B@Jyw4c zzF1?XDOY0otQTFASe|hx3bv^m&6e40xu?gt-bieX4vC$w=NiuNg-tLKY#}XpmrbXn zZ6-hc$@6Tk$+d+^d0g9T+XtTi-)kTGqWu4cec<^eY1=k|f?FTZ}vKJd8O_TeRD5mLFtdeP4-h|aM+*XdSE4l0o7`ld%kD+cjA+qa$xSE0l&>oBg zw-CMq@OpDPqC!WEMc^AC34slv-cRG@#kltc5#V9a4$J|(GN-^rt1|PdKrr|b3_{#)=TA`$ZH?eN33#Sj!fgNypcQxp z{E<0h+K1#_gZD+mT!dQ$j({_`e-!R@{s!Dlz#qj>;JUzeeh*e7J_W9XEcbvr4*UgS zp}2n^{@I`x?z7<5!~5BAjfl&IdmcQ-3=xJ^@NgLnfIAm##S534Z z9jL<`;T>+$yNStE^nenePbv_WG0lI)yy-XBoohb-&=pr_0k*G`P%gTci-M~uw~28= zxyH4Rt)X~PnxoI{D?BN4h5JTLCF_G`AAPD#T*GwvjQAsS4;7>mi!hy8o;uRvj|I27 zJ!G@54=idn$B!1&6Y^Zg1gmaM5i06a+5uB5D(!9dv%J*o$L&`-<~+Y9dtl6_^w4@-LrU@r?hy z9TQXsqXn(i4)wFDtEt)@i)y0NvxPQwd}~)6A4Bf3xzQ~x6C6!eqW<}?!3lRYcow(- zfgQAavRHp*L8m$|;ch43PafdQeT44G8(HXji}ymSg!8771hEUNJL=7YZQ2flu*QMJ zZPaXy7(?xPu|VhTWnom>U35@>Z*c$(*eABMv>sk4XHT-Y52Xwb`DUA6E)6Ub8|v%# ziQ}2eR}7(oc=K32e}j4cuU4<%)1yx!{1^^fmdY3ksWeVb0wTo$x^!2Cr|H40n#`fIPwy*BPAzNqOPCiSKG z02bwHVf10i?u&x*&lquTi~eaN&Q}HgGe$fVg86+$oM-fZhY=6=7;)aw{6izI|MacU z+@f3a`FOlth=PfMAf9F=p;|sOR(8jf-9Q7kYn@pSDs3bA(|cpI2-jH=R@f-=@#tW_ zBG3a(SryNl_&{|}=vY24$NYLr5VI+gv z_R~JWnC9}yD8J}*54pK(zsbMu(GzD1rp_NO1giFzFV(9@?S@MY^hW}v7g8Dv#-TZG3Zd`R6W&4EM)FbQE>Z< z0@glsTbOto1&8hOUUQ!@g#?mV`Hnl%?1Qdxb`?)Jml5C5cdOPEz@g%qP| zr>f^F(lXD~%vblFFJ5J?$)deS?R9YrO!{%OihY3VJin-xzY*ej*lvV1hW{+G$nT%x zUBDPxGez{F^%Y`p-h4dJ0{pes%RTVIO}x+>F8^prtvH@YKZN%O1HeGQ!;;|+0)xR2 z@G=+%hJz7cBzOd*fKgyH7$akXoeEDH7z@UM@gN;c0FQ!+U=nToMs3U7hxec<)M2aI&5oC=6iEH~rhy=?s-UTwN^_`Lwn_6&yAP>5~SFWPUbZ41G2f zRo$Vs&|j?*eHfce@$bXnX0?%R`jnPpLuNTx(dYQWCX>^Py18PWYt_<9X(`N~+^xis z6d!JGsy7`gekRhuUP=eO!*TH)h7l2aO+;rh5uFK}OYw8W1S$xWt@K87HOLbCZQXAw zujHR?f8oKZKfluGJI}mY-{cTS^Hn|FmLZ;(SuVv_;w`%-M_HydYbc)|Kdk7;g8faq z>}qwYx}&wCqy1go_Bb_OXEVh+jCM~K`|5qqi+h=SwkS!9hrG9h24-Ux&?rzeVP!F2 ztdLnMvDpwnetUG+S=-D;OI+WQN7L6gKfR=1Q1i+k7ZvN%gQOK`FbW?AE)mPc|Cn+X z{6C|dp+DE7XPLVI)~Ot<7Nwwc>^VhZn3ZFg)1$uMgxCYEPyMlNkGUuNH1%p%Uv37+b{ibzJAfH|fnf(u1y##qMU- z8Vw@`)anmD7W3t02ujv(>=8{;qk9<~*1zxYo82Gl^}&S;^%_i#;3Mk>^t1d?!beJ9 zaHV&g=IQBDc%uFb~2lw+s>l7 zxXOh@p_y1?){POc8LtP>>~f)x!Y6?(?kj9nxp(BnLTJV(LY{FcVuu=>H=hgFL-+H3 zBmjL#fb@!G;EjyD0yBJbf&wH?0;sQRONuqo| zV^H18b>=_zhbH3XNB%gvV#ck0o_>|;J}!Powl5Wb-T#XCwTUhmjqpZF70kq!w7B@!lD^T6AX~*t=RoT2K7!!3NP_z^k}MV!UGbNGU{rFB`B|<^Z~pnk4#`L7 z{Pg(N8NEJz+AE%zp5ie^(+jw%87-zW%k#>-{n3WVV|5?P*;tcX{os!Rmc$Og^E!9~{0WqTgWwQ&6C4JA25*74!4Ys2 z90Tuw}_GY+a?)HtU?Z}`(XX&yR04g;Lc0Q-^zNIN1e@_4XE)TwFTwRRV6BICO9ank=V-8 z;)x$-yC1NO4&8Kl!wZWSU#E`e)uWb613LQkyESFSu-;qW(TzSmC@W2CLMd+TUC%Dr z(v8(a(Zd+U)L1;@bqQKv&~LV7Ed^)cV3;dA+Db_uDO8})pzuc*!&|x9W4wupsaGwNEfkj|3SOT5~OTiz&GVlyoQ$3~$?6DSi>%enh zJ$N2$055<-z-w?5+|6JMcoDe4RoL z8t@Ta4Cn|tfzBWnbOBw#gCGuc0}c=m5XR>}Yqgc#ied!t; z(`LjR|It8m_K5S8-l!jbxyo6tu-r^D%h?GtYmRk~NQBn3Ct(?)K4JY8zGK# zW`fZ;zv#|K;^BWd5b+7e8(7)&Tzquk9x53M=|L&dMe+A9q1C%@35_?a>L$xKda75_+^LeZHEyLO zc{*l7$DGOr(u_zck0sGHIPw7Gp{w(T(45vkAPv_xK!BI|AuQy#U4hg}Z#h{yH^9Bz zC{eyIUu}(+l9=2d(UJ7Huh53J)D=?PtBk7qIB&-MghFr0Ew$k9-#vjtRlTKCW`hk$ z^FdEdxb_a@xeB4U^gAb{8BGJ{5A@vK_veU1@_~^2^}=tYBiQ{ zr=NH$aPD5@ZN;7q$Y1PR zE`y5AMCq5q{oVVP^V!M*iKNM5#K8Z=RJZ`&=Piz}``c*yWU=wef-r?I^Gx@&k9VERSV^K3#@NHu ztcTP%n78dgU@#a0h629q>`67Xhg9gc$^vDZ%$Om3ZTzCX%O>Y~K18!@@;>PVR9TO1 zE+5Bgk1UkL%Ildowy=wwDAbkdVi$QGOP~eArEZMTJUFJ|r}$QqflMQ$&aM$sSiN-2 zz4$+VwE}MHJVNSF&(!Co)Rd(YUhkws4{*jHjVe^N0i7KoVThd#jfm+eN9c|yxl}B1 z$bv*${3Sbm*jEmq%A2x<%04#*lieaqw9|qKbP`i+o?E>rMowaMC`%64!$(W+Gs=G3 zT_}-Hnj_+mLA)J6msQa3fYEt zkEfWT>rwtHV-WTKvy8JUd*wHCtm=$?rQ+`>yTCKy}oqAae zqM~n1MjHIKIokD&si%HC)EF&qJv0#(_v%ARtR5R~e2Z;8l!5zI?NqyNk2IDs*Ir{J zWyQ%BJ+6=OkW2-AmBISp!N#48;vQB|5hIQ7Batk;l>9z69V{{qKFmrrE@AqiTuD%9 z?`NiDO8QI*AWNnq>6v43uyO05xp;nT1_HB~(MZ;rh_OyIR^X+4DbA$FEjAvqQ1L$F zWXdvQ*?wuJaVDf+E%&(wmg%%=E%XiJIOS% z$^B|l+K8gMieY5AW>VejO)6P(lw`W{I?gVP-)35Gau!Zk$X+hT=y7{ZhZvPXYssjFlpl%`*DvK9Z@5Q9(WIc>BDF z32#`Y=|dA08;wbN(pggxqa;;>PJd`RCsR_mI-V?lGbwsTg=w|yo@o-?7fn7?aY+fM z3K7!pV^K;NrC!CRUr4ZmhEyq;`cOnmd}wH*vO}f?E&<2d{;C-D;8~_GFyU27geF_og&gN^XM&%K3#vW-TD%fVDu$K0DNbJuW&>ty#jJebu-^V9uyC|96R!$g>~DDzq7Oz0d& z1$ofN{>A)*{STV`Xz*7`B4u1tgZ1n;l;tA%eJMujkDg=olT8Ad49T*jQy5%}a=$`#mv2aK!9(F(13S66c~On!hdmMRaK zL-o-|luaVpgLz9h3B{pe-2|f+XMW2}ey4d-XO%KWtA>eDw4#gXulMY2-p{D&&)8G; z|4{iFy0gvHl5Z2*^xoylJ|vK-wB(i}L{IEvJ|I)^ar1C}_<3cUNCjW3Fd$zmFd(SI zSSox%2_?sAbGW{wQkjKTcp80za#Q(%xs%Lcl)oKv#8EVVeduiS4%DPc?L#TMV6!qd zm{*HbSZEHWyl;^yd$GB!DHSa@N74L1wA`K_n)i#88o^6-$y_PZnN6k;T2YB^wBWMY zNS$se=V;3rgjsefVYH@9iln65%51tC0^#Ejfsr2t@YhFQF>iv_zio=3Q|m-OJ?^Uc zkVvKPqO~|~V6Q#&2Xnc}m1TlekkoS`o!`RyN+0zSdYp?ep!_hM9v7(MrLi~Aqh7kL z1e&PgwmFd!XPFm~;A6B=Wr*yn+pTJus2`hUj$yQ6tB3?$=5r>Dc^NihHkl6?Y12e( zB~%U*(AB?~0EW<~@CBG7jUp3Lg17CWLwU+cGfmM{kYhrRI#MlWx-ee7 z&DYY$|*e3!_Qv%~5*Ee6^3sWyg1yTo+2QxREF5nXzgRa|+4fdet`b`?A94 z;e1#_imG-hQPtrKI~Z;b)vBj_YR<%#=vuWsSsSX6 zRM}Lu(3*AX2<)8kY}!AQd}-Z!brl_Mr8cFPpH~~y*;!pmUeYK!U0;ooxpyM>ItZUt z8s!*f7{(f=8q%-~Kgp13NHU zo6iXpy-;08yZ(w3UrA9AUQwLdSHHBC3r~1l zOC|e4Rnl#h<_f6c3DfGDwQ`m0f)q%Vc`Ev|>*g!^l6dtzT8#tu*AtP3y{8J3QhY^O z`f6`=pGc0TasnkN>Nd(gVRBP}s799bR!6g5-3^`b1FQrOc5EE9HS{#}FmyD;!xwGn zfbbsh@xONby}ai- zp1yl)2rS(Ie+2NJNtr^^`l~(^Iz#R5J?WG`Lv3GgW6kp|OJ9ZGLLu*|lgPK9s?_m( zsrrLCRPZOYA+*1g`9AsEicb^$)P~inu0z!)Gpg5L9sQdpb=W44Le$|$PSR&(WlYPN zG%eF}h9~W4jWWc?C$^92(Y|emcJUqBM#tMbwvA7SvA6Bey;FQlOhRJ&P6-|7&Fz_% zos*uPZLL1}W9^aoC{C|f+edat`FT{oX_?b{rA?)FC2GU43DxgapCPiQ-+OQTe>)ZM z$&H(jthaBk+p{Cz*bbsm$?E5hd6FUV-zhNV4^kIUaYHqc8-oL)&IYS_ti`yT|B4)f zX(g!-yVgM#wG2wvR_a@I__74I8$UB6v%O{{k5u2*X)qyUVL;MhLUJ*eoCYJ3iJu>G z!;%ReMT}>kProxvjc0lBZS679QJvb`J4DBHjGkwzK8@G8M{LTV8Dn#1WKT##75u!C zYt?_^-FmEkvqt5sJ>Hgc6N@U|E4Z`{=E{6gEO8S{6k>5a@3I)L3n}Uwj1Kk_y9w#z ztB+cZR`U_`rW)4hJ`G0moI7_;d`$O_(K$3EOdS@MV@UB7a2#x=*LLy{E`mp^@4XwF zR2rrZrBg4!EJN2c8oW=ob0ca)--IqGz63`Uc{}!*nwFWy4_11Dr=ONvdrU1k=BN%= zDlGQN7gVdSPmjB83OTahJK)&9AKF{(IBz=l{(42yvnC*@)KlUFvQ9PI=!0H3_3_C| ztT|<*sjGj(F4GSYYQgW`=2L&`0G(d?wmOMfrc5f>JM+uGtsQlyr0s?_vt|<8$(oSr zQfx{ka+z+3HT*MY0;#korn~#v!j}K*$3LmEt?I9@->e?f?(ZNX#qM_4b#DEmVauaD zHoph#I=|zVz8x%md-%AmPr!-wwjdFG0`C{vAv7Mb3Hru|)G>ngI`$HH=jmhc94)+O z#-r%b!|Di1%@gZ$m8eJW&lXy;JsyJ^GATEGYEH_yX;ZVNWu|B5=A`g|np=;BWv_T1 z!}C^y zU%WMb+TABS1sLz?TrA$lcw7qq|yys6dqzTmap zDPD(nSP|?sPl7?eogkfPjbT#gYickRoy3}K(jQejb<0B2`}IDsEqjS4>HV&sH{G!_ za&xC;rg$7W*jkFLi-yThJA1B4j-OYY11Eq&mYJ!-1te^J!0Gbo9o+7y*9G2-!XpbH*%{ZOk#Yg+k5@1=RTvn-@lv8UDul& z-MuxmD81`V{2c=FQN1#YoHaG06Sd2NRpa9RHF;KyQLSWIBbroSe1V(6#NSt`^`ht1 z={_wpH+xz}hDU_G_=l{Ge_I#E(Z`Rfwt&5NO9J;mwLkG6YPVuagdX#n8d&A6DO2J@ zo>tiXUMsAAq}B&KUav4euL*8edKG@&>b+yPzt?6ov#0%VNp`p=$zQgw&&H@h0S#(C z5mwq9{?7ap|3stH%so8gBNVf{N16kETbkZxh$m~lS?%$bHoPV{u=GLr`SQ0{%8lHa zDhsLI=UdRxdygac#&KjM8GWxW6Z@qlP<)6ONrlN~AKLYUNuejEsq<*TVYM5#jy@jM z`b`tzqgH41epNJi3zkj?$7ufaSjTRvL@#(ZXNelG+ z*r4Apl;r16<7@X_UitamwJ#Xy^OL?FZTXihx4+*2k3H{o*PbJXeeVf)&@VFB?`}Wv z%lGcfC~mxYjjss~E#+H!4QTg=>HxB5sp*vdv6>LTrz+knpp^e|_##0>({D%T61Yo1UGMk~XR42Ex2M7L1PXw6%1Oie;yZ7@=i-i`|ieMQSXy z{8AlBS1zdz@0Cjay^OvbY1kIPF4z8v~Un(lZ^6ewDaOlM`SIu`n&IR!+vK@O0i)a3O@#fQM8V(EY z(3&j*61^Tw)lOm zM9|J9s=sR%%AJ4Bs~)cF>U?vGXBffrx%;}Qv#Tfa8FNduh*JzHw6RobKyj~17EA$S z^*cYROrh+3vY#H(NyB2aZH6gIk1}eBKhJudtv<1uKv|hE>!TZMp?cR@n&N+7QC3zL zg}cA6D2$5ks7u*WYG>C*@a?1MI{c&vw|LwQ^2%ebS02S%Op*16;6D`_k4bbcrbO|W zT~0DgrT76_3zXtJUu~oA>Z;jg${!B-O?Xjji8^ZPS?7zT0ZCda{b{piqdPmXQ}k1z z_9R1e7){!N(!7(bbrs3@qPEBrmbFr}=>Bfa$tb9y(2|O_X&Mb3t_9Gt7m-3`ie{v- z+q6u5zzD6M;CbbPBrVkA`Sc|%l=LDfNEgkfN5*IqjrW!Ch3d|XyWSE~)=g%iLPb-F z7xIDHg&c&U@^yppo@w->*da%eA%qMFAk5GjQqnvnzwZ+}sz1Tq|HLN(e))-izn*Yl z^vYUo0$%}-z^LOX6ooeg?soK6{3dV3+qYrU)zVK3a{8qQh(ioH)NO#)oRS{a0_&yW zxO6T=GSj0I(+t_vPSf(BmMe#80s4VWn#f2Sq7A0}d1}5#6FPb{p;rC#isSVk$GCd* z=8vb)8zZ%@RJjEeZW^i$(oyS6MVg-qby+_W3UFoAT`kCXMQhC83!}j!H7i#D9SS8d zZZP`a)rZ?O;1Rq~uo+skcDQEsrc^rSZb~OcY2)dom$d}0f$dpWJ~(MbD~4z-2?{nC z$*j4jx^!WTc9ARC9C8fOeCU}ptr=||fgEJ*)aG&PNM9A97kD~FJNNVNdh+f08qXeA z=2>)Vs}@=^M%#u>$33P{D!hRm^(Eh`{FE4N+^R*A^%c$H!>b0`X^9@yC+l=SMHjqGN$nR1X_c z-v>+mXx130?|n_AH=EDLM(E*-v9J3ln-tGn-9-$1tipa4&sDjZSMyNXBj^M=gILf7bOjHBIKclO7k)g- zGp;$Eq=kDb4;@hE-yh&myOA)UFc+VAMmf~)Wv$R-u=t-2w0?-z$deK`4e<26XYZs* f