diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs index 8a9f1ebc4..a2c3e861b 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs @@ -13,6 +13,8 @@ namespace Barotrauma private static Sprite noiseOverlay, damageOverlay; private static GUIButton cprButton; + + private static GUIButton grabHoldButton; private static GUIButton suicideButton; @@ -41,6 +43,8 @@ namespace Barotrauma if (cprButton != null && cprButton.Visible) cprButton.AddToGUIUpdateList(); + if (grabHoldButton != null && cprButton.Visible) grabHoldButton.AddToGUIUpdateList(); + if (suicideButton != null && suicideButton.Visible) suicideButton.AddToGUIUpdateList(); if (!character.IsUnconscious && character.Stun <= 0.0f) @@ -89,6 +93,8 @@ namespace Barotrauma if (cprButton != null && cprButton.Visible) cprButton.Update(deltaTime); + if (grabHoldButton != null && grabHoldButton.Visible) grabHoldButton.Update(deltaTime); + if (suicideButton != null && suicideButton.Visible) suicideButton.Update(deltaTime); if (damageOverlayTimer > 0.0f) damageOverlayTimer -= deltaTime; @@ -195,9 +201,37 @@ namespace Barotrauma }; } + if (grabHoldButton == null) + { + grabHoldButton = new GUIButton( + new Rectangle(character.SelectedCharacter.Inventory.SlotPositions[0].ToPoint() + new Point(320, -60), new Point(130, 20)), + "Grabbing: " + (character.AnimController.GrabLimb == LimbType.Torso ? "Torso" : "Hands"), ""); + + grabHoldButton.OnClicked = (button, userData) => + { + if (Character.Controlled == null || Character.Controlled.SelectedCharacter == null) return false; + + Character.Controlled.AnimController.GrabLimb = Character.Controlled.AnimController.GrabLimb == LimbType.None ? LimbType.Torso : LimbType.None; + + foreach (Limb limb in Character.Controlled.SelectedCharacter.AnimController.Limbs) + { + limb.pullJoint.Enabled = false; + } + + if (GameMain.Client != null) + { + GameMain.Client.CreateEntityEvent(Character.Controlled, new object[] { NetEntityEvent.Type.Control }); + } + + grabHoldButton.Text = "Grabbing: " + (Character.Controlled.AnimController.GrabLimb == LimbType.Torso ? "Torso" : "Hands"); + return true; + }; + } + //cprButton.Visible = character.GetSkillLevel("Medical") > 20.0f; if (cprButton.Visible) cprButton.Draw(spriteBatch); + if (grabHoldButton.Visible) grabHoldButton.Draw(spriteBatch); } if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs index 82418a2a4..51d728219 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterNetworking.cs @@ -17,15 +17,19 @@ namespace Barotrauma switch ((NetEntityEvent.Type)extraData[0]) { case NetEntityEvent.Type.InventoryState: - msg.WriteRangedInteger(0, 2, 0); + msg.WriteRangedInteger(0, 3, 0); inventory.ClientWrite(msg, extraData); break; case NetEntityEvent.Type.Repair: - msg.WriteRangedInteger(0, 2, 1); + msg.WriteRangedInteger(0, 3, 1); msg.Write(AnimController.Anim == AnimController.Animation.CPR); break; case NetEntityEvent.Type.Status: - msg.WriteRangedInteger(0, 2, 2); + msg.WriteRangedInteger(0, 3, 2); + break; + case NetEntityEvent.Type.Control: + msg.WriteRangedInteger(0, 3, 3); + msg.Write((UInt16)AnimController.GrabLimb); break; } } @@ -91,6 +95,7 @@ namespace Barotrauma bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); + AnimController.GrabLimb = (LimbType)msg.ReadUInt16(); } bool hasAttackLimb = msg.ReadBoolean(); @@ -367,6 +372,9 @@ namespace Barotrauma SetStun(0.0f, true, true); } + bool ragdolled = msg.ReadBoolean(); + IsRagdolled = ragdolled; + bool huskInfected = msg.ReadBoolean(); if (huskInfected) { diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameServerSettings.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameServerSettings.cs index 7c694d39a..229fe6432 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameServerSettings.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameServerSettings.cs @@ -320,7 +320,7 @@ namespace Barotrauma.Networking return true; }; - y += 40; + y += 20; var voteKickBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Allow vote kicking", Alignment.Left, settingsTabs[1]); voteKickBox.Selected = Voting.AllowVoteKick; @@ -357,7 +357,7 @@ namespace Barotrauma.Networking return true; }; - y += 40; + y += 20; var randomizeLevelBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Randomize level seed between rounds", Alignment.Left, settingsTabs[1]); randomizeLevelBox.Selected = RandomizeSeed; @@ -367,7 +367,7 @@ namespace Barotrauma.Networking return true; }; - y += 40; + y += 20; var saveLogsBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Save server logs", Alignment.Left, settingsTabs[1]); saveLogsBox.Selected = SaveServerLogs; @@ -378,6 +378,83 @@ namespace Barotrauma.Networking return true; }; + y += 20; + + var ragdollButtonBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Allow ragdoll button", Alignment.Left, settingsTabs[1]); + ragdollButtonBox.Selected = AllowRagdollButton; + ragdollButtonBox.OnSelected = (GUITickBox) => + { + AllowRagdollButton = GUITickBox.Selected; + return true; + }; + + y += 20; + + var traitorRatioBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Use % of players for max traitors", Alignment.Left, settingsTabs[1]); + var traitorRatioText = new GUITextBlock(new Rectangle(20, y + 20, 20, 20), "Traitor ratio: 20 %", "", settingsTabs[1], GUI.SmallFont); + var traitorRatioSlider = new GUIScrollBar(new Rectangle(150, y + 22, 100, 15), "", 0.1f, settingsTabs[1]); + //Prepare the slider before the tick box + if (traitorUseRatio) + { + traitorRatioSlider.UserData = traitorRatioText; + traitorRatioSlider.Step = 0.01f; //Lots of fine-tuning + traitorRatioSlider.BarScroll = (traitorRatio - 0.1f) / 0.9f; + } + else + { + traitorRatioSlider.UserData = traitorRatioText; + traitorRatioSlider.Step = 1f / (maxPlayers-1); + traitorRatioSlider.BarScroll = MathUtils.Round(traitorRatio, 1f); + } + //Slider END + + traitorRatioBox.Selected = traitorUseRatio; + traitorRatioBox.OnSelected = (GUITickBox) => + { + traitorUseRatio = GUITickBox.Selected; + //Affect the slider graphics + if (traitorUseRatio) + { + traitorRatioSlider.UserData = traitorRatioText; + traitorRatioSlider.Step = 0.01f; //Lots of fine-tuning + traitorRatioSlider.BarScroll = 0.2f; //default values + traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll); //Update the scroll bar + } + else + { + traitorRatioSlider.UserData = traitorRatioText; + traitorRatioSlider.Step = 1f / (maxPlayers-1); + traitorRatioSlider.BarScroll = 1; //default values + traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll); //Update the scroll bar + } + return true; + }; + traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) => + { + GUITextBlock traitorText = scrollBar.UserData as GUITextBlock; + if (traitorUseRatio) + { + traitorRatio = barScroll * 0.9f + 0.1f; + traitorText.Text = "Traitor ratio: " + (int)MathUtils.Round(traitorRatio * 100.0f, 1.0f) + " %"; + } + else + { + traitorRatio = MathUtils.Round(barScroll * (maxPlayers-1), 1f) + 1; + traitorText.Text = "Traitor count: " + traitorRatio; + } + return true; + }; + traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll); + + y += 45; + + var karmaButtonBox = new GUITickBox(new Rectangle(0, y, 20, 20), "Use Karma", Alignment.Left, settingsTabs[1]); + karmaButtonBox.Selected = KarmaEnabled; + karmaButtonBox.OnSelected = (GUITickBox) => + { + KarmaEnabled = GUITickBox.Selected; + return true; + }; //-------------------------------------------------------------------------------- // banlist diff --git a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/misc.xml b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/misc.xml index cdb8cb115..c94e03422 100644 --- a/Barotrauma/BarotraumaShared/Content/Items/Jobgear/misc.xml +++ b/Barotrauma/BarotraumaShared/Content/Items/Jobgear/misc.xml @@ -14,13 +14,16 @@ - - - - + + + + + + + + - diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/AnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/AnimController.cs index 28cfc35c4..7fcc25d17 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/AnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/AnimController.cs @@ -9,6 +9,8 @@ namespace Barotrauma public enum Animation { None, Climbing, UsingConstruction, Struggle, CPR }; public Animation Anim; + public LimbType GrabLimb; + protected Character character; protected float walkSpeed, swimSpeed; diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs index 9dbaf2193..d77bc2bac 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Animation/HumanoidAnimController.cs @@ -20,6 +20,7 @@ namespace Barotrauma private float thighTorque; private float cprAnimState; + private float cprPump; private float inWaterTimer; private bool swimming; @@ -872,7 +873,34 @@ namespace Barotrauma character.SelectedConstruction = null; IgnorePlatforms = false; } + else if (character.SelectedCharacter != null && !character.SelectedCharacter.AllowInput) + { + Limb targetLeftHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.LeftHand); + Limb targetRightHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.RightHand); + Limb targetTorso = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso); + if (character.SelectedCharacter.AnimController.Dir != Dir) + character.SelectedCharacter.AnimController.Flip(); + + targetTorso.pullJoint.Enabled = true; + targetTorso.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * -Dir) * 0.2f; + targetTorso.pullJoint.MaxForce = 5000.0f; + + if (!targetLeftHand.IsSevered) + { + targetLeftHand.pullJoint.Enabled = true; + targetLeftHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f; + targetLeftHand.pullJoint.MaxForce = 5000.0f; + } + if (!targetRightHand.IsSevered) + { + targetRightHand.pullJoint.Enabled = true; + targetRightHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f; + targetRightHand.pullJoint.MaxForce = 5000.0f; + } + + character.SelectedCharacter.AnimController.IgnorePlatforms = true; + } } private void UpdateCPR(float deltaTime) @@ -883,11 +911,16 @@ namespace Barotrauma return; } + Character target = character.SelectedCharacter; + Crouching = true; - Vector2 diff = character.SelectedCharacter.SimPosition - character.SimPosition; - var targetHead = character.SelectedCharacter.AnimController.GetLimb(LimbType.Head); - + Vector2 diff = target.SimPosition - character.SimPosition; + Limb targetHead = target.AnimController.GetLimb(LimbType.Head); + Limb targetTorso = target.AnimController.GetLimb(LimbType.Torso); + Limb head = GetLimb(LimbType.Head); + Limb torso = GetLimb(LimbType.Torso); + Vector2 headDiff = targetHead == null ? diff : targetHead.SimPosition - character.SimPosition; targetMovement = new Vector2(diff.X, 0.0f); @@ -895,21 +928,104 @@ namespace Barotrauma UpdateStanding(); - Vector2 handPos = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso).SimPosition + Vector2.UnitY * 0.2f; + Vector2 handPos = targetTorso.SimPosition + Vector2.UnitY * 0.2f; Grab(handPos, handPos); - float yPos = (float)Math.Sin(cprAnimState) * 0.1f; - cprAnimState += deltaTime * 8.0f; + Vector2 colliderPos = GetColliderBottom(); - var head = GetLimb(LimbType.Head); - head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.6f + yPos); - head.pullJoint.Enabled = true; + if (GameMain.Client == null) //Serverside code + { + if (target.Bleeding <= 0.5f && target.Oxygen <= 0.0f) //If they're bleeding too hard CPR will hurt them + { + target.Oxygen += deltaTime * 0.5f; //Stabilize them + } + } + + + int skill = character.GetSkillLevel("Medical"); + if (cprAnimState % 17 > 15.0f) + { + float yPos = (float)Math.Sin(cprAnimState) * 0.2f; + head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.3f + yPos); + head.pullJoint.Enabled = true; + torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.2f)); + torso.pullJoint.Enabled = true; + + if (GameMain.Client == null) //Serverside code + { + float cpr = skill / 2.0f; //Max possible oxygen addition is 20 per second + character.Oxygen -= (30.0f - cpr) * deltaTime; //Worse skill = more oxygen required + if (character.Oxygen > 0.0f) //we didn't suffocate yet did we + target.Oxygen += cpr * deltaTime; + + //DebugConsole.NewMessage("CPR Us: " + character.Oxygen + " Them: " + target.Oxygen + " How good we are: restore " + cpr + " use " + (30.0f - cpr), Color.Aqua); + } + } + else + { + head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.8f); + head.pullJoint.Enabled = true; + torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.1f)); + torso.pullJoint.Enabled = true; + if (cprPump >= 1) + { + torso.body.ApplyForce(new Vector2(0, -1000f)); + targetTorso.body.ApplyForce(new Vector2(0, -1000f)); + cprPump = 0; + + if (target.Bleeding <= 0.5f && target.Health <= 0.0f && !target.IsDead) //Have a chance to revive them to 2 HP if they were damaged. + { + if (GameMain.Client == null) //Serverside code + { + float reviveChance = (cprAnimState % 17) * (skill / 50.0f); //~5% max chance for 10 skill, ~50% max chance for 100 skill + float rng = Rand.Int(100, Rand.RandSync.Server); + + //DebugConsole.NewMessage("CPR Pump cprAnimState: " + (cprAnimState % 17) + " revive chance: " + reviveChance + " rng: " + rng, Color.Aqua); + if (rng <= reviveChance) //HOLY CRAP YOU SAVED HIM!!! + { + target.Oxygen = Math.Max(target.Oxygen, 10.0f); + target.Health = 2.0f; + Anim = Animation.None; + return; + } + } + } + else if (target.Bleeding > 0.5f || skill < 50) //We will hurt them if they're bleeding or we suck + { + //If not bleeding: 10% skill causes 0.8 damage per pump, 40% skill causes only 0.2 + if (target.Bleeding <= 0.5f) + target.AddDamage(CauseOfDeath.Damage, (50 - skill) * 0.02f, character); + else //If bleeding: 2 HP damage per pump. Basically speeds up their death. Don't pump bleeding people! + { + target.AddDamage(CauseOfDeath.Bloodloss, 1.0f, character); +#if CLIENT + SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, 25.0f, targetTorso.body); + float bloodParticleAmount = 4; + float bloodParticleSize = 1.0f; + + for (int i = 0; i < bloodParticleAmount; i++) + { + var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", targetTorso.WorldPosition, Rand.Vector(10.0f), 0.0f, target.AnimController.CurrentHull); + if (blood != null) + { + blood.Size *= bloodParticleSize; + } + } +#endif + } + } + } + cprPump += deltaTime; + } + + cprAnimState += deltaTime; } public override void DragCharacter(Character target) { if (target == null) return; + Limb torso = GetLimb(LimbType.Torso); Limb leftHand = GetLimb(LimbType.LeftHand); Limb rightHand = GetLimb(LimbType.RightHand); @@ -922,31 +1038,34 @@ namespace Barotrauma for (int i = 0; i < 2; i++) { - Limb targetLimb = target.AnimController.GetLimb(LimbType.Torso); + Limb targetLimb = target.AnimController.GetLimb(GrabLimb); - if (i == 0) + if (targetLimb == null || targetLimb.IsSevered) { - if (!targetLeftHand.IsSevered) + targetLimb = target.AnimController.GetLimb(LimbType.Torso); + if (i == 0) { - targetLimb = targetLeftHand; + if (!targetLeftHand.IsSevered) + { + targetLimb = targetLeftHand; + } + else if (!targetRightHand.IsSevered) + { + targetLimb = targetRightHand; + } } - else if (!targetRightHand.IsSevered) + else { - targetLimb = targetRightHand; + if (!targetRightHand.IsSevered) + { + targetLimb = targetRightHand; + } + else if (!targetLeftHand.IsSevered) + { + targetLimb = targetLeftHand; + } } } - else - { - if (!targetRightHand.IsSevered) - { - targetLimb = targetRightHand; - } - else if (!targetLeftHand.IsSevered) - { - targetLimb = targetLeftHand; - } - } - Limb pullLimb = i == 0 ? leftHand : rightHand; if (i == 1 && inWater) @@ -958,12 +1077,32 @@ namespace Barotrauma Vector2 diff = ConvertUnits.ToSimUnits(targetLimb.WorldPosition - pullLimb.WorldPosition); pullLimb.pullJoint.Enabled = true; - pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff; - pullLimb.pullJoint.MaxForce = 10000.0f; + if (targetLimb.type == LimbType.Torso) + { + pullLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition; + pullLimb.pullJoint.MaxForce = 5000.0f; + targetMovement *= 0.7f; //Carrying people like that takes a lot of effort. + + if (target.AnimController.Dir != Dir) + target.AnimController.Flip(); + } + else + { + pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff; + pullLimb.pullJoint.MaxForce = 5000.0f; + } targetLimb.pullJoint.Enabled = true; - targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff; - targetLimb.pullJoint.MaxForce = 10000.0f; + if (targetLimb.type == LimbType.Torso) + { + targetLimb.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * Dir) * 0.6f; + targetLimb.pullJoint.MaxForce = 300.0f; + } + else + { + targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff; + targetLimb.pullJoint.MaxForce = 5000.0f; + } target.AnimController.movement = -diff; } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 6819a412f..ad03fcce7 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -1383,7 +1383,7 @@ namespace Barotrauma findFocusedTimer -= deltaTime; } - if (SelectedCharacter != null && IsKeyHit(InputType.Select)) + if (SelectedCharacter != null && focusedItem == null && IsKeyHit(InputType.Select)) //Let people use ladders and buttons and stuff when dragging chars { DeselectCharacter(); } @@ -1541,26 +1541,42 @@ namespace Barotrauma } } + //Skip health effects as critical health handles it differently if (IsUnconscious) { UpdateUnconscious(deltaTime); return; } + //Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us! if (IsForceRagdolled) IsRagdolled = IsForceRagdolled; - else if (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f) //Keep us ragdolled if we were forced or we're too speedy to unragdoll + else if ((GameMain.Server == null || GameMain.Server.AllowRagdollButton) && (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f)) //Keep us ragdolled if we were forced or we're too speedy to unragdoll IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves + //Health effects + if (needsAir) UpdateOxygen(deltaTime); + + Health -= bleeding * deltaTime; + Bleeding -= BleedingDecreaseSpeed * deltaTime; + + if (health <= minHealth) Kill(CauseOfDeath.Bloodloss); + + if (!IsDead) LockHands = false; + + //ragdoll button if (IsRagdolled) { if (AnimController is HumanoidAnimController) ((HumanoidAnimController)AnimController).Crouching = false; - + if(GameMain.Server != null) + GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status }); AnimController.ResetPullJoints(); selectedConstruction = null; return; } + //AI and control stuff + Control(deltaTime, cam); if (controlled != this && (!(this is AICharacter) || IsRemotePlayer)) { @@ -1573,24 +1589,12 @@ namespace Barotrauma selectedConstruction = null; } - if (SelectedCharacter != null && AnimController.Anim == AnimController.Animation.CPR) - { - if (GameMain.Client == null) SelectedCharacter.Oxygen += (GetSkillLevel("Medical") / 10.0f) * deltaTime; - } - UpdateSightRange(); if (aiTarget != null) aiTarget.SoundRange = 0.0f; lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f); - if (needsAir) UpdateOxygen(deltaTime); - - Health -= bleeding * deltaTime; - Bleeding -= BleedingDecreaseSpeed * deltaTime; - - if (health <= minHealth) Kill(CauseOfDeath.Bloodloss); - - if (!IsDead) LockHands = false; + //CPR stuff is handled in the UpdateCPR function in HumanoidAnimController } partial void UpdateControlled(float deltaTime, Camera cam); @@ -1630,12 +1634,17 @@ namespace Barotrauma AnimController.ResetPullJoints(); selectedConstruction = null; - if (oxygen <= 0.0f) Oxygen -= deltaTime * 0.5f; + Oxygen -= deltaTime * 0.5f; //We're critical - our heart stopped! - if (health <= 0.0f) + if (health <= 0.0f) //Critical health - use current state for crit time { AddDamage(bleeding > 0.5f ? CauseOfDeath.Bloodloss : CauseOfDeath.Damage, Math.Max(bleeding, 1.0f) * deltaTime, null); } + else //Keep on bleedin' + { + Health -= bleeding * deltaTime; + Bleeding -= BleedingDecreaseSpeed * deltaTime; + } } private void UpdateSightRange() diff --git a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs index 1a6ec6b07..0420bbab4 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs @@ -325,7 +325,7 @@ namespace Barotrauma break; case ClientNetObject.ENTITY_STATE: - int eventType = msg.ReadRangedInteger(0,2); + int eventType = msg.ReadRangedInteger(0,3); switch (eventType) { case 0: @@ -357,6 +357,9 @@ namespace Barotrauma Kill(lastAttackCauseOfDeath); } break; + case 3: + AnimController.GrabLimb = (LimbType)msg.ReadUInt16(); + break; } break; } @@ -436,6 +439,7 @@ namespace Barotrauma if (AnimController is HumanoidAnimController) { tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching); + tempBuffer.Write((UInt16)AnimController.GrabLimb); } bool hasAttackLimb = AnimController.Limbs.Any(l => l != null && l.attack != null); @@ -534,6 +538,8 @@ namespace Barotrauma msg.WriteRangedSingle(MathHelper.Clamp(Stun, 0.0f, MaxStun), 0.0f, MaxStun, 8); } + msg.Write(IsRagdolled); + msg.Write(HuskInfectionState > 0.0f); } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs index 6e2622276..beb737fb9 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs @@ -678,14 +678,13 @@ namespace Barotrauma if (!MathUtils.IsValid(damage)) return; - float damageDiff = damage - sections[sectionIndex].damage; + if (GameMain.Server != null && damage != sections[sectionIndex].damage) { GameMain.Server.CreateEntityEvent(this); } - AdjustKarma(attacker, damageDiff); if (damage < prefab.Health*0.5f) { if (sections[sectionIndex].gap != null) @@ -717,10 +716,14 @@ namespace Barotrauma sections[sectionIndex].gap.Open = (damage / prefab.Health - 0.5f) * 2.0f; } - + + float damageDiff = damage - sections[sectionIndex].damage; bool hadHole = SectionBodyDisabled(sectionIndex); sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, prefab.Health); + if (sections[sectionIndex].damage < prefab.Health) //otherwise it's possible to infinitely gain karma by welding fixed things + AdjustKarma(attacker, damageDiff); + bool hasHole = SectionBodyDisabled(sectionIndex); if (hadHole == hasHole) return; diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs index e1b103cd4..43e9ad779 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServerSettings.cs @@ -133,6 +133,13 @@ namespace Barotrauma.Networking private set; } + [Serialize(true, true)] + public bool AllowRagdollButton + { + get; + private set; + } + [Serialize(true, true)] public bool AllowFileTransfers { @@ -213,6 +220,20 @@ namespace Barotrauma.Networking private set; } + [Serialize(true, true)] + public bool traitorUseRatio + { + get; + private set; + } + + [Serialize(0.2f, true)] + public float traitorRatio + { + get; + private set; + } + [Serialize(false,true)] public bool KarmaEnabled { diff --git a/Barotrauma/BarotraumaShared/serversettings.xml b/Barotrauma/BarotraumaShared/serversettings.xml index 1eb8f2d21..18abd505a 100644 --- a/Barotrauma/BarotraumaShared/serversettings.xml +++ b/Barotrauma/BarotraumaShared/serversettings.xml @@ -15,11 +15,15 @@ allowspectating="True" endroundatlevelend="True" saveserverlogs="True" + allowragdollbutton="True" allowfiletransfers="True" allowrespawn="True" allowvotekick="True" endvoterequiredratio="0.6" kickvoterequiredratio="0.6" + traitoruseratio="True" + traitorratio="0.2" + karmaenabled="False" SubSelection="Manual" ModeSelection="Manual" TraitorsEnabled="No"