mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-27 18:47:52 +03:00
167 lines
6.3 KiB
C#
167 lines
6.3 KiB
C#
using Content.Server.Clothing.Systems;
|
|
using Content.Server.DeltaV.ParadoxAnomaly.Components;
|
|
using Content.Server.DetailExaminable;
|
|
using Content.Server.GenericAntag;
|
|
using Content.Server.Ghost.Roles;
|
|
using Content.Server.Ghost.Roles.Components;
|
|
using Content.Server.Psionics;
|
|
using Content.Server.Spawners.Components;
|
|
using Content.Server.Station.Systems;
|
|
using Content.Shared.Abilities.Psionics;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Humanoid.Prototypes;
|
|
using Content.Shared.Mind;
|
|
using Content.Shared.Mind.Components;
|
|
using Content.Shared.Preferences;
|
|
using Content.Shared.Roles;
|
|
using Content.Shared.Roles.Jobs;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace Content.Server.DeltaV.ParadoxAnomaly.Systems;
|
|
|
|
/// <summary>
|
|
/// 90% of the work is done by exterminator since its a reskin.
|
|
/// All the logic here is spawning since thats tricky.
|
|
/// </summary>
|
|
public sealed class ParadoxAnomalySystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly GenericAntagSystem _genericAntag = default!;
|
|
[Dependency] private readonly GhostRoleSystem _ghostRole = default!;
|
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
|
[Dependency] private readonly PsionicsSystem _psionics = default!;
|
|
[Dependency] private readonly SharedHumanoidAppearanceSystem _humanoid = default!;
|
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
|
[Dependency] private readonly SharedRoleSystem _role = default!;
|
|
[Dependency] private readonly StationSystem _station = default!;
|
|
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
|
|
[Dependency] private readonly LoadoutSystem _loadout = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<ParadoxAnomalySpawnerComponent, TakeGhostRoleEvent>(OnTakeGhostRole);
|
|
}
|
|
|
|
private void OnTakeGhostRole(Entity<ParadoxAnomalySpawnerComponent> ent, ref TakeGhostRoleEvent args)
|
|
{
|
|
Log.Info($"Using paradox anomaly spawner {ent}");
|
|
if (!TrySpawnParadoxAnomaly(ent.Comp.Rule, out var twin))
|
|
return;
|
|
|
|
Log.Info($"Created paradox anomaly {ToPrettyString(twin):twin}");
|
|
var role = Comp<GhostRoleComponent>(ent);
|
|
_ghostRole.GhostRoleInternalCreateMindAndTransfer(args.Player, ent, twin.Value, role);
|
|
_ghostRole.UnregisterGhostRole((ent.Owner, role));
|
|
|
|
args.TookRole = true;
|
|
QueueDel(ent);
|
|
}
|
|
|
|
private bool TrySpawnParadoxAnomaly(string rule, [NotNullWhen(true)] out EntityUid? twin)
|
|
{
|
|
twin = null;
|
|
|
|
// Get a list of potential candidates
|
|
var candidates = new List<(EntityUid, EntityUid, SpeciesPrototype, HumanoidCharacterProfile)>();
|
|
var query = EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent>();
|
|
while (query.MoveNext(out var uid, out var mindContainer, out var humanoid))
|
|
{
|
|
if (humanoid.LastProfileLoaded is not {} profile)
|
|
continue;
|
|
|
|
if (!_proto.TryIndex<SpeciesPrototype>(humanoid.Species, out var species))
|
|
continue;
|
|
|
|
if (_mind.GetMind(uid, mindContainer) is not {} mindId || !HasComp<JobRoleComponent>(mindId))
|
|
continue;
|
|
|
|
if (_role.MindIsAntagonist(mindId))
|
|
continue;
|
|
|
|
// TODO: when metempsychosis real skip whoever has Karma
|
|
|
|
candidates.Add((uid, mindId, species, profile));
|
|
}
|
|
|
|
twin = SpawnParadoxAnomaly(candidates, rule);
|
|
return twin != null;
|
|
}
|
|
|
|
private EntityUid? SpawnParadoxAnomaly(List<(EntityUid, EntityUid, SpeciesPrototype, HumanoidCharacterProfile)> candidates, string rule)
|
|
{
|
|
// Select a candidate.
|
|
if (candidates.Count == 0)
|
|
return null;
|
|
|
|
var (uid, mindId, species, profile) = _random.Pick(candidates);
|
|
var jobId = Comp<JobRoleComponent>(mindId).Prototype;
|
|
var job = _proto.Index<JobPrototype>(jobId!);
|
|
|
|
// Find a suitable spawn point.
|
|
var station = _station.GetOwningStation(uid);
|
|
var latejoins = new List<EntityUid>();
|
|
var query = EntityQueryEnumerator<SpawnPointComponent>();
|
|
while (query.MoveNext(out var spawnUid, out var spawnPoint))
|
|
{
|
|
if (spawnPoint.SpawnType != SpawnPointType.LateJoin)
|
|
continue;
|
|
|
|
if (_station.GetOwningStation(spawnUid) == station)
|
|
latejoins.Add(spawnUid);
|
|
}
|
|
|
|
if (latejoins.Count == 0)
|
|
return null;
|
|
|
|
// Spawn the twin.
|
|
var destination = Transform(_random.Pick(latejoins)).Coordinates;
|
|
var spawned = Spawn(species.Prototype, destination);
|
|
|
|
// Set the kill target to the chosen player
|
|
// _terminator.SetTarget(spawned, mindId);
|
|
_genericAntag.MakeAntag(spawned, rule);
|
|
|
|
//////////////////////////
|
|
// /!\ WARNING /!\ //
|
|
// MAJOR SHITCODE BELOW //
|
|
// /!\ WARNING /!\ //
|
|
//////////////////////////
|
|
|
|
// Copy the details.
|
|
_humanoid.LoadProfile(spawned, profile);
|
|
_metaData.SetEntityName(spawned, Name(uid));
|
|
|
|
if (TryComp<DetailExaminableComponent>(uid, out var detail))
|
|
{
|
|
var detailCopy = EnsureComp<DetailExaminableComponent>(spawned);
|
|
detailCopy.Content = detail.Content;
|
|
}
|
|
|
|
if (job.StartingGear != null && _proto.TryIndex<StartingGearPrototype>(job.StartingGear, out var gear))
|
|
{
|
|
_stationSpawning.EquipStartingGear(spawned, gear);
|
|
_stationSpawning.SetPdaAndIdCardData(spawned,
|
|
profile.Name,
|
|
job,
|
|
station);
|
|
_loadout.ApplyCharacterLoadout(spawned, job, profile, [], false); // TODO: find a way to get playtimes and whitelisted
|
|
}
|
|
|
|
foreach (var special in job.Special)
|
|
{
|
|
special.AfterEquip(spawned);
|
|
}
|
|
|
|
// TODO: In a future PR, make it so that the Paradox Anomaly spawns with a completely 1:1 clone of the victim's entire PsionicComponent.
|
|
if (HasComp<PsionicComponent>(uid))
|
|
EnsureComp<PsionicComponent>(spawned);
|
|
|
|
return spawned;
|
|
}
|
|
}
|