Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Content.Client/ADT/ZombieJump/ZombieJumpSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Content.Shared.ADT.ZombieJump;

namespace Content.Client.ADT.ZombieJump;
public sealed partial class ZombieJumpSystem : SharedZombieJumpSystem
{
protected override void TryStunAndKnockdown(EntityUid uid, TimeSpan duration)
{
// На клиенте ничего не делаем
}
}
101 changes: 101 additions & 0 deletions Content.Server/ADT/ZombieJump/Operators/ZombieJumpAttackOperator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System.Threading;
using System.Threading.Tasks;
using Content.Server.ADT.ZombieJump;
using Content.Server.ADT.ZombieJump.Preconditions;
using Content.Server.NPC;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.HTN.PrimitiveTasks;
using Content.Shared.ADT.ZombieJump;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Zombies;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Physics.Components;
using Robust.Shared.Timing;

namespace Content.Server.ADT.ZombieJump.Operators;
public sealed partial class ZombieJumpAttackOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;

[DataField("targetKey", required: true)]
public string TargetKey = default!;

[DataField("cooldown")]
public float Cooldown = 10f;

private ZombieJumpSystem _jumpSystem = default!;

public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_jumpSystem = sysManager.GetEntitySystem<ZombieJumpSystem>();
}

public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);

var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);

if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
return;

if (!_entManager.EntityExists(target))
return;

if (!_entManager.TryGetComponent<ZombieJumpComponent>(owner, out var jumpComp))
return;

if (!_entManager.TryGetComponent<TransformComponent>(owner, out var ownerXform) ||
!_entManager.TryGetComponent<TransformComponent>(target, out var targetXform) ||
ownerXform.MapID != targetXform.MapID)
{
return;
}

_jumpSystem.ExecuteJump(owner, jumpComp);
blackboard.SetValue("LastJumpTime", _gameTiming.CurTime.TotalSeconds);
}

public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
return (false, null);

if (_entManager.TryGetComponent<MobStateComponent>(target, out var mobState) &&
mobState.CurrentState > MobState.Critical)
return (false, null);

var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);

if (!_entManager.HasComponent<ZombieJumpComponent>(owner))
return (false, null);

if (blackboard.TryGetValue<double>("LastJumpTime", out var lastJumpTime, _entManager))
{
var currentTime = _gameTiming.CurTime.TotalSeconds;
if (currentTime - lastJumpTime < Cooldown)
return (false, null);
}

if (!_entManager.TryGetComponent<TransformComponent>(owner, out var ownerXform) ||
!_entManager.TryGetComponent<TransformComponent>(target, out var targetXform))
return (false, null);

if (ownerXform.MapID != targetXform.MapID)
return (false, null);

return (true, null);
}

public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
base.Update(blackboard, frameTime);
return HTNOperatorStatus.Finished;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Content.Server.NPC;
using Content.Server.NPC.HTN;
using Content.Server.NPC.HTN.Preconditions;
using Robust.Shared.Timing;

namespace Content.Server.ADT.ZombieJump.Preconditions;

public sealed partial class ZombieJumpCooldownPrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;

[DataField("cooldown")]
public float Cooldown = 10f;

public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
}

public override bool IsMet(NPCBlackboard blackboard)
{
try
{
if (blackboard.TryGetValue<double>("LastJumpTime", out var lastJumpTime, _entManager))
{
var currentTime = _gameTiming.CurTime.TotalSeconds;
if (currentTime - lastJumpTime < Cooldown)
return false;
}
return true;
}
catch
{
return true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Content.Server.NPC;
using Content.Server.NPC.HTN;
using Content.Server.NPC.HTN.Preconditions;
using Robust.Shared.Map;

namespace Content.Server.ADT.ZombieJump.Preconditions;
public sealed partial class ZombieJumpRangePrecondition : HTNPrecondition
{
[Dependency] private readonly IEntityManager _entManager = default!;

private SharedTransformSystem _transformSystem = default!;

[DataField("targetKey", required: true)] public string TargetKey = default!;

[DataField("rangeKey", required: true)]
public string RangeKey = default!;

public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_transformSystem = sysManager.GetEntitySystem<SharedTransformSystem>();
}

public override bool IsMet(NPCBlackboard blackboard)
{
try
{
if (!blackboard.TryGetValue<EntityCoordinates>(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager))
return false;

if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
return false;

if (!_entManager.TryGetComponent<TransformComponent>(target, out var targetXform))
return false;

var jumpRange = blackboard.GetValueOrDefault<float>(RangeKey, _entManager);

if (jumpRange <= 0f)
return false;

return _transformSystem.InRange(coordinates, targetXform.Coordinates, jumpRange);
}
catch
{
return false;
}
}
}
77 changes: 77 additions & 0 deletions Content.Server/ADT/ZombieJump/ZombieJumpSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Content.Shared.ADT.ZombieJump;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Robust.Shared.GameObjects;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;

namespace Content.Server.ADT.ZombieJump;
public sealed partial class ZombieJumpSystem : SharedZombieJumpSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ZombieJumpEvent>(OnZombieJumpServer);
}
public void ExecuteJump(EntityUid uid, ZombieJumpComponent jumpComp)
{
if (!TryComp<TransformComponent>(uid, out var xform) ||
!TryComp<PhysicsComponent>(uid, out var physics))
{
return;
}

if (xform.Anchored)
{
_transform.Unanchor(uid, xform);
}

_physics.SetAwake(uid, physics, true);

var direction = xform.LocalRotation.ToWorldVec();
var targetCoords = xform.Coordinates.Offset(direction * jumpComp.JumpDistance);
_throwing.TryThrow(uid, targetCoords, jumpComp.JumpThrowSpeed);

EnsureComp<ActiveZombieLeaperComponent>(uid, out var leaperComp);
leaperComp.KnockdownDuration = jumpComp.CollideKnockdown;
}

private void OnZombieJumpServer(ZombieJumpEvent args)
{
if (args.Handled)
return;

var uid = args.Performer;

if (!TryComp<ZombieJumpComponent>(uid, out var jumpComp))
{
return;
}

ExecuteJump(uid, jumpComp);

args.Handled = true;
}

protected override void TryStunAndKnockdown(EntityUid uid, TimeSpan duration)
{
_stun.TryAddStunDuration(uid, TimeSpan.FromSeconds(1));

if (TryComp(uid, out StunVisualsComponent? starsComp) &&
TryComp(uid, out AppearanceComponent? appearance))
{
_appearance.SetData(uid, SharedStunSystem.StunVisuals.SeeingStars, true, appearance);
}

if (duration > TimeSpan.FromSeconds(1))
{
_stun.TryKnockdown(uid, duration, force: true);
}
}
}
26 changes: 25 additions & 1 deletion Content.Server/Zombies/ZombieSystem.Transform.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@
using Content.Shared.Zombies;
using Content.Shared.Prying.Components;
using Content.Shared.Traits.Assorted;
using Content.Shared.Movement.Components;
using Robust.Shared.Audio.Systems;
using Content.Server.ADT.ZombieJump;
using Content.Shared.ADT.ZombieJump;
using Content.Shared.Ghost.Roles.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Tag;
Expand Down Expand Up @@ -218,11 +221,30 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null)
pryComp.PryPowered = true;
pryComp.Force = true;

// ADT-Tweak start: Zombies get special jump ability with collision knockdown
var jumpComp = EnsureComp<ZombieJumpComponent>(target);
jumpComp.JumpDistance = zombiecomp.JumpDistance;
jumpComp.JumpThrowSpeed = zombiecomp.JumpThrowSpeed;
jumpComp.CollideKnockdown = zombiecomp.JumpCollideKnockdown;
Dirty(target, jumpComp);
// ADT-Tweak end

Dirty(target, pryComp);
}

Dirty(target, melee);

// ADT-Tweak start: Non-humanoid zombies also get jump ability
if (!HasComp<HumanoidAppearanceComponent>(target))
{
var jumpComp = EnsureComp<ZombieJumpComponent>(target);
jumpComp.JumpDistance = zombiecomp.JumpDistance;
jumpComp.JumpThrowSpeed = zombiecomp.JumpThrowSpeed;
jumpComp.CollideKnockdown = zombiecomp.JumpCollideKnockdown;
Dirty(target, jumpComp);
}
// ADT-Tweak end

//The zombie gets the assigned damage weaknesses and strengths
_damageable.SetDamageModifierSetId(target, "Zombie");

Expand Down Expand Up @@ -260,8 +282,10 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null)
_identity.QueueIdentityUpdate(target);

var htn = EnsureComp<HTNComponent>(target);
htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" };
htn.RootTask = new HTNCompoundTask() { Task = "ZombieHostileCompound" }; // ADT-Tweak
htn.Blackboard.SetValue(NPCBlackboard.Owner, target);
// Добавляем дальность прыжка для HTN
htn.Blackboard.SetValue("JumpRange", zombiecomp.JumpDistance);
_npc.SleepNPC(target, htn);

//He's gotta have a mind
Expand Down
22 changes: 20 additions & 2 deletions Content.Server/Zombies/ZombieSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, M
}

component.NextTick = _timing.CurTime + TimeSpan.FromSeconds(1f);
component.TimeUntilInevitable = component.InevitableZombificationTime; // ADT-Tweak
}

public override void Update(float frameTime)
Expand All @@ -127,10 +128,25 @@ public override void Update(float frameTime)
comp.NextTick = curTime + TimeSpan.FromSeconds(1f);

comp.GracePeriod -= TimeSpan.FromSeconds(1f);
// ADT-Tweak start
comp.TimeUntilInevitable -= TimeSpan.FromSeconds(1f);

// Check for inevitable zombification
if (comp.TimeUntilInevitable <= TimeSpan.Zero)
{
ZombifyEntity(uid);
continue;
}

// Show warnings only if not infected by Romerol
if (!comp.RomerolInfection && comp.GracePeriod > TimeSpan.Zero && _random.Prob(comp.InfectionWarningChance))
_popup.PopupEntity(Loc.GetString(_random.Pick(comp.InfectionWarnings)), uid, uid);
// ADT-Tweak end

if (comp.GracePeriod > TimeSpan.Zero)
continue;

if (_random.Prob(comp.InfectionWarningChance))
if (!comp.RomerolInfection && _random.Prob(comp.InfectionWarningChance)) // ADT-Tweak
_popup.PopupEntity(Loc.GetString(_random.Pick(comp.InfectionWarnings)), uid, uid);

var multiplier = _mobState.IsCritical(uid, mobState)
Expand Down Expand Up @@ -265,7 +281,9 @@ private void OnMeleeHit(Entity<ZombieComponent> entity, ref MeleeHitEvent args)
if (HasComp<ZombieImmuneComponent>(uid) || cannotSpread || _random.Prob(GetZombieInfectionChance(uid, entity.Comp)))
continue;

EnsureComp<PendingZombieComponent>(uid);
var pendingComp = EnsureComp<PendingZombieComponent>(uid);
// Zombie bites are NOT Romerol infections - warnings will show
pendingComp.RomerolInfection = false; // ADT-Tweak
EnsureComp<ZombifyOnDeathComponent>(uid);
}
else
Expand Down
10 changes: 10 additions & 0 deletions Content.Shared/ADT/ZombieJump/ActiveZombieLeaperComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Robust.Shared.GameStates;

namespace Content.Shared.ADT.ZombieJump;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ActiveZombieLeaperComponent : Component
{
[DataField, AutoNetworkedField]
public TimeSpan KnockdownDuration;
}
Loading
Loading