using Content.Server._Sunrise.Boss.Components; using Content.Server.NPC.HTN; using Content.Shared._Sunrise.Boss.Components; using Content.Shared.Actions; using Content.Shared.Actions.Components; using Content.Shared.Atmos.Components; using Robust.Shared.Timing; namespace Content.Server._Sunrise.Boss.Systems; public sealed class NPCUseActionWhenTargetInRangeSystem : EntitySystem { [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly IGameTiming _timing = default!; public override void Initialize() { SubscribeLocalEvent(OnMapInit); } private void OnMapInit(Entity ent, ref MapInitEvent args) { foreach (var action in ent.Comp.Actions) { action.ActionEnt = _actions.AddAction(ent, action.ActionId); // Костыль. Так как это писалось для MobHellspawn, а у него добавление действия пождигания обрабатывает компонент Firestarter, то надо из того компонента выудить энтити экшена if (action.ActionId == "ActionFireStarter") { if (TryComp(ent, out var firestarterComponent)) action.ActionEnt = firestarterComponent.FireStarterActionEntity; } if (action.ActionId == "ActionHellSpawnRush") { if (TryComp(ent, out var hellSpawnRushComponent)) action.ActionEnt = hellSpawnRushComponent.RushActionEntity; } if (action.ActionId == "ActionHellSpawnTentacleRight") { if (TryComp(ent, out var hellSpawnTentacleComponent)) { action.ActionEnt = hellSpawnTentacleComponent.RightGrabActionEntity; } } if (action.ActionId == "ActionHellSpawnTentacleLeft") { if (TryComp(ent, out var hellSpawnTentacleComponent)) { action.ActionEnt = hellSpawnTentacleComponent.LeftGrabActionEntity; } } } } public bool TryUseAction(Entity user, EntityUid target) { if (!Resolve(user, ref user.Comp, false)) return false; foreach (var actionWhenTargetInRange in user.Comp.Actions) { if (TryComp(actionWhenTargetInRange.ActionEnt, out var instantAction)) { var action = Comp(actionWhenTargetInRange.ActionEnt.Value); if (!_actions.ValidAction((actionWhenTargetInRange.ActionEnt.Value, action))) continue; var targetXform = Transform(target); var userXform = Transform(user); // Манхеттенская геометрия var distance = Math.Abs(targetXform.Coordinates.X - userXform.Coordinates.X) + Math.Abs(targetXform.Coordinates.Y - userXform.Coordinates.Y); if (actionWhenTargetInRange.MaxRange != 0f && distance > actionWhenTargetInRange.MaxRange || actionWhenTargetInRange.MinRange != 0f && distance < actionWhenTargetInRange.MinRange) continue; _actions.PerformAction((user, null), (actionWhenTargetInRange.ActionEnt.Value, action), instantAction.Event, false); } else if (TryComp(actionWhenTargetInRange.ActionEnt, out var worldTargetAction)) { var action = Comp(actionWhenTargetInRange.ActionEnt.Value); if (!_actions.ValidAction((actionWhenTargetInRange.ActionEnt.Value, action))) continue; var targetXform = Transform(target); var userXform = Transform(user); // Манхеттенская геометрия var distance = Math.Abs(targetXform.Coordinates.X - userXform.Coordinates.X) + Math.Abs(targetXform.Coordinates.Y - userXform.Coordinates.Y); if (actionWhenTargetInRange.MaxRange != 0f && distance > actionWhenTargetInRange.MaxRange || actionWhenTargetInRange.MinRange != 0f && distance < actionWhenTargetInRange.MinRange) continue; if (worldTargetAction.Event is {} worldEv) { worldEv.Target = targetXform.Coordinates; } _actions.PerformAction((user, null), (actionWhenTargetInRange.ActionEnt.Value, action), worldTargetAction.Event, false); } } return true; } public override void Update(float frameTime) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp, out var htn)) { if (!htn.Blackboard.TryGetValue(comp.TargetKey, out var target, EntityManager)) continue; if (comp.Delay != null) { if (_timing.CurTime - comp.Prev < comp.Delay) continue; } if (comp.Delay != null && TryUseAction((uid, comp), target)) comp.Prev = _timing.CurTime; } } }