CatStation/Content.Server/Anomaly/Effects/ProjectileAnomalySystem.cs
TemporalOroboros 84b2f07157
The IMapManager is dead (#44002)
* Axes the easy IMapManager references

* Axes the references to unported (obsolete) IMapManager methods

* Converts salvageruler command to a LocalizedEntityCommand so it can use SharedMapSystem

* Removes IMapManager from GameTicker
This required axing the map nuke during restart, but that should be fine?
Maps are entities so EntityManager.FlushEntities should delete them all and that's the preceding line

* submodule update(?)

---------

Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com>
2026-07-01 20:44:54 -07:00

109 lines
3.8 KiB
C#

using System.Numerics;
using Content.Server.Anomaly.Components;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared.Anomaly.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.Projectiles;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Anomaly.Effects;
/// <summary>
/// This handles <see cref="ProjectileAnomalyComponent"/> and the events from <seealso cref="AnomalySystem"/>
/// </summary>
public sealed partial class ProjectileAnomalySystem : EntitySystem
{
[Dependency] private TransformSystem _xform = default!;
[Dependency] private EntityLookupSystem _lookup = default!;
[Dependency] private IRobustRandom _random = default!;
[Dependency] private GunSystem _gunSystem = default!;
[Dependency] private SharedMapSystem _map = default!;
[Dependency] private EntityQuery<MobStateComponent> _mobStateQuery = default!;
/// <summary> Pre-allocated collection for calculating entities in range. </summary>
private readonly HashSet<EntityUid> _inRange = new();
public override void Initialize()
{
SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalyPulseEvent>(OnPulse);
SubscribeLocalEvent<ProjectileAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
}
private void OnPulse(EntityUid uid, ProjectileAnomalyComponent component, ref AnomalyPulseEvent args)
{
ShootProjectilesAtEntities(uid, component, args.Severity * args.PowerModifier);
}
private void OnSupercritical(EntityUid uid, ProjectileAnomalyComponent component, ref AnomalySupercriticalEvent args)
{
ShootProjectilesAtEntities(uid, component, args.PowerModifier);
}
private void ShootProjectilesAtEntities(EntityUid uid, ProjectileAnomalyComponent component, float severity)
{
var projectileCount = (int)MathF.Round(MathHelper.Lerp(component.MinProjectiles, component.MaxProjectiles, severity));
var xform = Transform(uid);
_inRange.Clear();
_lookup.GetEntitiesInRange(uid, component.ProjectileRange * severity, _inRange, LookupFlags.Dynamic);
if (_inRange.Count == 0)
return;
var priority = new List<EntityUid>();
foreach (var entity in _inRange)
{
if (_mobStateQuery.HasComponent(entity))
priority.Add(entity);
}
Log.Debug($"shots: {projectileCount}");
while (projectileCount > 0)
{
Log.Debug($"{projectileCount}");
var target = priority.Count > 0
? _random.PickAndTake(priority)
: _random.Pick(_inRange);
var targetXForm = Transform(target);
var targetCoords = targetXForm.Coordinates.Offset(_random.NextVector2(0.5f));
ShootProjectile(
uid,
component,
xform.Coordinates,
targetCoords,
severity
);
projectileCount--;
}
}
private void ShootProjectile(
EntityUid uid,
ProjectileAnomalyComponent component,
EntityCoordinates coords,
EntityCoordinates targetCoords,
float severity
)
{
var mapPos = _xform.ToMapCoordinates(coords);
var spawnCoords = _map.TryFindGridAt(mapPos, out var gridUid, out _)
? _xform.WithEntityId(coords, gridUid)
: new(_map.GetMapOrInvalid(mapPos.MapId), mapPos.Position);
var ent = Spawn(component.ProjectilePrototype, spawnCoords);
var direction = _xform.ToMapCoordinates(targetCoords).Position - mapPos.Position;
if (!TryComp<ProjectileComponent>(ent, out var comp))
return;
comp.Damage *= severity;
_gunSystem.ShootProjectile(ent, direction, Vector2.Zero, uid, uid, component.ProjectileSpeed);
}
}