diff --git a/Subsurface/Source/Characters/AI/HumanAIController.cs b/Subsurface/Source/Characters/AI/HumanAIController.cs index 07b194cb3..ef9cea153 100644 --- a/Subsurface/Source/Characters/AI/HumanAIController.cs +++ b/Subsurface/Source/Characters/AI/HumanAIController.cs @@ -95,6 +95,7 @@ namespace Barotrauma //unequip diving suit if running out of oxygen if (Character.Oxygen < 50.0f && Character.AnimController.CurrentHull!=null && + Character.AnimController.CurrentHull.OxygenPercentage > 20.0f && Character.AnimController.CurrentHull.Volume < Character.AnimController.CurrentHull.FullVolume*0.3f) { var divingSuit = Character.Inventory.FindItem("Diving Suit"); diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index b0a65ac6c..b725cffab 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -85,7 +85,7 @@ namespace Barotrauma protected float drowningTime; protected float health; - protected float maxHealth; + protected float minHealth, maxHealth; protected Item closestItem; private Character closestCharacter, selectedCharacter; @@ -237,7 +237,7 @@ namespace Barotrauma public bool IsUnconscious { - get { return (needsAir && oxygen < 0.0f) || health < 0.0f; } + get { return (needsAir && oxygen <= 0.0f) || health <= 0.0f; } } public bool NeedsAir @@ -274,7 +274,7 @@ namespace Barotrauma set { if (!MathUtils.IsValid(value)) return; - health = MathHelper.Clamp(value, -100.0f, maxHealth); + health = MathHelper.Clamp(value, minHealth, maxHealth); } } @@ -390,20 +390,27 @@ namespace Barotrauma var ai = new EnemyAIController(enemyCharacter, file); enemyCharacter.SetAI(ai); + enemyCharacter.minHealth = 0.0f; + return enemyCharacter; } if (hasAi && !isNetworkPlayer) { - var character = new AICharacter(file, position, characterInfo, isNetworkPlayer); - var ai = new HumanAIController(character); - character.SetAI(ai); + var aiCharacter = new AICharacter(file, position, characterInfo, isNetworkPlayer); + var ai = new HumanAIController(aiCharacter); + aiCharacter.SetAI(ai); - return character; + aiCharacter.minHealth = -100.0f; + + return aiCharacter; } - return new Character(file, position, characterInfo, isNetworkPlayer); + var character = new Character(file, position, characterInfo, isNetworkPlayer); + character.minHealth = -100.0f; + + return character; } protected Character(string file, Vector2 position, CharacterInfo characterInfo = null, bool isNetworkPlayer = false) @@ -1023,6 +1030,12 @@ namespace Barotrauma } } + if (IsUnconscious) + { + UpdateUnconscious(deltaTime); + return; + } + if (controlled == this) { Lights.LightManager.ViewTarget = this; @@ -1030,12 +1043,6 @@ namespace Barotrauma ControlLocalPlayer(deltaTime, cam); } - if (IsUnconscious) - { - UpdateUnconscious(deltaTime); - return; - } - if (controlled == this || !(this is AICharacter)) Control(deltaTime, cam); if (selectedCharacter != null && AnimController.Anim == AnimController.Animation.CPR) @@ -1069,7 +1076,7 @@ namespace Barotrauma Health -= bleeding * deltaTime; Bleeding -= BleedingDecreaseSpeed * deltaTime; - if (health <= 0.0f) Kill(CauseOfDeath.Bloodloss); + if (health <= minHealth) Kill(CauseOfDeath.Bloodloss); if (!IsDead) LockHands = false; } @@ -1078,9 +1085,15 @@ namespace Barotrauma { Stun = Math.Max(5.0f, Stun); - if (oxygen < 0.0f) Oxygen -= deltaTime; + AnimController.ResetPullJoints(); + selectedConstruction = null; - if (health < 0.0f) Health -= Math.Max(bleeding, 1.0f) * deltaTime; + if (oxygen <= 0.0f) Oxygen -= deltaTime; + + if (health <= 0.0f) + { + AddDamage(bleeding > 0.5f ? CauseOfDeath.Bloodloss : CauseOfDeath.Damage, Math.Max(bleeding, 1.0f) * deltaTime, null); + } } private void UpdateSightRange() @@ -1168,13 +1181,13 @@ namespace Barotrauma public virtual void AddDamage(CauseOfDeath causeOfDeath, float amount, IDamageable attacker) { - health = MathHelper.Clamp(health-amount, 0.0f, maxHealth); + Health = health-amount; if (amount > 0.0f) { lastAttackCauseOfDeath = causeOfDeath; if (controlled == this) CharacterHUD.TakeDamage(amount); } - if (health <= 0.0f) Kill(causeOfDeath); + if (health <= minHealth) Kill(causeOfDeath); } public virtual AttackResult AddDamage(IDamageable attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = false) @@ -1246,7 +1259,7 @@ namespace Barotrauma Vector2 centerOfMass = AnimController.GetCenterOfMass(); - health = 0.0f; + health = minHealth; foreach (Limb limb in AnimController.Limbs) { @@ -1444,16 +1457,19 @@ namespace Barotrauma case NetworkEventType.InventoryUpdate: if (inventory == null) return false; return inventory.FillNetworkData(NetworkEventType.InventoryUpdate, message, data); - case NetworkEventType.ImportantEntityUpdate: - if (health > 0.0f) - { - message.Write(Math.Max((byte)((health / maxHealth) * 255.0f), (byte)1)); - } - else - { - message.Write((byte)0); - message.WriteRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1, (int)lastAttackCauseOfDeath); - } + case NetworkEventType.ImportantEntityUpdate: + + message.WriteRangedSingle(health, minHealth, maxHealth, 8); + + //if (health > 0.0f) + //{ + // message.Write(Math.Max((byte)((health / maxHealth) * 255.0f), (byte)1)); + //} + //else + //{ + // message.Write((byte)0); + // message.WriteRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1, (int)lastAttackCauseOfDeath); + //} if (AnimController.StunTimer <= 0.0f && bleeding <= 0.0f && oxygen > 99.0f) { @@ -1465,7 +1481,7 @@ namespace Barotrauma message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer, 0.0f, 60.0f), 0.0f, 60.0f, 8); - message.Write((byte)(MathHelper.Clamp(oxygen * 2.55f, 0.0f, 255.0f))); + message.WriteRangedSingle(oxygen, -100.0f, 100.0f, 8); bleeding = MathHelper.Clamp(bleeding, 0.0f, 5.0f); message.WriteRangedSingle(bleeding, 0.0f, 5.0f, 8); @@ -1635,14 +1651,16 @@ namespace Barotrauma inventory.ReadNetworkData(NetworkEventType.InventoryUpdate, message, sendingTime); return; case NetworkEventType.ImportantEntityUpdate: - - health = MathHelper.Clamp((message.ReadByte() / 255.0f) * maxHealth, 0.0f, maxHealth); - if (health == 0.0f) - { - causeOfDeath = (CauseOfDeath)message.ReadRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1); - Kill(causeOfDeath, true); - } + health = message.ReadRangedSingle(minHealth, 100.0f, 8); + + // MathHelper.Clamp((message.ReadByte() / 255.0f) * maxHealth, 0.0f, maxHealth); + + //if (health == 0.0f) + //{ + // causeOfDeath = (CauseOfDeath)message.ReadRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1); + // Kill(causeOfDeath, true); + //} bool allOk = message.ReadBoolean(); if (allOk) @@ -1654,8 +1672,8 @@ namespace Barotrauma float newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); StartStun(newStunTimer); - - Oxygen = (message.ReadByte() / 2.55f); + + Oxygen = message.ReadRangedSingle(-100.0f,100.0f, 8); Bleeding = message.ReadRangedSingle(0.0f, 5.0f, 8); return; diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index 4b22da7c3..e13f11d7c 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; +using Barotrauma.Items.Components; namespace Barotrauma { @@ -55,87 +56,107 @@ namespace Barotrauma damageOverlay = new Sprite("Content/UI/damageOverlay.png", Vector2.Zero); } + if (character.Inventory != null) + { + for (int i = 0; i< character.Inventory.Items.Length-1; i++) + { + var item = character.Inventory.Items[i]; + if (item == null || CharacterInventory.limbSlots[i]==LimbSlot.Any) continue; + var statusHUD = item.GetComponent(); + if (statusHUD == null) continue; + + statusHUD.DrawHUD(spriteBatch, character); + } + } + DrawStatusIcons(spriteBatch, character); - if (character.Inventory != null && !character.LockHands && - !character.IsUnconscious && character.Stun >= -0.1f) character.Inventory.DrawOwn(spriteBatch, Vector2.Zero); - - if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory!=null) + if (!character.IsUnconscious) { - character.SelectedCharacter.Inventory.DrawOwn(spriteBatch, new Vector2(320.0f, 0.0f)); + if (character.Inventory != null && !character.LockHands && + character.Stun >= -0.1f) character.Inventory.DrawOwn(spriteBatch, Vector2.Zero); - if (cprButton == null) + if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null) { - cprButton = new GUIButton( - new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(150+320, 0), new Point(130, 20)), "Perform CPR", GUI.Style); + character.SelectedCharacter.Inventory.DrawOwn(spriteBatch, new Vector2(320.0f, 0.0f)); - cprButton.OnClicked = (button, userData) => + if (cprButton == null) { - if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false; + cprButton = new GUIButton( + new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(150 + 320, 0), new Point(130, 20)), "Perform CPR", GUI.Style); - Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ? - AnimController.Animation.None : AnimController.Animation.CPR; - - foreach (Limb limb in Character.Controlled.SelectedCharacter.AnimController.Limbs) + cprButton.OnClicked = (button, userData) => { - limb.pullJoint.Enabled = false; - } + if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false; - new NetworkEvent(NetworkEventType.SelectCharacter, Character.Controlled.ID, true, Character.Controlled.SelectedCharacter); + Character.Controlled.AnimController.Anim = (Character.Controlled.AnimController.Anim == AnimController.Animation.CPR) ? + AnimController.Animation.None : AnimController.Animation.CPR; - return true; - }; + foreach (Limb limb in Character.Controlled.SelectedCharacter.AnimController.Limbs) + { + limb.pullJoint.Enabled = false; + } + + new NetworkEvent(NetworkEventType.SelectCharacter, Character.Controlled.ID, true, Character.Controlled.SelectedCharacter); + + return true; + }; + } + + //cprButton.Visible = character.GetSkillLevel("Medical") > 20.0f; + + if (cprButton.Visible) cprButton.Draw(spriteBatch); } - //cprButton.Visible = character.GetSkillLevel("Medical") > 20.0f; - - if (cprButton.Visible) cprButton.Draw(spriteBatch); - } - - if (character.ClosestCharacter != null && character.ClosestCharacter.CanBeSelected) - { - Vector2 startPos = character.DrawPosition + (character.ClosestCharacter.DrawPosition - character.DrawPosition) * 0.7f; - startPos = cam.WorldToScreen(startPos); - - Vector2 textPos = startPos; - textPos -= new Vector2(GUI.Font.MeasureString(character.ClosestCharacter.Info.Name).X / 2, 20); - - GUI.DrawString(spriteBatch, textPos, character.ClosestCharacter.Info.Name, Color.White, Color.Black, 2); - } - else if (character.SelectedCharacter == null && character.ClosestItem != null && character.SelectedConstruction == null) - { - var hudTexts = character.ClosestItem.GetHUDTexts(character); - - Vector2 startPos = new Vector2((int)(GameMain.GraphicsWidth / 2.0f), GameMain.GraphicsHeight); - startPos.Y -= 50 + hudTexts.Count * 25; - - Vector2 textPos = startPos; - textPos -= new Vector2((int)GUI.Font.MeasureString(character.ClosestItem.Name).X / 2, 20); - - GUI.DrawString(spriteBatch, textPos, character.ClosestItem.Name, Color.White, Color.Black * 0.7f, 2); - - textPos.Y += 30.0f; - foreach (ColoredText coloredText in hudTexts) + if (character.ClosestCharacter != null && character.ClosestCharacter.CanBeSelected) { - textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X / 2); + Vector2 startPos = character.DrawPosition + (character.ClosestCharacter.DrawPosition - character.DrawPosition) * 0.7f; + startPos = cam.WorldToScreen(startPos); - GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color, Color.Black*0.7f, 2, GUI.SmallFont); - - textPos.Y += 25; + Vector2 textPos = startPos; + textPos -= new Vector2(GUI.Font.MeasureString(character.ClosestCharacter.Info.Name).X / 2, 20); + + GUI.DrawString(spriteBatch, textPos, character.ClosestCharacter.Info.Name, Color.White, Color.Black, 2); } + else if (character.SelectedCharacter == null && character.ClosestItem != null && character.SelectedConstruction == null) + { + var hudTexts = character.ClosestItem.GetHUDTexts(character); + + Vector2 startPos = new Vector2((int)(GameMain.GraphicsWidth / 2.0f), GameMain.GraphicsHeight); + startPos.Y -= 50 + hudTexts.Count * 25; + + Vector2 textPos = startPos; + textPos -= new Vector2((int)GUI.Font.MeasureString(character.ClosestItem.Name).X / 2, 20); + + GUI.DrawString(spriteBatch, textPos, character.ClosestItem.Name, Color.White, Color.Black * 0.7f, 2); + + textPos.Y += 30.0f; + foreach (ColoredText coloredText in hudTexts) + { + textPos.X = (int)(startPos.X - GUI.SmallFont.MeasureString(coloredText.Text).X / 2); + + GUI.DrawString(spriteBatch, textPos, coloredText.Text, coloredText.Color, Color.Black * 0.7f, 2, GUI.SmallFont); + + textPos.Y += 25; + } + } } + + if (Screen.Selected == GameMain.EditMapScreen) return; - if (character.Oxygen < 80.0f && !character.IsDead) + if (character.IsUnconscious || (character.Oxygen < 80.0f && !character.IsDead)) { Vector2 offset = Rand.Vector(noiseOverlay.size.X); offset.X = Math.Abs(offset.X); offset.Y = Math.Abs(offset.Y); + float alpha = character.IsUnconscious ? 1.0f : Math.Min((80.0f - character.Oxygen)/50.0f, 0.8f); + noiseOverlay.DrawTiled(spriteBatch, Vector2.Zero - offset, new Vector2(GameMain.GraphicsWidth, GameMain.GraphicsHeight) + offset, Vector2.Zero, - Color.White * Math.Min((80.0f - character.Oxygen) / 50.0f, 0.8f)); + Color.White * alpha); } if (damageOverlayTimer>0.0f) diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index dac52bf6f..950385fb7 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -250,6 +250,9 @@ namespace Barotrauma.Networking { if (gameStarted && Screen.Selected == GameMain.GameScreen) { + chatBox.Visible = Character.Controlled == null || !Character.Controlled.IsUnconscious; + chatMsgBox.Visible = chatBox.Visible; + inGameHUD.Update(deltaTime); GameMain.GameSession.CrewManager.Update(deltaTime); diff --git a/Subsurface/Source/Screens/GameScreen.cs b/Subsurface/Source/Screens/GameScreen.cs index 478f2971f..0dbbc797e 100644 --- a/Subsurface/Source/Screens/GameScreen.cs +++ b/Subsurface/Source/Screens/GameScreen.cs @@ -66,39 +66,6 @@ namespace Barotrauma /// Provides a snapshot of timing values. public override void Update(double deltaTime) { - //if (PlayerInput.KeyHit(Keys.T)) - //{ - // Stopwatch sw = new Stopwatch(); - // sw.Start(); - - // Rand.SetSyncedSeed(123); - - // for (int i = 0; i<10000; i++) - // { - // Hull.FindHull(new Vector2( - // Rand.Range(Submarine.Borders.X, Submarine.Borders.Right, false), - // Rand.Range(Submarine.Borders.Y - Submarine.Borders.Height, Submarine.Borders.Y, false)), - // Hull.hullList[Rand.Int(Hull.hullList.Count-1)], false); - // } - - // sw.Stop(); - // Debug.WriteLine("FindHull1: "+sw.ElapsedMilliseconds); - // sw.Restart(); - // Rand.SetSyncedSeed(123); - // for (int i = 0; i < 10000; i++) - // { - // Hull.FindHull2(new Vector2( - // Rand.Range(Submarine.Borders.X, Submarine.Borders.Right, false), - // Rand.Range(Submarine.Borders.Y - Submarine.Borders.Height, Submarine.Borders.Y, false)), - // Hull.hullList[Rand.Int(Hull.hullList.Count - 1)], false); - // } - - // sw.Stop(); - // Debug.WriteLine("FindHull2: " + sw.ElapsedMilliseconds); - // var askdnkjd = 1; - //} - - //the accumulator code is based on this article: //http://gafferongames.com/game-physics/fix-your-timestep/ Physics.accumulator += deltaTime; @@ -173,11 +140,6 @@ namespace Barotrauma public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch) { - //if (Character.Controlled != null) - //{ - // cam.TargetPos = Character.Controlled.WorldPosition; - //} - cam.UpdateTransform(); DrawMap(graphics, spriteBatch);