monkey reinforcement teleporters can now select between kobold or monkey with a verb (#25982)

* inital

* Update animals.yml

* Update animals.yml

* Update Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

* Update Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

* Update Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

* Update Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

* Update Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>

* selecting different role will change the description and name

* fix name

* gargh

* the review

Hello

* e

---------

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
This commit is contained in:
Mr. 27
2024-04-26 09:06:43 -04:00
committed by GitHub
parent 36084d9712
commit 50fb91bd18
11 changed files with 223 additions and 40 deletions

View File

@@ -1,5 +1,4 @@
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Ghost.Roles.Components namespace Content.Server.Ghost.Roles.Components
{ {
@@ -10,17 +9,22 @@ namespace Content.Server.Ghost.Roles.Components
[Access(typeof(GhostRoleSystem))] [Access(typeof(GhostRoleSystem))]
public sealed partial class GhostRoleMobSpawnerComponent : Component public sealed partial class GhostRoleMobSpawnerComponent : Component
{ {
[ViewVariables(VVAccess.ReadWrite)] [DataField("deleteOnSpawn")] [DataField]
public bool DeleteOnSpawn = true; public bool DeleteOnSpawn = true;
[ViewVariables(VVAccess.ReadWrite)] [DataField("availableTakeovers")] [DataField]
public int AvailableTakeovers = 1; public int AvailableTakeovers = 1;
[ViewVariables] [ViewVariables]
public int CurrentTakeovers = 0; public int CurrentTakeovers = 0;
[ViewVariables(VVAccess.ReadWrite)] [DataField]
[DataField("prototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))] public EntProtoId? Prototype;
public string? Prototype { get; private set; }
/// <summary>
/// If this ghostrole spawner has multiple selectable ghostrole prototypes.
/// </summary>
[DataField]
public List<string> SelectablePrototypes = [];
} }
} }

View File

@@ -23,6 +23,10 @@ using Robust.Shared.Enums;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Content.Server.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Prototypes;
using Robust.Shared.Collections;
namespace Content.Server.Ghost.Roles namespace Content.Server.Ghost.Roles
{ {
@@ -37,6 +41,8 @@ namespace Content.Server.Ghost.Roles
[Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly SharedMindSystem _mindSystem = default!;
[Dependency] private readonly SharedRoleSystem _roleSystem = default!; [Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
private uint _nextRoleIdentifier; private uint _nextRoleIdentifier;
private bool _needsUpdateGhostRoleCount = true; private bool _needsUpdateGhostRoleCount = true;
@@ -63,6 +69,7 @@ namespace Content.Server.Ghost.Roles
SubscribeLocalEvent<GhostRoleComponent, EntityUnpausedEvent>(OnUnpaused); SubscribeLocalEvent<GhostRoleComponent, EntityUnpausedEvent>(OnUnpaused);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole); SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole);
SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole); SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GetVerbsEvent<Verb>>(OnVerb);
_playerManager.PlayerStatusChanged += PlayerStatusChanged; _playerManager.PlayerStatusChanged += PlayerStatusChanged;
} }
@@ -100,11 +107,11 @@ namespace Content.Server.Ghost.Roles
public void OpenEui(ICommonSession session) public void OpenEui(ICommonSession session)
{ {
if (session.AttachedEntity is not {Valid: true} attached || if (session.AttachedEntity is not { Valid: true } attached ||
!EntityManager.HasComponent<GhostComponent>(attached)) !EntityManager.HasComponent<GhostComponent>(attached))
return; return;
if(_openUis.ContainsKey(session)) if (_openUis.ContainsKey(session))
CloseEui(session); CloseEui(session);
var eui = _openUis[session] = new GhostRolesEui(); var eui = _openUis[session] = new GhostRolesEui();
@@ -250,7 +257,7 @@ namespace Content.Server.Ghost.Roles
if (metaQuery.GetComponent(uid).EntityPaused) if (metaQuery.GetComponent(uid).EntityPaused)
continue; continue;
roles.Add(new GhostRoleInfo {Identifier = id, Name = role.RoleName, Description = role.RoleDescription, Rules = role.RoleRules, Requirements = role.Requirements}); roles.Add(new GhostRoleInfo { Identifier = id, Name = role.RoleName, Description = role.RoleDescription, Rules = role.RoleRules, Requirements = role.Requirements });
} }
return roles.ToArray(); return roles.ToArray();
@@ -407,6 +414,63 @@ namespace Content.Server.Ghost.Roles
args.TookRole = true; args.TookRole = true;
} }
private void OnVerb(EntityUid uid, GhostRoleMobSpawnerComponent component, GetVerbsEvent<Verb> args)
{
var prototypes = component.SelectablePrototypes;
if (prototypes.Count < 1)
return;
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
return;
var verbs = new ValueList<Verb>();
foreach (var prototypeID in prototypes)
{
if (_prototype.TryIndex<GhostRolePrototype>(prototypeID, out var prototype))
{
var verb = CreateVerb(uid, component, args.User, prototype);
verbs.Add(verb);
}
}
args.Verbs.UnionWith(verbs);
}
private Verb CreateVerb(EntityUid uid, GhostRoleMobSpawnerComponent component, EntityUid userUid, GhostRolePrototype prototype)
{
var verbText = Loc.GetString(prototype.Name);
return new Verb()
{
Text = verbText,
Disabled = component.Prototype == prototype.EntityPrototype,
Category = VerbCategory.SelectType,
Act = () => SetMode(uid, prototype, verbText, component, userUid)
};
}
public void SetMode(EntityUid uid, GhostRolePrototype prototype, string verbText, GhostRoleMobSpawnerComponent? component, EntityUid? userUid = null)
{
if (!Resolve(uid, ref component))
return;
var ghostrolecomp = EnsureComp<GhostRoleComponent>(uid);
component.Prototype = prototype.EntityPrototype;
ghostrolecomp.RoleName = verbText;
ghostrolecomp.RoleDescription = prototype.Description;
ghostrolecomp.RoleRules = prototype.Rules;
// Dirty(ghostrolecomp);
if (userUid != null)
{
var msg = Loc.GetString("ghostrole-spawner-select", ("mode", verbText));
_popupSystem.PopupEntity(msg, uid, userUid.Value);
}
}
} }
[AnyCommand] [AnyCommand]
@@ -417,7 +481,7 @@ namespace Content.Server.Ghost.Roles
public string Help => $"{Command}"; public string Help => $"{Command}";
public void Execute(IConsoleShell shell, string argStr, string[] args) public void Execute(IConsoleShell shell, string argStr, string[] args)
{ {
if(shell.Player != null) if (shell.Player != null)
EntitySystem.Get<GhostRoleSystem>().OpenEui(shell.Player); EntitySystem.Get<GhostRoleSystem>().OpenEui(shell.Player);
else else
shell.WriteLine("You can only open the ghost roles UI on a client."); shell.WriteLine("You can only open the ghost roles UI on a client.");

View File

@@ -0,0 +1,38 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Ghost.Roles;
/// <summary>
/// For selectable ghostrole prototypes in ghostrole spawners.
/// </summary>
[Prototype]
public sealed partial class GhostRolePrototype : IPrototype
{
[ViewVariables]
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// The name of the ghostrole.
/// </summary>
[DataField]
public string Name { get; set; } = default!;
/// <summary>
/// The description of the ghostrole.
/// </summary>
[DataField]
public string Description { get; set; } = default!;
/// <summary>
/// The entity prototype of the ghostrole
/// </summary>
[DataField]
public string EntityPrototype = default!;
/// <summary>
/// Rules of the ghostrole
/// </summary>
[DataField]
public string Rules = default!;
}

View File

@@ -228,6 +228,10 @@ ghost-role-information-syndicate-monkey-reinforcement-name = Syndicate Monkey Ag
ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them. ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them.
ghost-role-information-syndicate-monkey-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them. ghost-role-information-syndicate-monkey-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them.
ghost-role-information-syndicate-kobold-reinforcement-name = Syndicate Kobold Agent
ghost-role-information-syndicate-kobold-reinforcement-description = Someone needs reinforcements. You, a trained kobold, will help them.
ghost-role-information-syndicate-kobold-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them.
ghost-role-information-artifact-name = Sentient Artifact ghost-role-information-artifact-name = Sentient Artifact
ghost-role-information-artifact-description = ghost-role-information-artifact-description =
Enact your eldritch whims. Enact your eldritch whims.

View File

@@ -0,0 +1 @@
ghostrole-spawner-select = Selected: {$mode}

View File

@@ -121,8 +121,8 @@ uplink-agent-id-card-desc = A modified ID card that can copy accesses from other
uplink-black-jetpack-name = Black Jetpack uplink-black-jetpack-name = Black Jetpack
uplink-black-jetpack-desc = A black jetpack. It allows you to fly around in space. Refills not included, use your fuel wisely. uplink-black-jetpack-desc = A black jetpack. It allows you to fly around in space. Refills not included, use your fuel wisely.
uplink-reinforcement-radio-monkey-name = Monkey Reinforcement Teleporter uplink-reinforcement-radio-ancestor-name = Genetic Ancestor Reinforcement Teleporter
uplink-reinforcement-radio-monkey-desc = Call in a trained monkey to assist you. Comes with a single syndicate cigarette. uplink-reinforcement-radio-ancestor-desc = Call in a trained ancestor of your choosing to assist you. Comes with a single syndicate cigarette.
uplink-reinforcement-radio-name = Reinforcement Teleporter uplink-reinforcement-radio-name = Reinforcement Teleporter
uplink-reinforcement-radio-desc = Radio in a reinforcement agent of extremely questionable quality. No off button, buy this if you're ready to party. They have a pistol with no reserve ammo, and a knife. That's it. uplink-reinforcement-radio-desc = Radio in a reinforcement agent of extremely questionable quality. No off button, buy this if you're ready to party. They have a pistol with no reserve ammo, and a knife. That's it.

View File

@@ -937,10 +937,10 @@
- NukeOpsUplink - NukeOpsUplink
- type: listing - type: listing
id: UplinkReinforcementRadioSyndicateMonkey id: UplinkReinforcementRadioSyndicateAncestor
name: uplink-reinforcement-radio-monkey-name name: uplink-reinforcement-radio-ancestor-name
description: uplink-reinforcement-radio-monkey-desc description: uplink-reinforcement-radio-ancestor-desc
productEntity: ReinforcementRadioSyndicateMonkey productEntity: ReinforcementRadioSyndicateAncestor
icon: { sprite: Objects/Devices/communication.rsi, state: old-radio } icon: { sprite: Objects/Devices/communication.rsi, state: old-radio }
cost: cost:
Telecrystal: 6 Telecrystal: 6
@@ -953,10 +953,10 @@
- NukeOpsUplink - NukeOpsUplink
- type: listing - type: listing
id: UplinkReinforcementRadioSyndicateMonkeyNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component. id: UplinkReinforcementRadioSyndicateAncestorNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component.
name: uplink-reinforcement-radio-monkey-name name: uplink-reinforcement-radio-ancestor-name
description: uplink-reinforcement-radio-monkey-desc description: uplink-reinforcement-radio-ancestor-desc
productEntity: ReinforcementRadioSyndicateMonkeyNukeops productEntity: ReinforcementRadioSyndicateAncestorNukeops
icon: { sprite: Objects/Devices/communication.rsi, state: old-radio } icon: { sprite: Objects/Devices/communication.rsi, state: old-radio }
cost: cost:
Telecrystal: 6 Telecrystal: 6

View File

@@ -1324,9 +1324,10 @@
- type: entity - type: entity
name: kobold name: kobold
id: MobKobold id: MobBaseKobold
parent: MobBaseAncestor parent: MobBaseAncestor
description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death. description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death.
abstract: true
components: components:
- type: NameIdentifier - type: NameIdentifier
group: Kobold group: Kobold
@@ -1420,15 +1421,6 @@
spawned: spawned:
- id: FoodMeat - id: FoodMeat
amount: 2 amount: 2
- type: Clumsy
clumsyDamage:
types:
Blunt: 2
Piercing: 7
groups:
Burn: 3
clumsySound:
path: /Audio/Voice/Reptilian/reptilian_scream.ogg
- type: AlwaysRevolutionaryConvertible - type: AlwaysRevolutionaryConvertible
- type: GhostTakeoverAvailable - type: GhostTakeoverAvailable
- type: SentienceTarget - type: SentienceTarget
@@ -1439,6 +1431,55 @@
name: ghost-role-information-kobold-name name: ghost-role-information-kobold-name
description: ghost-role-information-kobold-description description: ghost-role-information-kobold-description
- type: entity
name: kobold
id: MobKobold
parent: MobBaseKobold
description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death.
components:
- type: Clumsy
clumsyDamage:
types:
Blunt: 2
Piercing: 7
groups:
Burn: 3
clumsySound:
path: /Audio/Voice/Reptilian/reptilian_scream.ogg
- type: entity
id: MobBaseSyndicateKobold
parent: MobBaseKobold
suffix: syndicate base
components:
- type: MobThresholds
thresholds:
0: Alive
75: Critical
200: Dead
- type: NpcFactionMember
factions:
- Syndicate
- type: Loadout
prototypes: [SyndicateOperativeGearMonkey]
- type: entity
id: MobKoboldSyndicateAgent
parent: MobBaseSyndicateKobold
suffix: syndicate agent
components:
# make the player a traitor once its taken
- type: AutoTraitor
giveUplink: false
giveObjectives: false
- type: entity
id: MobKoboldSyndicateAgentNukeops # Reinforcement exclusive to nukeops uplink
parent: MobBaseSyndicateKobold
suffix: NukeOps
components:
- type: NukeOperative
- type: entity - type: entity
name: guidebook monkey name: guidebook monkey
parent: MobMonkey parent: MobMonkey

View File

@@ -29,9 +29,9 @@
- type: entity - type: entity
parent: ReinforcementRadioSyndicate parent: ReinforcementRadioSyndicate
id: ReinforcementRadioSyndicateMonkey id: ReinforcementRadioSyndicateAncestor
name: syndicate monkey reinforcement radio name: syndicate genetic ancestor reinforcement radio
description: Calls in a specially trained monkey to assist you. description: Calls in a specially trained ancestor of your choosing to assist you.
components: components:
- type: GhostRole - type: GhostRole
name: ghost-role-information-syndicate-monkey-reinforcement-name name: ghost-role-information-syndicate-monkey-reinforcement-name
@@ -39,14 +39,16 @@
rules: ghost-role-information-syndicate-monkey-reinforcement-rules rules: ghost-role-information-syndicate-monkey-reinforcement-rules
- type: GhostRoleMobSpawner - type: GhostRoleMobSpawner
prototype: MobMonkeySyndicateAgent prototype: MobMonkeySyndicateAgent
selectablePrototypes: ["SyndicateMonkey", "SyndicateKobold"]
- type: entity - type: entity
parent: ReinforcementRadioSyndicateMonkey parent: ReinforcementRadioSyndicateAncestor
id: ReinforcementRadioSyndicateMonkeyNukeops # Reinforcement radio exclusive to nukeops uplink id: ReinforcementRadioSyndicateAncestorNukeops # Reinforcement radio exclusive to nukeops uplink
suffix: NukeOps suffix: NukeOps
components: components:
- type: GhostRoleMobSpawner - type: GhostRoleMobSpawner
prototype: MobMonkeySyndicateAgentNukeops prototype: MobMonkeySyndicateAgentNukeops
selectablePrototypes: ["SyndicateMonkeyNukeops", "SyndicateKoboldNukeops"]
- type: entity - type: entity
parent: ReinforcementRadioSyndicate parent: ReinforcementRadioSyndicate

View File

@@ -0,0 +1,27 @@
- type: ghostRole
id: SyndicateKobold
name: ghost-role-information-syndicate-kobold-reinforcement-name
description: ghost-role-information-syndicate-kobold-reinforcement-description
rules: ghost-role-information-syndicate-kobold-reinforcement-rules
entityPrototype: MobKoboldSyndicateAgent
- type: ghostRole
id: SyndicateKoboldNukeops
name: ghost-role-information-syndicate-kobold-reinforcement-name
description: ghost-role-information-syndicate-kobold-reinforcement-description
rules: ghost-role-information-syndicate-kobold-reinforcement-rules
entityPrototype: MobKoboldSyndicateAgentNukeops
- type: ghostRole
id: SyndicateMonkey
name: ghost-role-information-syndicate-monkey-reinforcement-name
description: ghost-role-information-syndicate-monkey-reinforcement-description
rules: ghost-role-information-syndicate-monkey-reinforcement-name
entityPrototype: MobMonkeySyndicateAgent
- type: ghostRole
id: SyndicateMonkeyNukeops
name: ghost-role-information-syndicate-monkey-reinforcement-name
description: ghost-role-information-syndicate-monkey-reinforcement-description
rules: ghost-role-information-syndicate-monkey-reinforcement-name
entityPrototype: MobMonkeySyndicateAgentNukeops

View File

@@ -327,3 +327,5 @@ WeaponPistolN1984Nonlethal: WeaponPistolN1984
WeaponSubMachineGunVectorRubber: WeaponSubMachineGunVector WeaponSubMachineGunVectorRubber: WeaponSubMachineGunVector
WeaponSubMachineGunDrozdRubber: WeaponSubMachineGunDrozd WeaponSubMachineGunDrozdRubber: WeaponSubMachineGunDrozd
WeaponRifleLecterRubber: WeaponRifleLecter WeaponRifleLecterRubber: WeaponRifleLecter
ReinforcementRadioSyndicateMonkey: ReinforcementRadioSyndicateAncestor
ReinforcementRadioSyndicateMonkeyNukeops: ReinforcementRadioSyndicateAncestorNukeops