diff --git a/Content.Client/Jobs/ClownSpecial.cs b/Content.Client/Jobs/ClownSpecial.cs deleted file mode 100644 index e5cd37f1e1..0000000000 --- a/Content.Client/Jobs/ClownSpecial.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Shared.Roles; -using JetBrains.Annotations; - -namespace Content.Client.Jobs -{ - [UsedImplicitly] - public sealed class ClownSpecial : JobSpecial - { - // Dummy class that exists solely to avoid an exception on the client, - // but allow the server-side counterpart to exist. - } -} diff --git a/Content.Client/Jobs/JanitorSpecial.cs b/Content.Client/Jobs/JanitorSpecial.cs deleted file mode 100644 index a2ad46b619..0000000000 --- a/Content.Client/Jobs/JanitorSpecial.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Shared.Roles; -using JetBrains.Annotations; - -namespace Content.Client.Jobs -{ - [UsedImplicitly] - public class JanitorSpecial : JobSpecial - { - // Dummy class that exists solely to avoid an exception on the client, - // but allow the server-side counterpart to exist. - } -} diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 4d24d6249a..b178b920e4 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -97,7 +97,11 @@ namespace Content.Server.GameTicking AddManifestEntry(character.Name, jobId); AddSpawnedPosition(jobId); EquipIdCard(mob, character.Name, jobPrototype); - jobPrototype.Special?.AfterEquip(mob); + + foreach (var jobSpecial in jobPrototype.Special) + { + jobSpecial.AfterEquip(mob); + } Preset?.OnSpawnPlayerCompleted(player, mob, lateJoin); } diff --git a/Content.Server/Jobs/AddComponentSpecial.cs b/Content.Server/Jobs/AddComponentSpecial.cs new file mode 100644 index 0000000000..e628c2b8ca --- /dev/null +++ b/Content.Server/Jobs/AddComponentSpecial.cs @@ -0,0 +1,26 @@ +using Content.Server.Interaction.Components; +using Content.Shared.Roles; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Jobs +{ + [UsedImplicitly] + public sealed class AddComponentSpecial : JobSpecial + { + // TODO: Type serializer that ensures the component exists. + [DataField("component", required:true)] + public string Component { get; } = string.Empty; + + public override void AfterEquip(IEntity mob) + { + // Yes, this will throw if your component is invalid. + var component = (Component)IoCManager.Resolve().GetComponent(Component); + component.Owner = mob; + + IoCManager.Resolve().AddComponent(mob, component); + } + } +} diff --git a/Content.Server/Jobs/ClownSpecial.cs b/Content.Server/Jobs/ClownSpecial.cs deleted file mode 100644 index 95bc2c753a..0000000000 --- a/Content.Server/Jobs/ClownSpecial.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Server.Interaction.Components; -using Content.Shared.Roles; -using JetBrains.Annotations; -using Robust.Shared.GameObjects; - -namespace Content.Server.Jobs -{ - // Used by clown job def. - [UsedImplicitly] - public sealed class ClownSpecial : JobSpecial - { - public override void AfterEquip(IEntity mob) - { - base.AfterEquip(mob); - - mob.AddComponent(); - } - } -} diff --git a/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs b/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs new file mode 100644 index 0000000000..e7f4e5c625 --- /dev/null +++ b/Content.Server/Jobs/GiveItemOnHolidaySpecial.cs @@ -0,0 +1,41 @@ +using Content.Server.Hands.Components; +using Content.Server.Holiday; +using Content.Server.Holiday.Interfaces; +using Content.Server.Items; +using Content.Shared.Roles; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Jobs +{ + [UsedImplicitly] + [DataDefinition] + public class GiveItemOnHolidaySpecial : JobSpecial + { + [DataField("holiday", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string Holiday { get; } = string.Empty; + + [DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string Prototype { get; } = string.Empty; + + public override void AfterEquip(IEntity mob) + { + if (string.IsNullOrEmpty(Holiday) || string.IsNullOrEmpty(Prototype)) + return; + + if (!IoCManager.Resolve().IsCurrentlyHoliday(Holiday)) + return; + + var entity = mob.EntityManager.SpawnEntity(Prototype, mob.Transform.Coordinates); + + if (!entity.TryGetComponent(out ItemComponent? item) || !mob.TryGetComponent(out HandsComponent? hands)) + return; + + hands.PutInHand(item, false); + } + } +} diff --git a/Content.Server/Jobs/JanitorSpecial.cs b/Content.Server/Jobs/JanitorSpecial.cs deleted file mode 100644 index 6b498fed83..0000000000 --- a/Content.Server/Jobs/JanitorSpecial.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Content.Server.Hands.Components; -using Content.Server.Holiday.Interfaces; -using Content.Server.Items; -using Content.Shared.Roles; -using JetBrains.Annotations; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Server.Jobs -{ - [UsedImplicitly] - [DataDefinition] - public class JanitorSpecial : JobSpecial - { - [DataField("holiday")] private readonly string _holiday = string.Empty; - [DataField("prototype")] private readonly string _prototype = string.Empty; - - public override void AfterEquip(IEntity mob) - { - base.AfterEquip(mob); - - if (string.IsNullOrEmpty(_holiday) || string.IsNullOrEmpty(_prototype)) return; - if (!IoCManager.Resolve().IsCurrentlyHoliday(_holiday)) return; - - var item = mob.EntityManager.SpawnEntity(_prototype, mob.Transform.Coordinates); - if (!item.TryGetComponent(out ItemComponent? itemComp)) return; - if (!mob.TryGetComponent(out HandsComponent? handsComponent)) return; - handsComponent.PutInHand(itemComp, false); - } - } -} diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs index fea7913f3e..e3ed183c8f 100644 --- a/Content.Shared/Roles/JobPrototype.cs +++ b/Content.Shared/Roles/JobPrototype.cs @@ -50,8 +50,8 @@ namespace Content.Shared.Roles [DataField("icon")] public string Icon { get; } = string.Empty; - [DataField("special")] - public JobSpecial? Special { get; private set; } + [DataField("special", serverOnly:true)] + public JobSpecial[] Special { get; private set; } = Array.Empty(); [DataField("departments")] public IReadOnlyCollection Departments { get; } = Array.Empty(); diff --git a/Content.Shared/Roles/JobSpecial.cs b/Content.Shared/Roles/JobSpecial.cs index c2924eb014..8ef76fda0f 100644 --- a/Content.Shared/Roles/JobSpecial.cs +++ b/Content.Shared/Roles/JobSpecial.cs @@ -9,9 +9,6 @@ namespace Content.Shared.Roles [ImplicitDataDefinitionForInheritors] public abstract class JobSpecial { - public virtual void AfterEquip(IEntity mob) - { - - } + public abstract void AfterEquip(IEntity mob); } } diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml index 813f466790..1218463c48 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/clown.yml @@ -9,7 +9,9 @@ access: - Theatre - Maintenance - special: !type:ClownSpecial {} + special: + - !type:AddComponentSpecial + component: Clumsy # Adds ClumsyComponent to the mob. - type: startingGear id: ClownGear diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml index 8800fe1656..4210498af5 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/janitor.yml @@ -10,7 +10,7 @@ - Janitor - Maintenance special: - !type:JanitorSpecial + - !type:GiveItemOnHolidaySpecial holiday: GarbageDay prototype: RevolverInspector