Zombie virus delayed from 20-30 minutes from rule start. (#16346)
This commit is contained in:
@@ -14,8 +14,7 @@ public sealed class PendingZombieComponent : Component
|
||||
{
|
||||
DamageDict = new ()
|
||||
{
|
||||
{ "Blunt", 0.5 },
|
||||
{ "Cellular", 0.2 },
|
||||
{ "Blunt", 0.8 },
|
||||
{ "Toxin", 0.2 },
|
||||
}
|
||||
};
|
||||
@@ -23,7 +22,37 @@ public sealed class PendingZombieComponent : Component
|
||||
[DataField("nextTick", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextTick;
|
||||
|
||||
// Scales damage over time.
|
||||
[DataField("infectedSecs")]
|
||||
/// <summary>
|
||||
/// Scales damage over time.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("infectedSecs")]
|
||||
public int InfectedSecs;
|
||||
|
||||
/// <summary>
|
||||
/// Number of seconds that a typical infection will last before the player is totally overwhelmed with damage and
|
||||
/// dies.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("maxInfectionLength")]
|
||||
public float MaxInfectionLength = 120f;
|
||||
|
||||
/// <summary>
|
||||
/// Infection warnings are shown as popups, times are in seconds.
|
||||
/// -ve times shown to initial zombies (once timer counts from -ve to 0 the infection starts)
|
||||
/// +ve warnings are in seconds after being bitten
|
||||
/// </summary>
|
||||
[DataField("infectionWarnings")]
|
||||
public Dictionary<int, string> InfectionWarnings = new()
|
||||
{
|
||||
{-45, "zombie-infection-warning"},
|
||||
{-30, "zombie-infection-warning"},
|
||||
{10, "zombie-infection-underway"},
|
||||
{25, "zombie-infection-underway"},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A minimum multiplier applied to Damage once you are in crit to get you dead and ready for your next life
|
||||
/// as fast as possible.
|
||||
/// </summary>
|
||||
[DataField("minimumCritMultiplier")]
|
||||
public float MinimumCritMultiplier = 10;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Content.Server.Zombies
|
||||
SubscribeLocalEvent<ZombieComponent, TryingToSleepEvent>(OnSleepAttempt);
|
||||
|
||||
SubscribeLocalEvent<PendingZombieComponent, MapInitEvent>(OnPendingMapInit);
|
||||
SubscribeLocalEvent<PendingZombieComponent, MobStateChangedEvent>(OnPendingMobState);
|
||||
}
|
||||
|
||||
private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, MapInitEvent args)
|
||||
@@ -65,24 +66,47 @@ namespace Content.Server.Zombies
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
var query = EntityQueryEnumerator<PendingZombieComponent, DamageableComponent>();
|
||||
var query = EntityQueryEnumerator<PendingZombieComponent, DamageableComponent, MobStateComponent>();
|
||||
var curTime = _timing.CurTime;
|
||||
|
||||
var zombQuery = EntityQueryEnumerator<ZombieComponent, DamageableComponent, MobStateComponent>();
|
||||
|
||||
// Hurt the living infected
|
||||
while (query.MoveNext(out var uid, out var comp, out var damage))
|
||||
while (query.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.InfectedSecs += 1;
|
||||
// Pain of becoming a zombie grows over time
|
||||
// 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, damage);
|
||||
|
||||
comp.InfectedSecs += 1;
|
||||
// See if there should be a warning popup for the player.
|
||||
if (comp.InfectionWarnings.TryGetValue(comp.InfectedSecs, out var popupStr))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString(popupStr), uid, uid);
|
||||
}
|
||||
|
||||
if (comp.InfectedSecs < 0)
|
||||
{
|
||||
// This zombie has a latent virus, probably set up by ZombieRuleSystem. No damage yet.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pain of becoming a zombie grows over time
|
||||
// By scaling the number of seconds we have an accessible way to scale this exponential function.
|
||||
// The function was hand tuned to 120 seconds, hence the 120 constant here.
|
||||
var scaledSeconds = (120.0f / comp.MaxInfectionLength) * comp.InfectedSecs;
|
||||
|
||||
// 1x at 30s, 3x at 60s, 6x at 90s, 10x at 120s. Limit at 20x so we don't gib you.
|
||||
var painMultiple = Math.Min(20f, 0.1f + 0.02f * scaledSeconds + 0.0005f * scaledSeconds * scaledSeconds);
|
||||
if (mobState.CurrentState == MobState.Critical)
|
||||
{
|
||||
// Speed up their transformation when they are (or have been) in crit by ensuring their damage
|
||||
// multiplier is at least 10x
|
||||
painMultiple = Math.Max(comp.MinimumCritMultiplier, painMultiple);
|
||||
}
|
||||
_damageable.TryChangeDamage(uid, comp.Damage * painMultiple, true, false, damage);
|
||||
}
|
||||
|
||||
// Heal the zombified
|
||||
@@ -168,6 +192,15 @@ namespace Content.Server.Zombies
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPendingMobState(EntityUid uid, PendingZombieComponent pending, MobStateChangedEvent args)
|
||||
{
|
||||
if (args.NewMobState == MobState.Critical)
|
||||
{
|
||||
// Immediately jump to an active virus when you crit
|
||||
pending.InfectedSecs = Math.Max(0, pending.InfectedSecs);
|
||||
}
|
||||
}
|
||||
|
||||
private float GetZombieInfectionChance(EntityUid uid, ZombieComponent component)
|
||||
{
|
||||
var baseChance = component.MaxZombieInfectionChance;
|
||||
@@ -227,7 +260,8 @@ namespace Content.Server.Zombies
|
||||
{
|
||||
if (_random.Prob(GetZombieInfectionChance(entity, component)))
|
||||
{
|
||||
EnsureComp<PendingZombieComponent>(entity);
|
||||
var pending = EnsureComp<PendingZombieComponent>(entity);
|
||||
pending.MaxInfectionLength = _random.NextFloat(0.25f, 1.0f) * component.ZombieInfectionTurnTime;
|
||||
EnsureComp<ZombifyOnDeathComponent>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,8 @@ namespace Content.Server.Zombies
|
||||
}
|
||||
RemComp<HandsComponent>(target);
|
||||
// No longer waiting to become a zombie:
|
||||
RemComp<PendingZombieComponent>(target);
|
||||
// Requires deferral because this is (probably) the event which called ZombifyEntity in the first place.
|
||||
RemCompDeferred<PendingZombieComponent>(target);
|
||||
|
||||
//zombie gamemode stuff
|
||||
RaiseLocalEvent(new EntityZombifiedEvent(target));
|
||||
|
||||
Reference in New Issue
Block a user