From d83dfedce031bb85db8ac400391d90474af0e417 Mon Sep 17 00:00:00 2001 From: plykiya Date: Tue, 9 Jul 2024 10:19:19 -0700 Subject: [PATCH 1/7] Syndicate thief, spy, medic --- .../ghost/roles/ghost-role-component.ftl | 10 +++++ .../Prototypes/Entities/Mobs/Player/human.yml | 24 +++++++++++ .../reinforcement_teleporter.yml | 5 ++- Resources/Prototypes/Roles/Antags/traitor.yml | 42 +++++++++++++++++++ .../Prototypes/Roles/Ghostroles/syndicate.yml | 23 +++++++++- 5 files changed, 101 insertions(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl index 98f31e0ab074..b2082f772805 100644 --- a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl @@ -197,6 +197,16 @@ ghost-role-information-syndicate-reinforcement-name = Syndicate Agent ghost-role-information-syndicate-reinforcement-description = Someone needs reinforcements. You, the first person the syndicate could find, will help them. ghost-role-information-syndicate-reinforcement-rules = You are a [color=red][bold]Team Antagonist[/bold][/color] with the agent who summoned you. +ghost-role-information-syndicate-reinforcement-medic-name = Syndicate Medic +ghost-role-information-syndicate-reinforcement-medic-description = Someone needs reinforcements. Your task is to keep the agent who called you alive. + +ghost-role-information-syndicate-reinforcement-spy-name = Syndicate Spy +ghost-role-information-syndicate-reinforcement-spy-description = Someone needs reinforcements. Your speciality lies in espionage, do not be discovered. + +ghost-role-information-syndicate-reinforcement-thief-name = Syndicate Thief +ghost-role-information-syndicate-reinforcement-thief-description = Someone needs reinforcements. Your job is to break in and retrieve something valuable for your agent. + + ghost-role-information-syndicate-monkey-reinforcement-name = Syndicate Monkey Agent ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them. ghost-role-information-syndicate-monkey-reinforcement-rules = You are a [color=red][bold]Team Antagonist[/bold][/color] with the agent who summoned you. diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 629ba91518ae..d9881229f624 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -33,6 +33,30 @@ giveUplink: false giveObjectives: false +- type: entity + parent: MobHumanSyndicateAgent + id: MobHumanSyndicateAgentMedic + name: syndicate medic + components: + - type: Loadout + prototypes: [SyndicateReinforcementMedic] + +- type: entity + parent: MobHumanSyndicateAgent + id: MobHumanSyndicateAgentSpy + name: syndicate spy + components: + - type: Loadout + prototypes: [SyndicateReinforcementSpy] + +- type: entity + parent: MobHumanSyndicateAgent + id: MobHumanSyndicateAgentThief + name: syndicate thief + components: + - type: Loadout + prototypes: [SyndicateReinforcementThief] + - type: entity parent: MobHumanSyndicateAgentBase id: MobHumanSyndicateAgentNukeops # Reinforcement exclusive to nukeops uplink diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index d49c79f48b3c..a64ca01ec4f9 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -9,13 +9,14 @@ layers: - state: old-radio - type: GhostRole - name: ghost-role-information-syndicate-reinforcement-name + name: ghost-role-information-syndicate-reinforcement-spy-name description: ghost-role-information-syndicate-reinforcement-description rules: ghost-role-information-syndicate-reinforcement-rules raffle: settings: default - type: GhostRoleMobSpawner - prototype: MobHumanSyndicateAgent + prototype: MobHumanSyndicateAgentSpy + selectablePrototypes: ["SyndicateAgentMedic", "SyndicateAgentSpy", "SyndicateAgentThief"] - type: EmitSoundOnUse sound: /Audio/Effects/Emotes/parp1.ogg - type: UseDelay diff --git a/Resources/Prototypes/Roles/Antags/traitor.yml b/Resources/Prototypes/Roles/Antags/traitor.yml index 205f04b05ea5..e40466d57fe0 100644 --- a/Resources/Prototypes/Roles/Antags/traitor.yml +++ b/Resources/Prototypes/Roles/Antags/traitor.yml @@ -36,6 +36,48 @@ - PinpointerSyndicateNuclear - DeathAcidifierImplanter +- type: startingGear + id: SyndicateOperativeClothing + equipment: + jumpsuit: ClothingUniformJumpsuitOperative + back: ClothingBackpackSyndicate + shoes: ClothingShoesBootsCombatFilled + gloves: ClothingHandsGlovesColorBlack + +- type: startingGear + id: SyndicateReinforcementMedic + parent: SyndicateOperativeClothing + equipment: + pocket1: WeaponPistolViper + inhand: + - MedkitCombatFilled + storage: + back: + - BoxSurvivalSyndicate + +- type: startingGear + id: SyndicateReinforcementSpy + parent: SyndicateOperativeClothing + equipment: + id: AgentIDCard + mask: ClothingMaskGasVoiceChameleon + pocket1: WeaponPistolViper + storage: + back: + - BoxSurvivalSyndicate + +- type: startingGear + id: SyndicateReinforcementThief + parent: SyndicateOperativeClothing + equipment: + pocket1: WeaponPistolViper + inhand: + - ToolboxSyndicateFilled + storage: + back: + - BoxSurvivalSyndicate + - SyndicateJawsOfLife + #Syndicate Operative Outfit - Basic - type: startingGear id: SyndicateOperativeGearBasic diff --git a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml index 24c0d8b3e3be..444dabd62b0e 100644 --- a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml +++ b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml @@ -24,4 +24,25 @@ 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 \ No newline at end of file + entityPrototype: MobMonkeySyndicateAgentNukeops + +- type: ghostRole + id: SyndicateAgentMedic + name: ghost-role-information-syndicate-reinforcement-medic-name + description: ghost-role-information-syndicate-reinforcement-medic-description + rules: ghost-role-information-syndicate-monkey-reinforcement-rules + entityPrototype: MobHumanSyndicateAgentMedic + +- type: ghostRole + id: SyndicateAgentSpy + name: ghost-role-information-syndicate-reinforcement-spy-name + description: ghost-role-information-syndicate-reinforcement-spy-description + rules: ghost-role-information-syndicate-monkey-reinforcement-rules + entityPrototype: MobHumanSyndicateAgentSpy + +- type: ghostRole + id: SyndicateAgentThief + name: ghost-role-information-syndicate-reinforcement-thief-name + description: ghost-role-information-syndicate-reinforcement-thief-description + rules: ghost-role-information-syndicate-monkey-reinforcement-rules + entityPrototype: MobHumanSyndicateAgentThief From 3591a74f2dddba7a05de519b63f50d0d282e4d3d Mon Sep 17 00:00:00 2001 From: plykiya Date: Tue, 9 Jul 2024 11:07:21 -0700 Subject: [PATCH 2/7] Fixes description for nukies --- .../reinforcement_teleporter.yml | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index a64ca01ec4f9..15660e4b4e0b 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -1,6 +1,7 @@ - type: entity parent: BaseItem - id: ReinforcementRadioSyndicate + abstract: true + id: ReinforcementRadio name: syndicate reinforcement radio description: Call in a syndicate agent of questionable quality, instantly! Only basic equipment provided. components: @@ -8,6 +9,17 @@ sprite: Objects/Devices/communication.rsi layers: - state: old-radio + - type: EmitSoundOnUse + sound: /Audio/Effects/Emotes/parp1.ogg + - type: UseDelay + delay: 300 + +- type: entity + parent: ReinforcementRadio + id: ReinforcementRadioSyndicate + name: syndicate reinforcement radio + description: Call in a syndicate agent of questionable quality, instantly! + components: - type: GhostRole name: ghost-role-information-syndicate-reinforcement-spy-name description: ghost-role-information-syndicate-reinforcement-description @@ -17,21 +29,21 @@ - type: GhostRoleMobSpawner prototype: MobHumanSyndicateAgentSpy selectablePrototypes: ["SyndicateAgentMedic", "SyndicateAgentSpy", "SyndicateAgentThief"] - - type: EmitSoundOnUse - sound: /Audio/Effects/Emotes/parp1.ogg - - type: UseDelay - delay: 300 - type: entity - parent: ReinforcementRadioSyndicate + parent: ReinforcementRadio id: ReinforcementRadioSyndicateNukeops # Reinforcement radio exclusive to nukeops uplink suffix: NukeOps components: + - type: GhostRole + name: ghost-role-information-syndicate-reinforcement-name + description: ghost-role-information-syndicate-reinforcement-description + rules: ghost-role-information-syndicate-reinforcement-rules - type: GhostRoleMobSpawner prototype: MobHumanSyndicateAgentNukeops - type: entity - parent: ReinforcementRadioSyndicate + parent: ReinforcementRadio id: ReinforcementRadioSyndicateAncestor name: syndicate genetic ancestor reinforcement radio description: Calls in a specially trained ancestor of your choosing to assist you. @@ -56,7 +68,7 @@ selectablePrototypes: ["SyndicateMonkeyNukeops", "SyndicateKoboldNukeops"] - type: entity - parent: ReinforcementRadioSyndicate + parent: ReinforcementRadio id: ReinforcementRadioSyndicateSyndiCat name: syndicat reinforcement radio description: Calls in a faithfully trained cat with a microbomb to assist you. @@ -73,7 +85,7 @@ sound: /Audio/Animals/cat_meow.ogg - type: entity - parent: ReinforcementRadioSyndicate + parent: ReinforcementRadio id: ReinforcementRadioSyndicateCyborgAssault # Reinforcement radio exclusive to nukeops uplink name: syndicate assault cyborg reinforcement radio description: Call in a well armed assault cyborg, instantly! From fe52fc89bc25241e4ce1e2edda16877860d6d2a0 Mon Sep 17 00:00:00 2001 From: plykiya Date: Wed, 10 Jul 2024 08:55:27 -0700 Subject: [PATCH 3/7] update description for uplink --- Resources/Locale/en-US/store/uplink-catalog.ftl | 4 +++- Resources/Prototypes/Catalog/uplink_catalog.yml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 2598970cefbe..4a68a24f9a66 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -124,8 +124,10 @@ uplink-black-jetpack-desc = A black jetpack. It allows you to fly around in spac uplink-reinforcement-radio-ancestor-name = Genetic Ancestor Reinforcement Teleporter 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-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-traitor-desc = Radio in a reinforcement agent of extremely questionable quality. No off button, buy this if you're ready to party. Call in a medic or spy or thief to help you out. Good luck. +uplink-reinforcement-radio-nukeops-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-cyborg-assault-name = Syndicate Assault Cyborg Teleporter uplink-reinforcement-radio-cyborg-assault-desc = A lean, mean killing machine with access to an Energy Sword, LMG, Cryptographic Sequencer, and a Pinpointer. diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 0ba83dfe735f..a147ee84eb50 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -902,7 +902,7 @@ - type: listing id: UplinkReinforcementRadioSyndicate name: uplink-reinforcement-radio-name - description: uplink-reinforcement-radio-desc + description: uplink-reinforcement-radio-traitor-desc productEntity: ReinforcementRadioSyndicate icon: { sprite: Objects/Devices/communication.rsi, state: old-radio-urist } cost: @@ -918,7 +918,7 @@ - type: listing id: UplinkReinforcementRadioSyndicateNukeops # Version for Nukeops that spawns an agent with the NukeOperative component. name: uplink-reinforcement-radio-name - description: uplink-reinforcement-radio-desc + description: uplink-reinforcement-radio-nukeops-desc productEntity: ReinforcementRadioSyndicateNukeops icon: { sprite: Objects/Devices/communication.rsi, state: old-radio-urist } cost: From 0a07c1f61c119e21cb88901857d7c310f139550a Mon Sep 17 00:00:00 2001 From: plykiya Date: Sat, 20 Jul 2024 21:56:56 -0700 Subject: [PATCH 4/7] Implement the radial menu --- .../Ghost/GhostRoleRadioBoundUserInterface.cs | 38 +++++++ Content.Client/Ghost/GhostRoleRadioMenu.xaml | 8 ++ .../Ghost/GhostRoleRadioMenu.xaml.cs | 106 ++++++++++++++++++ Content.Server/Ghost/Roles/GhostRoleSystem.cs | 18 ++- Content.Shared/Ghost/GhostRoleRadioEvents.cs | 21 ++++ .../GhostRoleMobSpawnerComponent.cs | 5 +- .../Ghost/Roles/GhostRolePrototype.cs | 7 ++ .../reinforcement_teleporter.yml | 10 +- .../Prototypes/Roles/Ghostroles/syndicate.yml | 3 + 9 files changed, 208 insertions(+), 8 deletions(-) create mode 100644 Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs create mode 100644 Content.Client/Ghost/GhostRoleRadioMenu.xaml create mode 100644 Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs create mode 100644 Content.Shared/Ghost/GhostRoleRadioEvents.cs rename {Content.Server => Content.Shared}/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs (85%) diff --git a/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs new file mode 100644 index 000000000000..6c4ec31229d1 --- /dev/null +++ b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs @@ -0,0 +1,38 @@ +using Content.Shared.Ghost.Roles; +using Robust.Shared.Prototypes; + +namespace Content.Client.Ghost; + +public sealed class GhostRoleRadioBoundUserInterface : BoundUserInterface +{ + private GhostRoleRadioMenu? _ghostRoleRadioMenu; + + public GhostRoleRadioBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + IoCManager.InjectDependencies(this); + } + + protected override void Open() + { + base.Open(); + + _ghostRoleRadioMenu = new GhostRoleRadioMenu(Owner, this); + _ghostRoleRadioMenu.OnClose += Close; + + // Open menu centered wherever the mouse currently is + _ghostRoleRadioMenu.OpenCentered(); + } + + public void SendGhostRoleRadioMessage(ProtoId protoId) + { + SendMessage(new GhostRoleRadioMessage(protoId)); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _ghostRoleRadioMenu?.Dispose(); + } +} diff --git a/Content.Client/Ghost/GhostRoleRadioMenu.xaml b/Content.Client/Ghost/GhostRoleRadioMenu.xaml new file mode 100644 index 000000000000..c35ee128c528 --- /dev/null +++ b/Content.Client/Ghost/GhostRoleRadioMenu.xaml @@ -0,0 +1,8 @@ + + + + diff --git a/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs new file mode 100644 index 000000000000..82c23ba4dddb --- /dev/null +++ b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs @@ -0,0 +1,106 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.Ghost.Roles; +using Content.Shared.Ghost.Roles.Components; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using System.Numerics; + +namespace Content.Client.Ghost; + +public sealed partial class GhostRoleRadioMenu : RadialMenu +{ + [Dependency] private readonly EntityManager _entityManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public event Action>? SendGhostRoleRadioMessageAction; + + public GhostRoleRadioMenu(EntityUid owner, GhostRoleRadioBoundUserInterface bui) + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + + // The main control that will contain all of the clickable options + var main = FindControl("Main"); + + if (main == null) + return; + + // The purpose of this radial UI is for ghost role radios that allow you to select + // more than one potential option, such as with kobolds/lizards. + // This means that it won't show anything if SelectablePrototypes is empty. + if (!_entityManager.TryGetComponent(owner, out var comp)) + return; + + foreach (var ghostRoleProtoString in comp.SelectablePrototypes) + { + // For each prototype we find we want to create a button that uses the name of the ghost role + // as the hover tooltip, and the icon is taken from either the ghost role entityprototype + // or the indicated icon entityprototype. + if (!_prototypeManager.TryIndex(ghostRoleProtoString, out var ghostRoleProto)) + return; + + var button = new GhostRoleRadioMenuButton() + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64, 64), + ToolTip = Loc.GetString(ghostRoleProto.Name), + ProtoId = ghostRoleProto.ID, + }; + + var entProtoView = new EntityPrototypeView() + { + SetSize = new Vector2(48, 48), + VerticalAlignment = VAlignment.Center, + HorizontalAlignment = HAlignment.Center, + Stretch = SpriteView.StretchMode.Fill + }; + + // pick the icon if it exists, otherwise fallback to the ghost role's entity + if (_prototypeManager.TryIndex(ghostRoleProto.IconPrototype, out var iconProto)) + entProtoView.SetPrototype(iconProto); + else + entProtoView.SetPrototype(comp.Prototype); + + button.AddChild(entProtoView); + main.AddChild(button); + AddGhostRoleRadioMenuButtonOnClickActions(main); + + SendGhostRoleRadioMessageAction += bui.SendGhostRoleRadioMessage; + } + } + + private void AddGhostRoleRadioMenuButtonOnClickActions(Control control) + { + var mainControl = control as RadialContainer; + + if (mainControl == null) + return; + + foreach (var child in mainControl.Children) + { + var castChild = child as GhostRoleRadioMenuButton; + + if (castChild == null) + continue; + + castChild.OnButtonUp += _ => + { + SendGhostRoleRadioMessageAction?.Invoke(castChild.ProtoId); + Close(); + }; + } + } +} + +public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButton +{ + public ProtoId ProtoId { get; set; } + + public GhostRoleRadioMenuButton() + { + + } +} diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index b6627f11540f..8b8aa7b8c8fc 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -3,7 +3,6 @@ using Content.Server.EUI; using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Events; -using Content.Server.Ghost.Roles.Raffles; using Content.Shared.Ghost.Roles.Raffles; using Content.Server.Ghost.Roles.UI; using Content.Server.Mind.Commands; @@ -31,6 +30,7 @@ using Content.Server.Popups; using Content.Shared.Verbs; using Robust.Shared.Collections; +using Content.Shared.Ghost.Roles.Components; namespace Content.Server.Ghost.Roles { @@ -80,6 +80,7 @@ public override void Initialize() SubscribeLocalEvent(OnSpawnerTakeRole); SubscribeLocalEvent(OnTakeoverTakeRole); SubscribeLocalEvent>(OnVerb); + SubscribeLocalEvent(OnGhostRoleRadioMessage); _playerManager.PlayerStatusChanged += PlayerStatusChanged; } @@ -786,6 +787,21 @@ public void SetMode(EntityUid uid, GhostRolePrototype prototype, string verbText _popupSystem.PopupEntity(msg, uid, userUid.Value); } } + + public void OnGhostRoleRadioMessage(Entity entity, ref GhostRoleRadioMessage args) + { + if (!_prototype.TryIndex(args.ProtoId, out var ghostRoleProto)) + return; + + // if the prototype chosen isn't actually part of the selectable options, ignore it + foreach (var selectableProto in entity.Comp.SelectablePrototypes) + { + if (selectableProto == ghostRoleProto.EntityPrototype.Id) + return; + } + + SetMode(entity.Owner, ghostRoleProto, ghostRoleProto.Name, entity.Comp); + } } [AnyCommand] diff --git a/Content.Shared/Ghost/GhostRoleRadioEvents.cs b/Content.Shared/Ghost/GhostRoleRadioEvents.cs new file mode 100644 index 000000000000..8bdd6e583755 --- /dev/null +++ b/Content.Shared/Ghost/GhostRoleRadioEvents.cs @@ -0,0 +1,21 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Ghost.Roles; + +[Serializable, NetSerializable] +public sealed class GhostRoleRadioMessage : BoundUserInterfaceMessage +{ + public ProtoId ProtoId; + + public GhostRoleRadioMessage(ProtoId protoId) + { + ProtoId = protoId; + } +} + +[Serializable, NetSerializable] +public enum GhostRoleRadioUiKey : byte +{ + Key +} diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs b/Content.Shared/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs similarity index 85% rename from Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs rename to Content.Shared/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs index 6116173f904b..2e44effad965 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs +++ b/Content.Shared/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs @@ -1,12 +1,11 @@ -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; -namespace Content.Server.Ghost.Roles.Components +namespace Content.Shared.Ghost.Roles.Components { /// /// Allows a ghost to take this role, spawning a new entity. /// [RegisterComponent, EntityCategory("Spawner")] - [Access(typeof(GhostRoleSystem))] public sealed partial class GhostRoleMobSpawnerComponent : Component { [DataField] diff --git a/Content.Shared/Ghost/Roles/GhostRolePrototype.cs b/Content.Shared/Ghost/Roles/GhostRolePrototype.cs index bc36774ea8ba..3e81b5e46e8e 100644 --- a/Content.Shared/Ghost/Roles/GhostRolePrototype.cs +++ b/Content.Shared/Ghost/Roles/GhostRolePrototype.cs @@ -30,6 +30,13 @@ public sealed partial class GhostRolePrototype : IPrototype [DataField(required: true)] public EntProtoId EntityPrototype; + /// + /// The entity prototype's sprite to use to represent the ghost role + /// Use this if you don't want to use the entity itself + /// + [DataField] + public EntProtoId? IconPrototype = null; + /// /// Rules of the ghostrole /// diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index 15660e4b4e0b..6aa2686fa617 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -9,10 +9,12 @@ sprite: Objects/Devices/communication.rsi layers: - state: old-radio - - type: EmitSoundOnUse - sound: /Audio/Effects/Emotes/parp1.ogg - - type: UseDelay - delay: 300 + - type: UserInterface + interfaces: + enum.GhostRoleRadioUiKey.Key: + type: GhostRoleRadioBoundUserInterface + - type: ActivatableUI + key: enum.GhostRoleRadioUiKey.Key - type: entity parent: ReinforcementRadio diff --git a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml index 444dabd62b0e..8e1827e81bf1 100644 --- a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml +++ b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml @@ -32,6 +32,7 @@ description: ghost-role-information-syndicate-reinforcement-medic-description rules: ghost-role-information-syndicate-monkey-reinforcement-rules entityPrototype: MobHumanSyndicateAgentMedic + iconPrototype: MedkitCombat - type: ghostRole id: SyndicateAgentSpy @@ -39,6 +40,7 @@ description: ghost-role-information-syndicate-reinforcement-spy-description rules: ghost-role-information-syndicate-monkey-reinforcement-rules entityPrototype: MobHumanSyndicateAgentSpy + iconPrototype: ClothingMaskGasVoiceChameleon - type: ghostRole id: SyndicateAgentThief @@ -46,3 +48,4 @@ description: ghost-role-information-syndicate-reinforcement-thief-description rules: ghost-role-information-syndicate-monkey-reinforcement-rules entityPrototype: MobHumanSyndicateAgentThief + iconPrototype: SyndicateJawsOfLife From d8db80f49b460424c2378ee65046c9c3d00a57fa Mon Sep 17 00:00:00 2001 From: plykiya Date: Sat, 20 Jul 2024 22:02:02 -0700 Subject: [PATCH 5/7] forgot these were necessary to push lol --- Content.Server/Bible/BibleSystem.cs | 2 +- Content.Server/Zombies/ZombieSystem.Transform.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Content.Server/Bible/BibleSystem.cs b/Content.Server/Bible/BibleSystem.cs index 2cb0ac1dd76e..76efe3290bf0 100644 --- a/Content.Server/Bible/BibleSystem.cs +++ b/Content.Server/Bible/BibleSystem.cs @@ -1,11 +1,11 @@ using Content.Server.Bible.Components; -using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Events; using Content.Server.Popups; using Content.Shared.ActionBlocker; using Content.Shared.Actions; using Content.Shared.Bible; using Content.Shared.Damage; +using Content.Shared.Ghost.Roles.Components; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Inventory; diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index a8952009e66e..74adea6cd697 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -9,7 +9,6 @@ using Content.Server.Mind; using Content.Server.Mind.Commands; using Content.Server.NPC; -using Content.Server.NPC.Components; using Content.Server.NPC.HTN; using Content.Server.NPC.Systems; using Content.Server.Roles; @@ -24,10 +23,8 @@ using Content.Shared.Interaction.Components; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; -using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Systems; -using Content.Shared.NPC.Components; using Content.Shared.NPC.Systems; using Content.Shared.Nutrition.AnimalHusbandry; using Content.Shared.Nutrition.Components; @@ -38,6 +35,7 @@ using Content.Shared.Prying.Components; using Content.Shared.Traits.Assorted; using Robust.Shared.Audio.Systems; +using Content.Shared.Ghost.Roles.Components; namespace Content.Server.Zombies { From 713cd20a82ea0a313a4081b3c1146ce55a495251 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Sun, 21 Jul 2024 15:33:24 +1000 Subject: [PATCH 6/7] BUI update --- .../Ghost/GhostRoleRadioBoundUserInterface.cs | 16 +++------------- .../Ghost/GhostRoleRadioMenu.xaml.cs | 18 +++++------------- 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs index 6c4ec31229d1..3f0814a47fd1 100644 --- a/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs +++ b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Ghost.Roles; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Ghost; @@ -16,23 +17,12 @@ protected override void Open() { base.Open(); - _ghostRoleRadioMenu = new GhostRoleRadioMenu(Owner, this); - _ghostRoleRadioMenu.OnClose += Close; - - // Open menu centered wherever the mouse currently is - _ghostRoleRadioMenu.OpenCentered(); + _ghostRoleRadioMenu = this.CreateWindow(); + _ghostRoleRadioMenu.SendGhostRoleRadioMessageAction += SendGhostRoleRadioMessage; } public void SendGhostRoleRadioMessage(ProtoId protoId) { SendMessage(new GhostRoleRadioMessage(protoId)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _ghostRoleRadioMenu?.Dispose(); - } } diff --git a/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs index 82c23ba4dddb..19683da28c15 100644 --- a/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs +++ b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs @@ -17,7 +17,9 @@ public sealed partial class GhostRoleRadioMenu : RadialMenu public event Action>? SendGhostRoleRadioMessageAction; - public GhostRoleRadioMenu(EntityUid owner, GhostRoleRadioBoundUserInterface bui) + public EntityUid Entity { get; set; } + + public GhostRoleRadioMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); @@ -25,13 +27,10 @@ public GhostRoleRadioMenu(EntityUid owner, GhostRoleRadioBoundUserInterface bui) // The main control that will contain all of the clickable options var main = FindControl("Main"); - if (main == null) - return; - // The purpose of this radial UI is for ghost role radios that allow you to select // more than one potential option, such as with kobolds/lizards. // This means that it won't show anything if SelectablePrototypes is empty. - if (!_entityManager.TryGetComponent(owner, out var comp)) + if (!_entityManager.TryGetComponent(Entity, out var comp)) return; foreach (var ghostRoleProtoString in comp.SelectablePrototypes) @@ -40,7 +39,7 @@ public GhostRoleRadioMenu(EntityUid owner, GhostRoleRadioBoundUserInterface bui) // as the hover tooltip, and the icon is taken from either the ghost role entityprototype // or the indicated icon entityprototype. if (!_prototypeManager.TryIndex(ghostRoleProtoString, out var ghostRoleProto)) - return; + continue; var button = new GhostRoleRadioMenuButton() { @@ -67,8 +66,6 @@ public GhostRoleRadioMenu(EntityUid owner, GhostRoleRadioBoundUserInterface bui) button.AddChild(entProtoView); main.AddChild(button); AddGhostRoleRadioMenuButtonOnClickActions(main); - - SendGhostRoleRadioMessageAction += bui.SendGhostRoleRadioMessage; } } @@ -98,9 +95,4 @@ private void AddGhostRoleRadioMenuButtonOnClickActions(Control control) public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButton { public ProtoId ProtoId { get; set; } - - public GhostRoleRadioMenuButton() - { - - } } From b30fffca65ba5bdad4a0d88dfeb3bf2d0483ac74 Mon Sep 17 00:00:00 2001 From: plykiya Date: Sat, 20 Jul 2024 23:02:21 -0700 Subject: [PATCH 7/7] fixa the UI --- Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs | 1 + Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs index 3f0814a47fd1..33944973b51f 100644 --- a/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs +++ b/Content.Client/Ghost/GhostRoleRadioBoundUserInterface.cs @@ -18,6 +18,7 @@ protected override void Open() base.Open(); _ghostRoleRadioMenu = this.CreateWindow(); + _ghostRoleRadioMenu.SetEntity(Owner); _ghostRoleRadioMenu.SendGhostRoleRadioMessageAction += SendGhostRoleRadioMessage; } diff --git a/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs index 19683da28c15..b05ac3fbddde 100644 --- a/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs +++ b/Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs @@ -23,7 +23,16 @@ public GhostRoleRadioMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); + } + public void SetEntity(EntityUid uid) + { + Entity = uid; + RefreshUI(); + } + + private void RefreshUI() + { // The main control that will contain all of the clickable options var main = FindControl("Main");