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;
[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()
{
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;
// 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);
+ }
}
}
// 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);
+ }
+ }
}
}
[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.
{
DamageDict = new ()
{
- { "Blunt", -0.3 },
+ { "Blunt", -0.4 },
{ "Slash", -0.2 },
+ { "Piercing", -0.2 },
{ "Heat", -0.2 },
{ "Cold", -0.2 },
{ "Shock", -0.2 },