Fix/Addition - Wizard Survivor Antag Status (#35226)

This commit is contained in:
keronshb
2025-02-23 12:24:36 -05:00
committed by GitHub
parent 326bd7f93a
commit 3192914fc5
15 changed files with 246 additions and 2 deletions

View File

@@ -0,0 +1,8 @@
namespace Content.Server.GameTicking.Rules.Components;
/// <summary>
/// Component for the SurvivorRuleSystem. Game rule that turns everyone into a survivor and gives them the objective to escape centcom alive.
/// Started by Wizard Summon Guns/Magic spells.
/// </summary>
[RegisterComponent, Access(typeof(SurvivorRuleSystem))]
public sealed partial class SurvivorRuleComponent : Component;

View File

@@ -0,0 +1,108 @@
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Roles;
using Content.Server.Shuttles.Systems;
using Content.Shared.GameTicking.Components;
using Content.Shared.Mind;
using Content.Shared.Mobs.Systems;
using Content.Shared.Survivor.Components;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
namespace Content.Server.GameTicking.Rules;
public sealed class SurvivorRuleSystem : GameRuleSystem<SurvivorRuleComponent>
{
[Dependency] private readonly RoleSystem _role = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly TransformSystem _xform = default!;
[Dependency] private readonly EmergencyShuttleSystem _eShuttle = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SurvivorRoleComponent, GetBriefingEvent>(OnGetBriefing);
}
// TODO: Planned rework post wizard release when RandomGlobalSpawnSpell becomes a gamerule
protected override void Started(EntityUid uid, SurvivorRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var allAliveHumanMinds = _mind.GetAliveHumans();
foreach (var humanMind in allAliveHumanMinds)
{
if (!humanMind.Comp.OwnedEntity.HasValue)
continue;
var mind = humanMind.Owner;
var ent = humanMind.Comp.OwnedEntity.Value;
if (HasComp<SurvivorComponent>(mind) || _tag.HasTag(mind, "InvalidForSurvivorAntag"))
continue;
EnsureComp<SurvivorComponent>(mind);
_role.MindAddRole(mind, "MindRoleSurvivor");
_antag.SendBriefing(ent, Loc.GetString("survivor-role-greeting"), Color.Olive, null);
}
}
private void OnGetBriefing(Entity<SurvivorRoleComponent> ent, ref GetBriefingEvent args)
{
args.Append(Loc.GetString("survivor-role-greeting"));
}
protected override void AppendRoundEndText(EntityUid uid,
SurvivorRuleComponent component,
GameRuleComponent gameRule,
ref RoundEndTextAppendEvent args)
{
base.AppendRoundEndText(uid, component, gameRule, ref args);
// Using this instead of alive antagonists to make checking for shuttle & if the ent is alive easier
var existingSurvivors = AllEntityQuery<SurvivorComponent, MindComponent>();
var deadSurvivors = 0;
var aliveMarooned = 0;
var aliveOnShuttle = 0;
var eShuttle = _eShuttle.GetShuttle();
while (existingSurvivors.MoveNext(out _, out _, out var mindComp))
{
// If their brain is gone or they respawned/became a ghost role
if (mindComp.CurrentEntity is null)
{
deadSurvivors++;
continue;
}
var survivor = mindComp.CurrentEntity.Value;
if (!_mobState.IsAlive(survivor))
{
deadSurvivors++;
continue;
}
if (eShuttle != null && eShuttle.Value.IsValid() && (Transform(eShuttle.Value).MapID == _xform.GetMapCoordinates(survivor).MapId))
{
aliveOnShuttle++;
continue;
}
aliveMarooned++;
}
args.AddLine(Loc.GetString("survivor-round-end-dead-count", ("deadCount", deadSurvivors)));
args.AddLine(Loc.GetString("survivor-round-end-alive-count", ("aliveCount", aliveMarooned)));
args.AddLine(Loc.GetString("survivor-round-end-alive-on-shuttle-count", ("aliveCount", aliveOnShuttle)));
// Player manifest at EOR shows who's a survivor so no need for extra info here.
}
}

View File

@@ -1,12 +1,20 @@
using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Shared.Magic;
using Content.Shared.Magic.Events;
using Content.Shared.Mind;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;
namespace Content.Server.Magic;
public sealed class MagicSystem : SharedMagicSystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public override void Initialize()
{
@@ -32,4 +40,20 @@ public sealed class MagicSystem : SharedMagicSystem
Spawn(ev.Effect, perfXForm.Coordinates);
Spawn(ev.Effect, targetXForm.Coordinates);
}
protected override void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
{
base.OnRandomGlobalSpawnSpell(ev);
if (!ev.MakeSurvivorAntagonist)
return;
if (_mind.TryGetMind(ev.Performer, out var mind, out _) && !_tag.HasTag(mind, "InvalidForSurvivorAntag"))
_tag.AddTag(mind, "InvalidForSurvivorAntag");
EntProtoId survivorRule = "Survivor";
if (!_gameTicker.IsGameRuleActive<SurvivorRuleComponent>())
_gameTicker.StartGameRule(survivorRule);
}
}

View File

@@ -0,0 +1,9 @@
using Content.Shared.Roles;
namespace Content.Server.Roles;
/// <summary>
/// Adds to a mind role ent to tag they're a Survivor
/// </summary>
[RegisterComponent]
public sealed partial class SurvivorRoleComponent : BaseMindRoleComponent;

View File

@@ -35,6 +35,7 @@ using Content.Shared.Prying.Components;
using Content.Shared.Traits.Assorted;
using Robust.Shared.Audio.Systems;
using Content.Shared.Ghost.Roles.Components;
using Content.Shared.Tag;
namespace Content.Server.Zombies;
@@ -58,6 +59,7 @@ public sealed partial class ZombieSystem
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
[Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly TagSystem _tag = default!;
/// <summary>
/// Handles an entity turning into a zombie when they die or go into crit
@@ -275,5 +277,9 @@ public sealed partial class ZombieSystem
RaiseLocalEvent(target, ref ev, true);
//zombies get slowdown once they convert
_movementSpeedModifier.RefreshMovementSpeedModifiers(target);
//Need to prevent them from getting an item, they have no hands.
// Also prevents them from becoming a Survivor. They're undead.
_tag.AddTag(target, "InvalidForGlobalSpawnSpell");
}
}

View File

@@ -20,4 +20,11 @@ public sealed partial class RandomGlobalSpawnSpellEvent : InstantActionEvent, IS
[DataField]
public string? Speech { get; private set; }
/// <summary>
/// Should this Global spawn spell turn its targets into a Survivor Antagonist?
/// Ignores the caster for this.
/// </summary>
[DataField]
public bool MakeSurvivorAntagonist = false;
}

View File

@@ -469,7 +469,8 @@ public abstract class SharedMagicSystem : EntitySystem
#endregion
#region Global Spells
private void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
// TODO: Change this into a "StartRuleAction" when actions with multiple events are supported
protected virtual void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
{
if (!_net.IsServer || ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || ev.Spawns is not { } spawns)
return;
@@ -486,6 +487,9 @@ public abstract class SharedMagicSystem : EntitySystem
var ent = human.Comp.OwnedEntity.Value;
if (_tag.HasTag(ent, "InvalidForGlobalSpawnSpell"))
continue;
var mapCoords = _transform.GetMapCoordinates(ent);
foreach (var spawn in EntitySpawnCollection.GetSpawns(spawns, _random))
{

View File

@@ -0,0 +1,9 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Survivor.Components;
/// <summary>
/// Component to keep track of which entities are a Survivor antag.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class SurvivorComponent : Component;

View File

@@ -0,0 +1,36 @@
## Survivor
roles-antag-survivor-name = Survivor
# It's a Halo reference
roles-antag-survivor-objective = Current Objective: Survive
survivor-role-greeting =
You are a Survivor.
Above all you need to make it back to CentComm alive.
Collect as much firepower as needed to guarantee your survival.
Trust no one.
survivor-round-end-dead-count =
{
$deadCount ->
[one] [color=red]{$deadCount}[/color] survivor died.
*[other] [color=red]{$deadCount}[/color] survivors died.
}
survivor-round-end-alive-count =
{
$aliveCount ->
[one] [color=yellow]{$aliveCount}[/color] survivor was marooned on the station.
*[other] [color=yellow]{$aliveCount}[/color] survivors were marooned on the station.
}
survivor-round-end-alive-on-shuttle-count =
{
$aliveCount ->
[one] [color=green]{$aliveCount}[/color] survivor made it out alive.
*[other] [color=green]{$aliveCount}[/color] survivors made it out alive.
}
## TODO: Wizard
## TODO: Wizard Apprentice (Coming sometime post-wizard release)

View File

@@ -0,0 +1,5 @@
- type: entity
id: Survivor
parent: BaseGameRule
components:
- type: SurvivorRule

View File

@@ -26,6 +26,7 @@
sprite: Objects/Weapons/Guns/Rifles/ak.rsi
state: base
event: !type:RandomGlobalSpawnSpellEvent
makeSurvivorAntagonist: true
spawns:
- id: WeaponPistolViper
orGroup: Guns
@@ -158,7 +159,7 @@
- id: RevolverCapGunFake
orGroup: Guns
speech: action-speech-spell-summon-guns
- type: entity
id: ActionSummonMagic
name: Summon Magic
@@ -172,6 +173,7 @@
sprite: Objects/Magic/magicactions.rsi
state: magicmissile
event: !type:RandomGlobalSpawnSpellEvent
makeSurvivorAntagonist: true
spawns:
- id: SpawnSpellbook
orGroup: Magics

View File

@@ -0,0 +1,8 @@
# TODO: Actual wizard coming later, this is just for the survival antags
- type: antag
id: Survivor
name: roles-antag-survivor-name
antagonist: true
objective: roles-antag-survivor-objective
# guides: [ ]

View File

@@ -196,6 +196,17 @@
- type: MindRole
antagPrototype: Rev
# Survivors (Wizard)
- type: entity
parent: BaseMindRoleAntag
id: MindRoleSurvivor
name: Survivor Role
components:
- type: MindRole
antagPrototype: Survivor
roleType: FreeAgent
- type: SurvivorRole
# Thief
- type: entity
parent: BaseMindRoleAntag

View File

@@ -35,3 +35,4 @@
id: SiliconAntagonist
name: role-type-silicon-antagonist-name
color: '#c832e6'

View File

@@ -752,6 +752,12 @@
- type: Tag
id: IntercomElectronics
- type: Tag
id: InvalidForGlobalSpawnSpell
- type: Tag
id: InvalidForSurvivorAntag
- type: Tag
id: JawsOfLife