]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
monkey reinforcement teleporters can now select between kobold or monkey with a verb...
authorMr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com>
Fri, 26 Apr 2024 13:06:43 +0000 (09:06 -0400)
committerGitHub <noreply@github.com>
Fri, 26 Apr 2024 13:06:43 +0000 (15:06 +0200)
* 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>
Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs
Content.Server/Ghost/Roles/GhostRoleSystem.cs
Content.Shared/Ghost/Roles/GhostRolePrototype.cs [new file with mode: 0644]
Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl
Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl [new file with mode: 0644]
Resources/Locale/en-US/store/uplink-catalog.ftl
Resources/Prototypes/Catalog/uplink_catalog.yml
Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml
Resources/Prototypes/Roles/Ghostroles/syndicate.yml [new file with mode: 0644]
Resources/migration.yml

index 4cdab6ce070287f7fabc95ebb032b5deffb0a20e..6c2a6986fc96e95e3fe55278c0d05b93b58053fb 100644 (file)
@@ -1,5 +1,4 @@
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Server.Ghost.Roles.Components
 {
@@ -10,17 +9,22 @@ namespace Content.Server.Ghost.Roles.Components
     [Access(typeof(GhostRoleSystem))]
     public sealed partial class GhostRoleMobSpawnerComponent : Component
     {
-        [ViewVariables(VVAccess.ReadWrite)] [DataField("deleteOnSpawn")]
+        [DataField]
         public bool DeleteOnSpawn = true;
 
-        [ViewVariables(VVAccess.ReadWrite)] [DataField("availableTakeovers")]
+        [DataField]
         public int AvailableTakeovers = 1;
 
         [ViewVariables]
         public int CurrentTakeovers = 0;
 
-        [ViewVariables(VVAccess.ReadWrite)]
-        [DataField("prototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-        public string? Prototype { get; private set; }
+        [DataField]
+        public EntProtoId? Prototype;
+
+        /// <summary>
+        ///     If this ghostrole spawner has multiple selectable ghostrole prototypes.
+        /// </summary>
+        [DataField]
+        public List<string> SelectablePrototypes = [];
     }
 }
index 0649e68a317c22cdbb1dfdf022868cbd4f696eaa..e7495020c80104b27a45e6ec9eeb98f8540d7d98 100644 (file)
@@ -23,6 +23,10 @@ using Robust.Shared.Enums;
 using Robust.Shared.Player;
 using Robust.Shared.Random;
 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
 {
@@ -37,6 +41,8 @@ namespace Content.Server.Ghost.Roles
         [Dependency] private readonly TransformSystem _transform = default!;
         [Dependency] private readonly SharedMindSystem _mindSystem = default!;
         [Dependency] private readonly SharedRoleSystem _roleSystem = default!;
+        [Dependency] private readonly PopupSystem _popupSystem = default!;
+        [Dependency] private readonly IPrototypeManager _prototype = default!;
 
         private uint _nextRoleIdentifier;
         private bool _needsUpdateGhostRoleCount = true;
@@ -63,6 +69,7 @@ namespace Content.Server.Ghost.Roles
             SubscribeLocalEvent<GhostRoleComponent, EntityUnpausedEvent>(OnUnpaused);
             SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole);
             SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
+            SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GetVerbsEvent<Verb>>(OnVerb);
             _playerManager.PlayerStatusChanged += PlayerStatusChanged;
         }
 
@@ -74,11 +81,11 @@ namespace Content.Server.Ghost.Roles
             switch (args.NewMobState)
             {
                 case MobState.Alive:
-                {
-                    if (!ghostRole.Taken)
-                        RegisterGhostRole((component, ghostRole));
-                    break;
-                }
+                    {
+                        if (!ghostRole.Taken)
+                            RegisterGhostRole((component, ghostRole));
+                        break;
+                    }
                 case MobState.Critical:
                 case MobState.Dead:
                     UnregisterGhostRole((component, ghostRole));
@@ -100,11 +107,11 @@ namespace Content.Server.Ghost.Roles
 
         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))
                 return;
 
-            if(_openUis.ContainsKey(session))
+            if (_openUis.ContainsKey(session))
                 CloseEui(session);
 
             var eui = _openUis[session] = new GhostRolesEui();
@@ -250,7 +257,7 @@ namespace Content.Server.Ghost.Roles
                 if (metaQuery.GetComponent(uid).EntityPaused)
                     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();
@@ -407,6 +414,63 @@ namespace Content.Server.Ghost.Roles
 
             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]
@@ -417,7 +481,7 @@ namespace Content.Server.Ghost.Roles
         public string Help => $"{Command}";
         public void Execute(IConsoleShell shell, string argStr, string[] args)
         {
-            if(shell.Player != null)
+            if (shell.Player != null)
                 EntitySystem.Get<GhostRoleSystem>().OpenEui(shell.Player);
             else
                 shell.WriteLine("You can only open the ghost roles UI on a client.");
diff --git a/Content.Shared/Ghost/Roles/GhostRolePrototype.cs b/Content.Shared/Ghost/Roles/GhostRolePrototype.cs
new file mode 100644 (file)
index 0000000..43d6432
--- /dev/null
@@ -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!;
+}
\ No newline at end of file
index 23a178d282a1976fe1600b98fa8fde876ee0c122..d307813c26ed77eccc10b6d5edb4c37e667fbcb6 100644 (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-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-description =
       Enact your eldritch whims.
diff --git a/Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl b/Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl
new file mode 100644 (file)
index 0000000..9d649a5
--- /dev/null
@@ -0,0 +1 @@
+ghostrole-spawner-select = Selected: {$mode}
\ No newline at end of file
index 57a309ac69a914c96d53b2c2590534f0064be5f0..49d4ca0028ddb447adef73f257bfb594cdc49232 100644 (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-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-monkey-desc =  Call in a trained monkey to assist you. Comes with a single syndicate cigarette.
+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.
index a7c2dbc7a4f517b0a7440ec035deca9a85f923b5..ca1a2e4f2dacdd8b51e90da1e6c8b3d5d56d5a64 100644 (file)
           - NukeOpsUplink
 
 - type: listing
-  id: UplinkReinforcementRadioSyndicateMonkey
-  name: uplink-reinforcement-radio-monkey-name
-  description: uplink-reinforcement-radio-monkey-desc
-  productEntity: ReinforcementRadioSyndicateMonkey
+  id: UplinkReinforcementRadioSyndicateAncestor
+  name: uplink-reinforcement-radio-ancestor-name
+  description: uplink-reinforcement-radio-ancestor-desc
+  productEntity: ReinforcementRadioSyndicateAncestor
   icon: { sprite: Objects/Devices/communication.rsi, state: old-radio }
   cost:
     Telecrystal: 6
           - NukeOpsUplink
 
 - type: listing
-  id: UplinkReinforcementRadioSyndicateMonkeyNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component.
-  name: uplink-reinforcement-radio-monkey-name
-  description: uplink-reinforcement-radio-monkey-desc
-  productEntity: ReinforcementRadioSyndicateMonkeyNukeops
+  id: UplinkReinforcementRadioSyndicateAncestorNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component.
+  name: uplink-reinforcement-radio-ancestor-name
+  description: uplink-reinforcement-radio-ancestor-desc
+  productEntity: ReinforcementRadioSyndicateAncestorNukeops
   icon: { sprite: Objects/Devices/communication.rsi, state: old-radio }
   cost:
     Telecrystal: 6
index c0a99ec8a0c6dcfe0c580658cdfb62b4de91c30d..ab6afb540320698bcfda60eea69eb80b492bf6f0 100644 (file)
 
 - type: entity
   name: kobold
-  id: MobKobold
+  id: MobBaseKobold
   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.
+  abstract: true
   components:
   - type: NameIdentifier
     group: Kobold
     spawned:
     - id: FoodMeat
       amount: 2
-  - type: Clumsy
-    clumsyDamage:
-      types:
-        Blunt: 2
-        Piercing: 7
-      groups:
-        Burn: 3
-    clumsySound:
-      path: /Audio/Voice/Reptilian/reptilian_scream.ogg
   - type: AlwaysRevolutionaryConvertible
   - type: GhostTakeoverAvailable
   - type: SentienceTarget
     name: ghost-role-information-kobold-name
     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
   name: guidebook monkey
   parent: MobMonkey
index f6d57f53a50d2ccf6b73fe5444394070325cbb90..3ce39afcebbc13dc6c33bba4b06a3c86b779e4b6 100644 (file)
@@ -29,9 +29,9 @@
 
 - type: entity
   parent: ReinforcementRadioSyndicate
-  id: ReinforcementRadioSyndicateMonkey
-  name: syndicate monkey reinforcement radio
-  description: Calls in a specially trained monkey to assist you.
+  id: ReinforcementRadioSyndicateAncestor
+  name: syndicate genetic ancestor reinforcement radio
+  description: Calls in a specially trained ancestor of your choosing to assist you.
   components:
   - type: GhostRole
     name: ghost-role-information-syndicate-monkey-reinforcement-name
     rules: ghost-role-information-syndicate-monkey-reinforcement-rules
   - type: GhostRoleMobSpawner
     prototype: MobMonkeySyndicateAgent
+    selectablePrototypes: ["SyndicateMonkey", "SyndicateKobold"]
 
 - type: entity
-  parent: ReinforcementRadioSyndicateMonkey
-  id: ReinforcementRadioSyndicateMonkeyNukeops # Reinforcement radio exclusive to nukeops uplink
+  parent: ReinforcementRadioSyndicateAncestor
+  id: ReinforcementRadioSyndicateAncestorNukeops # Reinforcement radio exclusive to nukeops uplink
   suffix: NukeOps
   components:
   - type: GhostRoleMobSpawner
     prototype: MobMonkeySyndicateAgentNukeops
+    selectablePrototypes: ["SyndicateMonkeyNukeops", "SyndicateKoboldNukeops"]
 
 - type: entity
   parent: ReinforcementRadioSyndicate
diff --git a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml
new file mode 100644 (file)
index 0000000..24c0d8b
--- /dev/null
@@ -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
\ No newline at end of file
index 04e4f4b0801fa4717c66cbcabea1a49d439ac2d8..bf18cfe555b5e6e1ae3e1558f514acf7fca97426 100644 (file)
@@ -327,3 +327,5 @@ WeaponPistolN1984Nonlethal: WeaponPistolN1984
 WeaponSubMachineGunVectorRubber: WeaponSubMachineGunVector
 WeaponSubMachineGunDrozdRubber: WeaponSubMachineGunDrozd
 WeaponRifleLecterRubber: WeaponRifleLecter
+ReinforcementRadioSyndicateMonkey: ReinforcementRadioSyndicateAncestor
+ReinforcementRadioSyndicateMonkeyNukeops: ReinforcementRadioSyndicateAncestorNukeops