diff --git a/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonComponent.cs b/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonComponent.cs new file mode 100644 index 0000000000..65d8bc0a97 --- /dev/null +++ b/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonComponent.cs @@ -0,0 +1,28 @@ +using Content.Shared.Actions.ActionTypes; +using Robust.Shared.Utility; + +namespace Content.Server.White.Other.CustomFluffSystems.Pets; + +[RegisterComponent] +public sealed class PetSummonComponent : Component +{ + public InstantAction PetSummonAction = new() + { + Icon = new SpriteSpecifier.Texture(new ResPath("Objects/Misc/books.rsi/summon_book.png")), + DisplayName = "Призыв", + Description = "Призыв питомца БЕЗ возможности вселения призрака", + Event = new PetSummonActionEvent() + }; + + public InstantAction PetGhostSummonAction = new() + { + Icon = new SpriteSpecifier.Texture(new ResPath("Mobs/Ghosts/ghost_human.rsi/icon.png")), + DisplayName = "Призрачный призыв", + Description = "Призыв питомца С возможностью вселения призрака", + Event = new PetGhostSummonActionEvent() + }; + + public int UsesLeft = 10; + + public EntityUid? SummonedEntity; +} diff --git a/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonSystem.cs b/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonSystem.cs new file mode 100644 index 0000000000..1382e9439e --- /dev/null +++ b/Content.Server/White/Other/CustomFluffSystems/Pets/PetSummonSystem.cs @@ -0,0 +1,172 @@ +using Content.Server.Ghost.Roles.Components; +using Content.Shared.ActionBlocker; +using Content.Shared.Actions; +using Content.Shared.Examine; +using Content.Shared.Item; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Server.GameObjects; + +namespace Content.Server.White.Other.CustomFluffSystems.Pets; + +public sealed class PetSummonSystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + + private IReadOnlyDictionary MobMap = new Dictionary() + { + { "Wanderer_", "KommandantPetSpider" }, + }; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(GetSummonAction); + SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent>(AddSummonVerb); + SubscribeLocalEvent(OnSummon); + SubscribeLocalEvent(OnGhostSummon); + } + + private void OnGhostSummon(EntityUid uid, PetSummonComponent component, PetGhostSummonActionEvent args) + { + AttemptSummon(component, args.Performer, true); + } + + private void OnSummon(EntityUid uid, PetSummonComponent component, PetSummonActionEvent args) + { + AttemptSummon(component, args.Performer, false); + } + + private void AddSummonVerb(EntityUid uid, PetSummonComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + AlternativeVerb verb = new() + { + Act = () => + { + AttemptSummon(component, args.User, false); + }, + Text = "Призвать питомца", + Priority = 2 + }; + + AlternativeVerb ghostVerb = new() + { + Act = () => + { + AttemptSummon(component, args.User, true); + }, + Text = "Призвать питомца-призрак", + Priority = 2 + }; + + args.Verbs.Add(verb); + args.Verbs.Add(ghostVerb); + } + + private void OnExamine(EntityUid uid, PetSummonComponent component, ExaminedEvent args) + { + args.PushMarkup($"Осталось призывов: {component.UsesLeft}"); + } + + private void AttemptSummon(PetSummonComponent component, EntityUid user, bool ghostRole) + { + if (!_blocker.CanInteract(user, component.Owner)) + return; + + string? mobProto = null; + if (TryComp(user, out var actorComponent)) + { + var userKey = actorComponent.PlayerSession.Name; + + if (!MobMap.TryGetValue(userKey, out var proto)) + { + _popupSystem.PopupEntity("Вы не достойны", user, PopupType.Medium); + return; + } + + mobProto = proto; + } + + if (component.UsesLeft == 0) + { + _popupSystem.PopupEntity("Больше нет зарядов!", user, PopupType.Medium); + return; + } + + if (component.SummonedEntity != null) + { + if (!TryComp(component.SummonedEntity, out var mobState)) + { + component.SummonedEntity = null; + } + else + { + if (mobState.CurrentState is MobState.Dead or MobState.Invalid) + component.SummonedEntity = null; + else + { + _popupSystem.PopupEntity("Ваш питомец уже призван", user, PopupType.Medium); + return; + } + } + + } + + if (mobProto != null) + SummonPet(user, component, mobProto, ghostRole); + } + + private void SummonPet(EntityUid user, PetSummonComponent component, string mobProto, bool ghostRole) + { + var transform = CompOrNull(user)?.Coordinates; + + if (transform == null) + return; + + var entity = _entityManager.SpawnEntity(mobProto, transform.Value); + component.UsesLeft--; + component.SummonedEntity = entity; + + if (ghostRole) + SetupGhostRole(entity, user); + else + RemComp(entity); + } + + private void SetupGhostRole(EntityUid entity, EntityUid user) + { + EnsureComp(entity); + + if (!TryComp(entity, out var ghostRole)) + return; + + var meta = MetaData(user); + ghostRole.RoleName = $"Питомец {meta.EntityName}"; + ghostRole.RoleDescription = $"Следуйте за хозяином - {meta.EntityName} и выполняйте его приказы"; + ghostRole.RoleRules = $"Вы должны до самого конца следовать за своим хозяином - {meta.EntityName} и послушно выполнять его приказы, иначе можете быть уничтожены."; + } + + private void GetSummonAction(EntityUid uid, PetSummonComponent component, GetItemActionsEvent args) + { + args.Actions.Add(component.PetSummonAction); + args.Actions.Add(component.PetGhostSummonAction); + } +} + +public sealed class PetSummonActionEvent : InstantActionEvent +{ +} + +public sealed class PetGhostSummonActionEvent : InstantActionEvent +{ +} diff --git a/Resources/Prototypes/White/Fluff/fluff.yml b/Resources/Prototypes/White/Fluff/fluff.yml index 4243672dda..8af1983198 100644 --- a/Resources/Prototypes/White/Fluff/fluff.yml +++ b/Resources/Prototypes/White/Fluff/fluff.yml @@ -163,3 +163,21 @@ damage: types: Blunt: 0 + +# Pets book +- type: entity + parent: BookBase + id: PetSummonBook + name: странная потрёпанная книга + description: Книга непонятного происхождения. + suffix: Флафф + components: + - type: Sprite + sprite: Objects/Misc/books.rsi + layers: + - state: summon_book + - type: Item + size: 5 + - type: Paper + content: Ego voco electi pet + - type: PetSummon diff --git a/Resources/Prototypes/White/Fluff/sponsor.yml b/Resources/Prototypes/White/Fluff/sponsor.yml index faaecad893..8917dc5d76 100644 --- a/Resources/Prototypes/White/Fluff/sponsor.yml +++ b/Resources/Prototypes/White/Fluff/sponsor.yml @@ -57,3 +57,9 @@ id: OmntnsHammerLoadout entity: OmntnsHammer sponsorOnly: true + +# Pets summon book +- type: loadout + id: PetsSummonBookLoadout + entity: PetSummonBook + sponsorOnly: true diff --git a/Resources/Prototypes/White/Mobs/Pets/pets.yml b/Resources/Prototypes/White/Mobs/Pets/pets.yml new file mode 100644 index 0000000000..00fe88d1bf --- /dev/null +++ b/Resources/Prototypes/White/Mobs/Pets/pets.yml @@ -0,0 +1,73 @@ +# Kommandant +- type: entity + parent: SimpleMobBase + id: KommandantPetSpider + name: паук Валера + description: Любит мух и деньги. + components: + - type: Faction + factions: + - PetsNT + - type: Sprite + drawdepth: Mobs + layers: + - map: [ "enum.DamageStateVisualLayers.Base" ] + state: viper + sprite: White/Mobs/Pets/Kommandant/spider.rsi + scale: "0.5, 0.5" + - type: Physics + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 130 + mask: + - MobMask + layer: + - MobLayer + - type: Appearance + - type: DamageStateVisuals + states: + Alive: + Base: viper + Critical: + Base: viper_dead + Dead: + Base: viper_dead + - type: MobThresholds + thresholds: + 0: Alive + 90: Critical + 150: Dead + - type: ReplacementAccent + accent: xeno + - type: InteractionPopup + successChance: 0.5 + interactSuccessString: petting-success-tarantula + interactFailureString: petting-failure-generic + - type: IgnoreSpiderWeb + - type: NoSlip + - type: CanEscapeInventory + - type: Grammar + attributes: + proper: true + gender: female + - type: Bloodstream + bloodMaxVolume: 150 + bloodReagent: SpiderBlood + - type: Pacifist + - type: Tag + tags: + - CannotSuicide + - type: Item + size: 10 + - type: GhostRole + makeSentient: true + allowSpeech: true + allowMovement: true + name: "Питомец" + description: "Следуйте за хозяином" + rules: "Всегда следуйте за хозяином и слушайте его приказы." + diff --git a/Resources/Textures/Objects/Misc/books.rsi/meta.json b/Resources/Textures/Objects/Misc/books.rsi/meta.json index daa28bac2a..6493495363 100644 --- a/Resources/Textures/Objects/Misc/books.rsi/meta.json +++ b/Resources/Textures/Objects/Misc/books.rsi/meta.json @@ -101,6 +101,9 @@ }, { "name": "book_fish" + }, + { + "name": "summon_book" } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Objects/Misc/books.rsi/summon_book.png b/Resources/Textures/Objects/Misc/books.rsi/summon_book.png new file mode 100644 index 0000000000..8d1350f1ad Binary files /dev/null and b/Resources/Textures/Objects/Misc/books.rsi/summon_book.png differ diff --git a/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/meta.json b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/meta.json new file mode 100644 index 0000000000..36d381f4a4 --- /dev/null +++ b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/meta.json @@ -0,0 +1,40 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/frosty-dev/white", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "viper", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "viper_dead" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper.png b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper.png new file mode 100644 index 0000000000..9a53f0f54a Binary files /dev/null and b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper.png differ diff --git a/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper_dead.png b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper_dead.png new file mode 100644 index 0000000000..040ab3e49a Binary files /dev/null and b/Resources/Textures/White/Mobs/Pets/Kommandant/spider.rsi/viper_dead.png differ