diff --git a/Content.Server/Clothing/Systems/LoadoutSystem.Functions.cs b/Content.Server/Clothing/Systems/LoadoutSystem.Functions.cs new file mode 100644 index 00000000000..99ca8b15c28 --- /dev/null +++ b/Content.Server/Clothing/Systems/LoadoutSystem.Functions.cs @@ -0,0 +1,30 @@ +using JetBrains.Annotations; +using Robust.Shared.Serialization.Manager; +using Content.Shared.Clothing.Loadouts.Prototypes; +using Content.Server.NPC.Components; +using Content.Server.NPC.Systems; +using Content.Server.NPC.HTN; +using Content.Server.NPC; +using Robust.Shared.Map; +using System.Numerics; + +namespace Content.Server.Clothing.Systems; + +[UsedImplicitly] +public sealed partial class LoadoutMakeFollower : LoadoutFunction +{ + public override void OnPlayerSpawn(EntityUid character, + EntityUid loadoutEntity, + IComponentFactory factory, + IEntityManager entityManager, + ISerializationManager serializationManager) + { + var npc = entityManager.System(); + var htn = entityManager.System(); + if (!entityManager.TryGetComponent(loadoutEntity, out var hTNComponent)) + return; + + npc.SetBlackboard(loadoutEntity, NPCBlackboard.FollowTarget, new EntityCoordinates(character, Vector2.Zero), hTNComponent); + htn.Replan(hTNComponent); + } +} diff --git a/Content.Server/Clothing/Systems/LoadoutSystem.cs b/Content.Server/Clothing/Systems/LoadoutSystem.cs index 1527db0be85..4c357c58642 100644 --- a/Content.Server/Clothing/Systems/LoadoutSystem.cs +++ b/Content.Server/Clothing/Systems/LoadoutSystem.cs @@ -13,7 +13,6 @@ using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; using Content.Shared.Traits.Assorted.Components; -using Content.Shared.Whitelist; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -33,6 +32,7 @@ public sealed class LoadoutSystem : EntitySystem [Dependency] private readonly IPrototypeManager _protoMan = default!; [Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IComponentFactory _componentFactory = default!; public override void Initialize() @@ -103,6 +103,9 @@ public void ApplyCharacterLoadout( comp.Owner = loadout.Item1; EntityManager.AddComponent(loadout.Item1, comp); } + + foreach (var function in loadoutProto.Functions) + function.OnPlayerSpawn(uid, loadout.Item1, _componentFactory, EntityManager, _serialization); } diff --git a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs index 38a356b1e0d..ecb3c3fd6c5 100644 --- a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs +++ b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs @@ -1,5 +1,6 @@ using Content.Shared.Customization.Systems; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; namespace Content.Shared.Clothing.Loadouts.Prototypes; @@ -45,4 +46,19 @@ public sealed partial class LoadoutPrototype : IPrototype [DataField] public string GuideEntry { get; } = ""; + + [DataField(serverOnly: true)] + public LoadoutFunction[] Functions { get; private set; } = Array.Empty(); +} + +/// This serves as a hook for loadout functions to modify one or more entities upon spawning in. +[ImplicitDataDefinitionForInheritors] +public abstract partial class LoadoutFunction +{ + public abstract void OnPlayerSpawn( + EntityUid character, + EntityUid loadoutEntity, + IComponentFactory factory, + IEntityManager entityManager, + ISerializationManager serializationManager); } diff --git a/Resources/Locale/en-US/loadouts/generic/items.ftl b/Resources/Locale/en-US/loadouts/generic/items.ftl index ac52b8be226..37ca4f91fe3 100644 --- a/Resources/Locale/en-US/loadouts/generic/items.ftl +++ b/Resources/Locale/en-US/loadouts/generic/items.ftl @@ -42,3 +42,8 @@ loadout-name-LoadoutItemLighterFlippo = flippo lighter (colorable) loadout-name-LoadoutItemDrinkShinyFlask = shiny flask (colorable) loadout-name-LoadoutItemDrinkLithiumFlask = lithium flask (colorable) loadout-name-LoadoutItemDrinkVacuumFlask = vacuum flask (colorable) + +loadout-name-LoadoutItemPetMouse = pet mouse +loadout-name-LoadoutItemPetHamster = pet hamster +loadout-name-LoadoutItemPetMothroach = pet mothroach +loadout-name-LoadoutItemPetCockroach = pet cockroach diff --git a/Resources/Locale/en-US/loadouts/itemgroups.ftl b/Resources/Locale/en-US/loadouts/itemgroups.ftl index b6221e85850..8af87679c45 100644 --- a/Resources/Locale/en-US/loadouts/itemgroups.ftl +++ b/Resources/Locale/en-US/loadouts/itemgroups.ftl @@ -17,6 +17,7 @@ character-item-group-LoadoutInstrumentsAny = Musical Instruments (Non-Musician) character-item-group-LoadoutSmokes = Smokeables character-item-group-LoadoutBoxKits = Survival Kits character-item-group-LoadoutWritables = Writing Tools +character-item-group-LoadoutPets = Pets # Job Specific Template character-item-group-LoadoutJOBBackpacks = JOB Backpacks diff --git a/Resources/Prototypes/CharacterItemGroups/Generic/miscItemGroups.yml b/Resources/Prototypes/CharacterItemGroups/Generic/miscItemGroups.yml index 3cad4423f52..cc1e82ceb69 100644 --- a/Resources/Prototypes/CharacterItemGroups/Generic/miscItemGroups.yml +++ b/Resources/Prototypes/CharacterItemGroups/Generic/miscItemGroups.yml @@ -121,3 +121,16 @@ id: LoadoutBookRandom - type: loadout id: LoadoutPen + +- type: characterItemGroup + id: LoadoutPets + maxItems: 1 + items: + - type: loadout + id: LoadoutItemPetMouse + - type: loadout + id: LoadoutItemPetHamster + - type: loadout + id: LoadoutItemPetMothroach + - type: loadout + id: LoadoutItemPetCockroach diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 6e369389a90..1ee20cdcb61 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -404,6 +404,21 @@ speaks: [Hissing] understands: [Hissing] +- type: entity + parent: MobCockroach + id: MobCockroachPet + components: + - type: HTN + rootTask: + task: FollowCompound + blackboard: + IdleRange: !type:Single + 1.5 + FollowCloseRange: !type:Single + 1.0 + FollowRange: !type:Single + 2.0 + - type: entity name: glockroach parent: MobCockroach @@ -575,6 +590,21 @@ enum.SurgeryUIKey.Key: type: SurgeryBui +- type: entity + parent: MobMothroach + id: MobMothroachPet + components: + - type: HTN + rootTask: + task: FollowCompound + blackboard: + IdleRange: !type:Single + 1.5 + FollowCloseRange: !type:Single + 1.0 + FollowRange: !type:Single + 2.0 + # Note that the mallard duck is actually a male drake mallard, with the brown duck being the female variant of the same species, however ss14 lacks sex specific textures # The white duck is more akin to a pekin or call duck. @@ -1769,6 +1799,21 @@ enum.SurgeryUIKey.Key: type: SurgeryBui +- type: entity + parent: MobMouse + id: MobMousePet + components: + - type: HTN + rootTask: + task: FollowCompound + blackboard: + IdleRange: !type:Single + 1.5 + FollowCloseRange: !type:Single + 1.0 + FollowRange: !type:Single + 2.0 + - type: entity parent: MobMouse suffix: Dead @@ -3418,6 +3463,21 @@ sprite: Mobs/Effects/onfire.rsi normalState: Mouse_burning +- type: entity + parent: MobHamster + id: MobHamsterPet + components: + - type: HTN + rootTask: + task: FollowCompound + blackboard: + IdleRange: !type:Single + 1.5 + FollowCloseRange: !type:Single + 1.0 + FollowRange: !type:Single + 2.0 + - type: entity name: pig parent: SimpleMobBase diff --git a/Resources/Prototypes/Loadouts/Generic/items.yml b/Resources/Prototypes/Loadouts/Generic/items.yml index dafe7c9ffa5..2c42955c08f 100644 --- a/Resources/Prototypes/Loadouts/Generic/items.yml +++ b/Resources/Prototypes/Loadouts/Generic/items.yml @@ -766,3 +766,56 @@ customColorTint: true items: - DrinkVacuumFlask + +# Pets +- type: loadout + id: LoadoutItemPetMouse + category: Items + cost: 2 + canBeHeirloom: true + items: + - MobMousePet + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPets + functions: + - !type:LoadoutMakeFollower + +- type: loadout + id: LoadoutItemPetHamster + category: Items + cost: 2 + canBeHeirloom: true + items: + - MobHamsterPet + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPets + functions: + - !type:LoadoutMakeFollower + +- type: loadout + id: LoadoutItemPetMothroach + category: Items + cost: 2 + canBeHeirloom: true + items: + - MobMothroachPet + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPets + functions: + - !type:LoadoutMakeFollower + +- type: loadout + id: LoadoutItemPetCockroach + category: Items + cost: 2 + canBeHeirloom: true + items: + - MobCockroachPet + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPets + functions: + - !type:LoadoutMakeFollower