Delta-v/Content.Server/_DV/CosmicCult/Abilities/CosmicMonumentSystem.cs

145 lines
6.5 KiB
C#

using System.Numerics;
using Content.Server.Actions;
using Content.Server.Popups;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared._DV.CosmicCult.Components;
using Content.Shared._DV.CosmicCult;
using Content.Shared.Maps;
using Robust.Shared.Map.Components;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Server._DV.CosmicCult.Abilities;
public sealed class CosmicMonumentSystem : EntitySystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly CosmicCultRuleSystem _cultRule = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
[Dependency] private readonly MonumentSystem _monument = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StationSystem _station = default!;
private static readonly EntProtoId MonumentCollider = "MonumentCollider";
private static readonly EntProtoId MonumentCosmicCultMoveEnd = "MonumentCosmicCultMoveEnd";
private static readonly EntProtoId MonumentCosmicCultMoveStart = "MonumentCosmicCultMoveStart";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CosmicCultLeadComponent, EventCosmicPlaceMonument>(OnCosmicPlaceMonument);
SubscribeLocalEvent<CosmicCultLeadComponent, EventCosmicMoveMonument>(OnCosmicMoveMonument);
}
//todo attack this with a debugger at some point, it seems to un-prime before it should sometimes?
//no idea why, might be something to do with verifying placement inside the action's execution instead of in an attemptEvent beforehand?
//yeah it is - if the action is primed but fails at this step, then the action becomes un-primed but does not properly go through, requiring it to be primed again
//works fine:tm: for now with a slightly jank fix on the client end of things, will probably want to dig deeper?
//actually might not want to fix it?
//I've got the client stuff working well & this works out to making the ghost stay up so long as you consistently try (& fail) to place the monument
//guess I should ask for specific feedback for this one tiny feature?
private void OnCosmicPlaceMonument(Entity<CosmicCultLeadComponent> uid, ref EventCosmicPlaceMonument args)
{
if (!VerifyPlacement(uid, out var pos))
return;
_actions.RemoveAction(uid, uid.Comp.CosmicMonumentPlaceActionEntity);
Spawn(MonumentCollider, pos);
var monument = Spawn(uid.Comp.MonumentPrototype, pos);
_cultRule.TransferCultAssociation(uid, monument);
}
private void OnCosmicMoveMonument(Entity<CosmicCultLeadComponent> uid, ref EventCosmicMoveMonument args)
{
if (_cultRule.AssociatedGamerule(uid) is not {} cult)
return;
if (!VerifyPlacement(uid, out var pos))
return;
_actions.RemoveAction(uid, uid.Comp.CosmicMonumentMoveActionEntity);
//delete all old monument colliders for 100% safety
var colliderQuery = EntityQueryEnumerator<MonumentCollisionComponent>();
while (colliderQuery.MoveNext(out var collider, out _))
{
QueueDel(collider);
}
//spawn the destination effect first because we only need one
var destEnt = Spawn(MonumentCosmicCultMoveEnd, pos);
var destComp = EnsureComp<MonumentMoveDestinationComponent>(destEnt);
destComp.Monument = cult.Comp.MonumentInGame;
var coords = Transform(cult.Comp.MonumentInGame).Coordinates;
Spawn(MonumentCollider, pos); //spawn a new collider
Spawn(MonumentCosmicCultMoveStart, coords);
Spawn(MonumentCollider, Transform(cult.Comp.MonumentInGame).Coordinates); //spawn a new collider
_monument.PhaseOutMonument(cult.Comp.MonumentInGame);
destComp.PhaseInTimer = cult.Comp.MonumentInGame.Comp.PhaseOutTimer + TimeSpan.FromSeconds(0.75);
}
//todo this can probably be mostly moved to shared but my brain isn't cooperating w/ that rn
private bool VerifyPlacement(Entity<CosmicCultLeadComponent> uid, out EntityCoordinates outPos)
{
//MAKE SURE WE'RE STANDING ON A GRID
var xform = Transform(uid);
outPos = new EntityCoordinates();
if (!TryComp<MapGridComponent>(xform.GridUid, out var grid))
{
_popup.PopupEntity(Loc.GetString("cosmicability-monument-spawn-error-grid"), uid, uid);
return false;
}
var localTile = _map.GetTileRef(xform.GridUid.Value, grid, xform.Coordinates);
var targetIndices = localTile.GridIndices + new Vector2i(0, 1);
var pos = _map.ToCenterCoordinates(xform.GridUid.Value, targetIndices, grid);
outPos = pos;
var box = new Box2(pos.Position + new Vector2(-1.4f, -0.4f), pos.Position + new Vector2(1.4f, 0.4f));
//CHECK IF IT'S BEING PLACED CHEESILY CLOSE TO SPACE
var spaceDistance = 3;
var worldPos = _transform.GetWorldPosition(xform);
foreach (var tile in _map.GetTilesIntersecting(xform.GridUid.Value, grid, new Circle(worldPos, spaceDistance)))
{
if (tile.IsSpace(_tileDef))
{
_popup.PopupEntity(Loc.GetString("cosmicability-monument-spawn-error-space", ("DISTANCE", spaceDistance)), uid, uid);
return false;
}
}
//CHECK IF WE'RE ON THE STATION OR IF SOMEONE'S TRYING TO SNEAK THIS ONTO SOMETHING SMOL
var station = _station.GetStationInMap(xform.MapID);
EntityUid? stationGrid = null;
if (TryComp<StationDataComponent>(station, out var stationData))
stationGrid = _station.GetLargestGrid(stationData);
if (stationGrid is not null && stationGrid != xform.GridUid)
{
_popup.PopupEntity(Loc.GetString("cosmicability-monument-spawn-error-station"), uid, uid);
return false;
}
//CHECK FOR ENTITY AND ENVIRONMENTAL INTERSECTIONS
if (_lookup.AnyLocalEntitiesIntersecting(xform.GridUid.Value, box, LookupFlags.Dynamic | LookupFlags.Static, uid))
{
_popup.PopupEntity(Loc.GetString("cosmicability-monument-spawn-error-intersection"), uid, uid);
return false;
}
return true;
}
}