]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Zombies recover faster from crit. They heal Piercing damage (#16325)
authorTom Leys <tom@crump-leys.com>
Tue, 16 May 2023 03:58:36 +0000 (15:58 +1200)
committerGitHub <noreply@github.com>
Tue, 16 May 2023 03:58:36 +0000 (23:58 -0400)
Content.Server/Zombies/ZombieSystem.cs
Content.Shared/Zombies/ZombieComponent.cs
Resources/Locale/en-US/game-ticking/game-presets/preset-zombies.ftl
Resources/Locale/en-US/zombies/zombie.ftl

index 8f4b737fb6a77397d96a1b1f03777ae29e870ef0..8d5d0cd793ed327c03f8c96c6b48301071681a9b 100644 (file)
@@ -14,6 +14,8 @@ using Content.Shared.Damage;
 using Content.Shared.Inventory;
 using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
+using Content.Shared.Mobs.Systems;
+using Content.Shared.Popups;
 using Content.Shared.Weapons.Melee.Events;
 using Content.Shared.Zombies;
 using Robust.Shared.Prototypes;
@@ -35,6 +37,9 @@ namespace Content.Server.Zombies
         [Dependency] private readonly AutoEmoteSystem _autoEmote = default!;
         [Dependency] private readonly EmoteOnDamageSystem _emoteOnDamage = default!;
         [Dependency] private readonly HumanoidAppearanceSystem _humanoidSystem = default!;
+        [Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
+        [Dependency] private readonly MobStateSystem _mobState = default!;
+        [Dependency] private readonly SharedPopupSystem _popup = default!;
 
         public override void Initialize()
         {
@@ -60,12 +65,15 @@ namespace Content.Server.Zombies
         public override void Update(float frameTime)
         {
             base.Update(frameTime);
-            var query = EntityQueryEnumerator<PendingZombieComponent>();
+            var query = EntityQueryEnumerator<PendingZombieComponent, DamageableComponent>();
             var curTime = _timing.CurTime;
 
+            var zombQuery = EntityQueryEnumerator<ZombieComponent, DamageableComponent, MobStateComponent>();
+
             // Hurt the living infected
-            while (query.MoveNext(out var uid, out var comp))
+            while (query.MoveNext(out var uid, out var comp, out var damage))
             {
+                // Process only once per second
                 if (comp.NextTick + TimeSpan.FromSeconds(1) > curTime)
                     continue;
 
@@ -74,18 +82,34 @@ namespace Content.Server.Zombies
                 // 1x at 30s, 3x at 60s, 6x at 90s, 10x at 120s.
                 var pain_multiple = 0.1 + 0.02 * comp.InfectedSecs + 0.0005 * comp.InfectedSecs * comp.InfectedSecs;
                 comp.NextTick = curTime;
-                _damageable.TryChangeDamage(uid, comp.Damage * pain_multiple, true, false);
+                _damageable.TryChangeDamage(uid, comp.Damage * pain_multiple, true, false, damage);
             }
 
-            var zomb_query = EntityQueryEnumerator<ZombieComponent>();
             // Heal the zombified
-            while (zomb_query.MoveNext(out var uid, out var comp))
+            while (zombQuery.MoveNext(out var uid, out var comp, out var damage, out var mobState))
             {
+                // Process only once per second
                 if (comp.NextTick + TimeSpan.FromSeconds(1) > curTime)
                     continue;
 
                 comp.NextTick = curTime;
-                _damageable.TryChangeDamage(uid, comp.Damage, true, false);
+
+                if (comp.Permadeath)
+                {
+                    // No healing
+                    continue;
+                }
+
+                if (mobState.CurrentState == MobState.Alive)
+                {
+                    // Gradual healing for living zombies.
+                    _damageable.TryChangeDamage(uid, comp.Damage, true, false, damage);
+                }
+                else if (_random.Prob(comp.ZombieReviveChance))
+                {
+                    // There's a small chance to reverse all the zombie's damage (damage.Damage) in one go
+                    _damageable.TryChangeDamage(uid, -damage.Damage, true, false, damage);
+                }
             }
         }
 
@@ -128,6 +152,19 @@ namespace Content.Server.Zombies
 
                 // Stop random groaning
                 _autoEmote.RemoveEmote(uid, "ZombieGroan");
+
+                if (args.NewMobState == MobState.Dead)
+                {
+                    // Roll to see if this zombie is not coming back.
+                    //   Note that due to damage reductions it takes a lot of hits to gib a zombie without this.
+                    if (_random.Prob(component.ZombiePermadeathChance))
+                    {
+                        // You're dead! No reviving for you.
+                        _mobThreshold.SetAllowRevives(uid, false);
+                        component.Permadeath = true;
+                        _popup.PopupEntity(Loc.GetString("zombie-permadeath"), uid, uid);
+                    }
+                }
             }
         }
 
index 02b516263421671d4447520b75f8ef9fdc4c93ec..87943531fc7bf7b5f8184bd65eec7d3bc12cbaa3 100644 (file)
@@ -26,6 +26,25 @@ namespace Content.Shared.Zombies
         [ViewVariables(VVAccess.ReadWrite)]
         public float MaxZombieInfectionChance = 0.40f;
 
+        /// <summary>
+        /// Chance that this zombie be permanently killed (rolled once on crit->death transition)
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        public float ZombiePermadeathChance = 0.70f;
+
+        /// <summary>
+        /// Chance that this zombie will be healed (rolled each second when in crit or dead)
+        ///   3% means you have a 60% chance after 30 secs and a 84% chance after 60.
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        public float ZombieReviveChance = 0.03f;
+
+        /// <summary>
+        /// Has this zombie stopped healing now that it's died for real?
+        /// </summary>
+        [ViewVariables(VVAccess.ReadWrite)]
+        public bool Permadeath = false;
+
         /// <summary>
         /// The minimum infection chance possible. This is simply to prevent
         /// being invincible by bundling up.
@@ -97,8 +116,9 @@ namespace Content.Shared.Zombies
         {
             DamageDict = new ()
             {
-                { "Blunt", -0.3 },
+                { "Blunt", -0.4 },
                 { "Slash", -0.2 },
+                { "Piercing", -0.2 },
                 { "Heat", -0.2 },
                 { "Cold", -0.2 },
                 { "Shock", -0.2 },
index d7e487ba521623fc5e2e2bd69308c4aee7858727..cef09786de547aa98dc2bd780412b748880cc292 100644 (file)
@@ -5,6 +5,7 @@ zombie-not-enough-ready-players = Not enough players readied up for the game! Th
 zombie-no-one-ready = No players readied up! Can't start Zombies.
 
 zombie-patientzero-role-greeting = You are patient 0. Hide your infection, get supplies, and be prepared to turn once you die.
+zombie-healing = You feel a stirring in your flesh
 
 zombie-alone = You feel entirely alone.
 
@@ -24,4 +25,4 @@ zombie-round-end-survivor-count = {$count ->
     [one] There was only one survivor left:
     *[other] There were only {$count} survivors left:
 }
-zombie-round-end-user-was-survivor = - [color=White]{$name}[/color] ([color=gray]{$username}[/color]) survived the outbreak.
\ No newline at end of file
+zombie-round-end-user-was-survivor = - [color=White]{$name}[/color] ([color=gray]{$username}[/color]) survived the outbreak.
index f534a962e09a529aa7a756dd762196dd718f2609..dfcddf33085265bbfcc556ca0832e40df50aa463 100644 (file)
@@ -5,3 +5,5 @@ zombie-generic = zombie
 zombie-name-prefix = Zombified {$target}
 zombie-role-desc =  A malevolent creature of the dead.
 zombie-role-rules = You are an antagonist. Search out the living and bite them in order to infect them and turn them into zombies. Work together with other the zombies to overtake the station.
+
+zombie-permadeath = This time, you're dead for real.