Add paradox clone to admin antag control (#36105)

* make paradox clone receive the original's objectives

* antag control verb

* rename verb
This commit is contained in:
slarticodefast
2025-03-27 18:04:25 +01:00
committed by GitHub
parent f4adb0bdb3
commit 7c44038f63
6 changed files with 73 additions and 19 deletions

View File

@@ -1,9 +1,11 @@
using Content.Server.Administration.Commands;
using Content.Server.Antag;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Zombies;
using Content.Shared.Administration;
using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Shared.Mind.Components;
using Content.Shared.Roles;
using Content.Shared.Verbs;
@@ -17,6 +19,7 @@ public sealed partial class AdminVerbSystem
{
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly ZombieSystem _zombie = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[ValidatePrototypeId<EntityPrototype>]
private const string DefaultTraitorRule = "Traitor";
@@ -36,6 +39,8 @@ public sealed partial class AdminVerbSystem
[ValidatePrototypeId<StartingGearPrototype>]
private const string PirateGearId = "PirateGear";
private readonly EntProtoId _paradoxCloneRuleId = "ParadoxCloneSpawn";
// All antag verbs have names so invokeverb works.
private void AddAntagVerbs(GetVerbsEvent<Verb> args)
{
@@ -157,5 +162,29 @@ public sealed partial class AdminVerbSystem
Message = string.Join(": ", thiefName, Loc.GetString("admin-verb-make-thief")),
};
args.Verbs.Add(thief);
var paradoxCloneName = Loc.GetString("admin-verb-text-make-paradox-clone");
Verb paradox = new()
{
Text = paradoxCloneName,
Category = VerbCategory.Antag,
Icon = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/job_icons.rsi"), "ParadoxClone"),
Act = () =>
{
var ruleEnt = _gameTicker.AddGameRule(_paradoxCloneRuleId);
if (!TryComp<ParadoxCloneRuleComponent>(ruleEnt, out var paradoxCloneRuleComp))
return;
paradoxCloneRuleComp.OriginalBody = args.Target; // override the target player
_gameTicker.StartGameRule(ruleEnt);
},
Impact = LogImpact.High,
Message = string.Join(": ", paradoxCloneName, Loc.GetString("admin-verb-make-paradox-clone")),
};
if (HasComp<HumanoidAppearanceComponent>(args.Target)) // only humanoids can be cloned
args.Verbs.Add(paradox);
}
}

View File

@@ -22,12 +22,19 @@ public sealed partial class ParadoxCloneRuleComponent : Component
[DataField]
public EntProtoId GibProto = "MobParadoxTimed";
/// <summary>
/// Entity of the original player.
/// Gets randomly chosen from all alive players if not specified.
/// </summary>
[DataField]
public EntityUid? OriginalBody;
/// <summary>
/// Mind entity of the original player.
/// Gets assigned when cloning.
/// </summary>
[DataField]
public EntityUid? Original;
public EntityUid? OriginalMind;
/// <summary>
/// Whitelist for Objectives to be copied to the clone.

View File

@@ -47,28 +47,42 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
if (args.Session?.AttachedEntity is not { } spawner)
return;
// get possible targets
var allHumans = _mind.GetAliveHumans();
// we already checked when starting the gamerule, but someone might have died since then.
if (allHumans.Count == 0)
if (ent.Comp.OriginalBody != null) // target was overridden, for example by admin antag control
{
Log.Warning("Could not find any alive players to create a paradox clone from!");
return;
if (Deleted(ent.Comp.OriginalBody.Value) || !_mind.TryGetMind(ent.Comp.OriginalBody.Value, out var originalMindId, out var _))
{
Log.Warning("Could not find mind of target player to paradox clone!");
return;
}
ent.Comp.OriginalMind = originalMindId;
}
else
{
// get possible targets
var allAliveHumanoids = _mind.GetAliveHumans();
// we already checked when starting the gamerule, but someone might have died since then.
if (allAliveHumanoids.Count == 0)
{
Log.Warning("Could not find any alive players to create a paradox clone from!");
return;
}
// pick a random player
var randomHumanoidMind = _random.Pick(allAliveHumanoids);
ent.Comp.OriginalMind = randomHumanoidMind;
ent.Comp.OriginalBody = randomHumanoidMind.Comp.OwnedEntity;
}
// pick a random player
var playerToClone = _random.Pick(allHumans);
var bodyToClone = playerToClone.Comp.OwnedEntity;
if (bodyToClone == null || !_cloning.TryCloning(bodyToClone.Value, _transform.GetMapCoordinates(spawner), ent.Comp.Settings, out var clone))
if (ent.Comp.OriginalBody == null || !_cloning.TryCloning(ent.Comp.OriginalBody.Value, _transform.GetMapCoordinates(spawner), ent.Comp.Settings, out var clone))
{
Log.Error($"Unable to make a paradox clone of entity {ToPrettyString(bodyToClone)}");
Log.Error($"Unable to make a paradox clone of entity {ToPrettyString(ent.Comp.OriginalBody)}");
return;
}
var targetComp = EnsureComp<TargetOverrideComponent>(clone.Value);
targetComp.Target = playerToClone.Owner; // set the kill target
targetComp.Target = ent.Comp.OriginalMind; // set the kill target
var gibComp = EnsureComp<GibOnRoundEndComponent>(clone.Value);
gibComp.SpawnProto = ent.Comp.GibProto;
@@ -78,17 +92,16 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
_sensor.SetAllSensors(clone.Value, SuitSensorMode.SensorOff);
args.Entity = clone;
ent.Comp.Original = playerToClone.Owner;
}
private void AfterAntagEntitySelected(Entity<ParadoxCloneRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
{
if (ent.Comp.Original == null)
if (ent.Comp.OriginalMind == null)
return;
if (!_mind.TryGetMind(args.EntityUid, out var cloneMindId, out var cloneMindComp))
return;
_mind.CopyObjectives(ent.Comp.Original.Value, (cloneMindId, cloneMindComp), ent.Comp.ObjectiveWhitelist, ent.Comp.ObjectiveBlacklist);
_mind.CopyObjectives(ent.Comp.OriginalMind.Value, (cloneMindId, cloneMindComp), ent.Comp.ObjectiveWhitelist, ent.Comp.ObjectiveBlacklist);
}
}

View File

@@ -6,6 +6,7 @@ admin-verb-make-nuclear-operative = Make target into a lone Nuclear Operative.
admin-verb-make-pirate = Make the target into a pirate. Note this doesn't configure the game rule.
admin-verb-make-head-rev = Make the target into a Head Revolutionary.
admin-verb-make-thief = Make the target into a thief.
admin-verb-make-paradox-clone = Create a Paradox Clone ghost role of the target.
admin-verb-text-make-traitor = Make Traitor
admin-verb-text-make-initial-infected = Make Initial Infected
@@ -14,5 +15,6 @@ admin-verb-text-make-nuclear-operative = Make Nuclear Operative
admin-verb-text-make-pirate = Make Pirate
admin-verb-text-make-head-rev = Make Head Rev
admin-verb-text-make-thief = Make Thief
admin-verb-text-make-paradox-clone = Create Paradox Clone
admin-overlay-antag-classic = ANTAG

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi | Brigmedic icon made by PuroSlavKing (Github) | Zombie icon made by RamZ | Zookeper by netwy (discort) | Rev and Head Rev icon taken from https://tgstation13.org/wiki/HUD and edited by coolmankid12345 (Discord) | Mindshield icon taken from https://github.com/tgstation/tgstation/blob/ce6beb8a4d61235d9a597a7126c407160ed674ea/icons/mob/huds/hud.dmi | Admin recolored from MedicalIntern by TsjipTsjip | StationAi resprite to 8x8 size by lunarcomets | Service Worker resprite by anno_midi (Discord) and spanky-spanky (Github) | service icons darkened by frobnic8 (Discord and Github)",
"copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi | Brigmedic icon made by PuroSlavKing (Github) | Zombie icon made by RamZ | Zookeper by netwy (discort) | Rev and Head Rev icon taken from https://tgstation13.org/wiki/HUD and edited by coolmankid12345 (Discord) | Mindshield icon taken from https://github.com/tgstation/tgstation/blob/ce6beb8a4d61235d9a597a7126c407160ed674ea/icons/mob/huds/hud.dmi | Admin recolored from MedicalIntern by TsjipTsjip | StationAi resprite to 8x8 size by lunarcomets | Service Worker resprite by anno_midi (Discord) and spanky-spanky (Github) | service icons darkened by frobnic8 (Discord and Github) | paradoxClone taken from tg station at commit https://github.com/tgstation/tgstation/commit/d0db1ff267557017ae7bde68e6490e70cbb6e42f and modifed by slarticodefast (Github)",
"size": {
"x": 8,
@@ -191,6 +191,9 @@
},
{
"name": "Admin"
},
{
"name": "ParadoxClone"
}
]
}