From 407d4aed586a5143dc1dd0d31e7898f6df07a411 Mon Sep 17 00:00:00 2001 From: LankLTE <135308300+LankLTE@users.noreply.github.com> Date: Fri, 16 Feb 2024 18:54:44 -0800 Subject: [PATCH] Diona Nymphs & Splitting (#24630) * Porting & implementation * Fix two stupid errors * Human not humans * fix audio path * Fix test fails & update cooldown * Work on reviews & test fail * Rework nymph organ system. * Make the nymph organs nospawn. * IsDeadIC --- .../Atmos/EntitySystems/FlammableSystem.cs | 29 +++++ .../Components/IgniteOnHeatDamageComponent.cs | 15 +++ .../Silicons/Borgs/BorgSystem.Modules.cs | 2 +- .../Mind/Components/IsDeadICComponent.cs | 8 ++ Content.Shared/Mind/IsDeadICSystem.cs | 21 ++++ .../Species/Components/GibActionComponent.cs | 30 +++++ .../Species/Components/NymphComponent.cs | 24 ++++ .../Species/Components/ReformComponent.cs | 48 ++++++++ .../Species/Systems/GibActionSystem.cs | 61 ++++++++++ Content.Shared/Species/Systems/NymphSystem.cs | 41 +++++++ .../Species/Systems/ReformSystem.cs | 108 +++++++++++++++++ Resources/Audio/Animals/attributions.yml | 8 +- Resources/Audio/Animals/nymph_chirp.ogg | Bin 0 -> 6270 bytes .../Locale/en-US/actions/actions/diona.ftl | 3 + .../interaction-popup-component.ftl | 2 + Resources/Prototypes/Actions/diona.yml | 21 ++++ Resources/Prototypes/Body/Organs/diona.yml | 113 ++++++++++++++++-- .../Body/Prototypes/Animal/nymph.yml | 66 ++++++++++ .../Prototypes/Body/Prototypes/diona.yml | 6 +- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 74 ++++++++++++ .../Prototypes/Entities/Mobs/Player/diona.yml | 10 ++ .../Entities/Mobs/Species/diona.yml | 7 ++ .../Textures/Mobs/Animals/nymph.rsi/icon.png | Bin 0 -> 611 bytes .../Textures/Mobs/Animals/nymph.rsi/meta.json | 63 ++++++++++ .../Textures/Mobs/Animals/nymph.rsi/nymph.png | Bin 0 -> 3891 bytes .../Mobs/Animals/nymph.rsi/nymph_dead.png | Bin 0 -> 655 bytes .../Mobs/Animals/nymph.rsi/nymph_sleep.png | Bin 0 -> 1306 bytes 27 files changed, 743 insertions(+), 17 deletions(-) create mode 100644 Content.Server/Damage/Components/IgniteOnHeatDamageComponent.cs create mode 100644 Content.Shared/Mind/Components/IsDeadICComponent.cs create mode 100644 Content.Shared/Mind/IsDeadICSystem.cs create mode 100644 Content.Shared/Species/Components/GibActionComponent.cs create mode 100644 Content.Shared/Species/Components/NymphComponent.cs create mode 100644 Content.Shared/Species/Components/ReformComponent.cs create mode 100644 Content.Shared/Species/Systems/GibActionSystem.cs create mode 100644 Content.Shared/Species/Systems/NymphSystem.cs create mode 100644 Content.Shared/Species/Systems/ReformSystem.cs create mode 100644 Resources/Audio/Animals/nymph_chirp.ogg create mode 100644 Resources/Locale/en-US/actions/actions/diona.ftl create mode 100644 Resources/Prototypes/Actions/diona.yml create mode 100644 Resources/Prototypes/Body/Prototypes/Animal/nymph.yml create mode 100644 Resources/Textures/Mobs/Animals/nymph.rsi/icon.png create mode 100644 Resources/Textures/Mobs/Animals/nymph.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Animals/nymph.rsi/nymph.png create mode 100644 Resources/Textures/Mobs/Animals/nymph.rsi/nymph_dead.png create mode 100644 Resources/Textures/Mobs/Animals/nymph.rsi/nymph_sleep.png diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index cb1cb9bc15..53fcb72076 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -4,6 +4,7 @@ using Content.Server.IgnitionSource; using Content.Server.Stunnable; using Content.Server.Temperature.Components; using Content.Server.Temperature.Systems; +using Content.Server.Damage.Components; using Content.Shared.ActionBlocker; using Content.Shared.Alert; using Content.Shared.Atmos; @@ -20,6 +21,7 @@ using Content.Shared.Throwing; using Content.Shared.Timing; using Content.Shared.Toggleable; using Content.Shared.Weapons.Melee.Events; +using Content.Shared.FixedPoint; using Robust.Server.Audio; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -73,6 +75,8 @@ namespace Content.Server.Atmos.EntitySystems SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnExtinguishActivateInWorld); + + SubscribeLocalEvent(OnDamageChanged); } private void OnMeleeHit(EntityUid uid, IgniteOnMeleeHitComponent component, MeleeHitEvent args) @@ -318,6 +322,31 @@ namespace Content.Server.Atmos.EntitySystems UpdateAppearance(uid, flammable); } + private void OnDamageChanged(EntityUid uid, IgniteOnHeatDamageComponent component, DamageChangedEvent args) + { + // Make sure the entity is flammable + if (!TryComp(uid, out var flammable)) + return; + + // Make sure the damage delta isn't null + if (args.DamageDelta == null) + return; + + // Check if its' taken any heat damage, and give the value + if (args.DamageDelta.DamageDict.TryGetValue("Heat", out FixedPoint2 value)) + { + // Make sure the value is greater than the threshold + if(value <= component.Threshold) + return; + + // Ignite that sucker + flammable.FireStacks += component.FireStacks; + Ignite(uid, uid, flammable); + } + + + } + public void Resist(EntityUid uid, FlammableComponent? flammable = null) { diff --git a/Content.Server/Damage/Components/IgniteOnHeatDamageComponent.cs b/Content.Server/Damage/Components/IgniteOnHeatDamageComponent.cs new file mode 100644 index 0000000000..81018f539c --- /dev/null +++ b/Content.Server/Damage/Components/IgniteOnHeatDamageComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared.Damage; +using Content.Shared.FixedPoint; + +namespace Content.Server.Damage.Components; + +[RegisterComponent] +public sealed partial class IgniteOnHeatDamageComponent : Component +{ + [DataField("fireStacks")] + public float FireStacks = 1f; + + // The minimum amount of damage taken to apply fire stacks + [DataField("threshold")] + public FixedPoint2 Threshold = 15; +} diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs index a89a101845..cc57c34c47 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Content.Shared.Hands.Components; using Content.Shared.Interaction.Components; using Content.Shared.Silicons.Borgs.Components; diff --git a/Content.Shared/Mind/Components/IsDeadICComponent.cs b/Content.Shared/Mind/Components/IsDeadICComponent.cs new file mode 100644 index 0000000000..d62743d912 --- /dev/null +++ b/Content.Shared/Mind/Components/IsDeadICComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Mind.Components; + +[RegisterComponent] +public sealed partial class IsDeadICComponent : Component +{ +} + + diff --git a/Content.Shared/Mind/IsDeadICSystem.cs b/Content.Shared/Mind/IsDeadICSystem.cs new file mode 100644 index 0000000000..6716f38115 --- /dev/null +++ b/Content.Shared/Mind/IsDeadICSystem.cs @@ -0,0 +1,21 @@ +using Content.Shared.Mind.Components; + +namespace Content.Shared.Mind; + +/// +/// This marks any entity with the component as dead +/// for stuff like objectives & round-end +/// used for nymphs & reformed diona. +/// +public sealed class IsDeadICSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnGetDeadIC); + } + + private void OnGetDeadIC(EntityUid uid, IsDeadICComponent component, ref GetCharactedDeadIcEvent args) + { + args.Dead = true; + } +} diff --git a/Content.Shared/Species/Components/GibActionComponent.cs b/Content.Shared/Species/Components/GibActionComponent.cs new file mode 100644 index 0000000000..bed94f047e --- /dev/null +++ b/Content.Shared/Species/Components/GibActionComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.Mobs; +using Robust.Shared.Prototypes; +using Robust.Shared.GameStates; + +namespace Content.Shared.Species.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class GibActionComponent : Component +{ + /// + /// The action to use. + /// + [DataField("actionPrototype", required: true)] + public EntProtoId ActionPrototype; + + [DataField, AutoNetworkedField] + public EntityUid? ActionEntity; + + /// + /// What mob states the action will appear in + /// + [DataField("allowedStates"), ViewVariables(VVAccess.ReadWrite)] + public List AllowedStates = new(); + + /// + /// The text that appears when attempting to split. + /// + [DataField("popupText")] + public string PopupText = "diona-gib-action-use"; +} diff --git a/Content.Shared/Species/Components/NymphComponent.cs b/Content.Shared/Species/Components/NymphComponent.cs new file mode 100644 index 0000000000..e8fe2f367e --- /dev/null +++ b/Content.Shared/Species/Components/NymphComponent.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.GameStates; + +namespace Content.Shared.Species.Components; +/// +/// This will replace one entity with another entity when it is removed from a body part. +/// Obviously hyper-specific. If you somehow find another use for this, good on you. +/// + +[RegisterComponent, NetworkedComponent] +public sealed partial class NymphComponent : Component +{ + /// + /// The entity to replace the organ with. + /// + [DataField(required: true)] + public EntProtoId EntityPrototype = default!; + + /// + /// Whether to transfer the mind to this new entity. + /// + [DataField] + public bool TransferMind = false; +} diff --git a/Content.Shared/Species/Components/ReformComponent.cs b/Content.Shared/Species/Components/ReformComponent.cs new file mode 100644 index 0000000000..724c9dc330 --- /dev/null +++ b/Content.Shared/Species/Components/ReformComponent.cs @@ -0,0 +1,48 @@ + using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.GameStates; + +namespace Content.Shared.Species.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ReformComponent : Component +{ + /// + /// The action to use. + /// + [DataField(required: true)] + public EntProtoId ActionPrototype = default!; + + [DataField, AutoNetworkedField] + public EntityUid? ActionEntity; + + /// + /// How long it will take to reform + /// + [DataField(required: true)] + public float ReformTime = 0; + + /// + /// Whether or not the entity should start with a cooldown + /// + [DataField] + public bool StartDelayed = true; + + /// + /// Whether or not the entity should be stunned when reforming at all + /// + [DataField] + public bool ShouldStun = true; + + /// + /// The text that appears when attempting to reform + /// + [DataField(required: true)] + public string PopupText; + + /// + /// The mob that our entity will reform into + /// + [DataField(required: true)] + public EntProtoId ReformPrototype { get; private set; } +} diff --git a/Content.Shared/Species/Systems/GibActionSystem.cs b/Content.Shared/Species/Systems/GibActionSystem.cs new file mode 100644 index 0000000000..bd7cb6baff --- /dev/null +++ b/Content.Shared/Species/Systems/GibActionSystem.cs @@ -0,0 +1,61 @@ +using Content.Shared.Species.Components; +using Content.Shared.Actions; +using Content.Shared.Body.Systems; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; +using Content.Shared.Popups; +using Robust.Shared.Prototypes; + + +namespace Content.Shared.Species; + +public sealed partial class GibActionSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMobStateChanged); + SubscribeLocalEvent(OnGibAction); + } + + private void OnMobStateChanged(EntityUid uid, GibActionComponent comp, MobStateChangedEvent args) + { + // When the mob changes state, check if they're dead and give them the action if so. + if (!TryComp(uid, out var mobState)) + return; + + if (!_protoManager.TryIndex(comp.ActionPrototype, out var actionProto)) + return; + + + foreach (var allowedState in comp.AllowedStates) + { + if(allowedState == mobState.CurrentState) + { + // The mob should never have more than 1 state so I don't see this being an issue + _actionsSystem.AddAction(uid, ref comp.ActionEntity, comp.ActionPrototype); + return; + } + } + + // If they aren't given the action, remove it. + _actionsSystem.RemoveAction(uid, comp.ActionEntity); + } + + private void OnGibAction(EntityUid uid, GibActionComponent comp, GibActionEvent args) + { + // When they use the action, gib them. + _popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid); + _bodySystem.GibBody(uid, true); + } + + + + public sealed partial class GibActionEvent : InstantActionEvent { } +} diff --git a/Content.Shared/Species/Systems/NymphSystem.cs b/Content.Shared/Species/Systems/NymphSystem.cs new file mode 100644 index 0000000000..7acbf2e152 --- /dev/null +++ b/Content.Shared/Species/Systems/NymphSystem.cs @@ -0,0 +1,41 @@ +using Content.Shared.Species.Components; +using Content.Shared.Body.Events; +using Content.Shared.Mind; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Shared.Species; + +public sealed partial class NymphSystem : EntitySystem +{ + [Dependency] protected readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRemovedFromPart); + } + + private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, RemovedFromPartInBodyEvent args) + { + if (!_timing.IsFirstTimePredicted) + return; + + if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OldBody)) + return; + + if (!_protoManager.TryIndex(comp.EntityPrototype, out var entityProto)) + return; + + var coords = Transform(uid).Coordinates; + var nymph = EntityManager.SpawnEntity(entityProto.ID, coords); + + if (comp.TransferMind == true && _mindSystem.TryGetMind(args.OldBody, out var mindId, out var mind)) + _mindSystem.TransferTo(mindId, nymph, mind: mind); + + EntityManager.QueueDeleteEntity(uid); + } +} diff --git a/Content.Shared/Species/Systems/ReformSystem.cs b/Content.Shared/Species/Systems/ReformSystem.cs new file mode 100644 index 0000000000..a013a7f886 --- /dev/null +++ b/Content.Shared/Species/Systems/ReformSystem.cs @@ -0,0 +1,108 @@ +using Content.Shared.Species.Components; +using Content.Shared.Actions; +using Content.Shared.DoAfter; +using Content.Shared.Popups; +using Content.Shared.Stunnable; +using Content.Shared.Mind; +using Content.Shared.Humanoid; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; +using Robust.Shared.Serialization.Manager; + +namespace Content.Shared.Species; + +public sealed partial class ReformSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly SharedStunSystem _stunSystem = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly ISerializationManager _serializationManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnCompRemove); + + SubscribeLocalEvent(OnReform); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnMapInit(EntityUid uid, ReformComponent comp, MapInitEvent args) + { + // When the map is initialized, give them the action + if (comp.ActionPrototype != default && !_protoManager.TryIndex(comp.ActionPrototype, out var actionProto)) + return; + + _actionsSystem.AddAction(uid, ref comp.ActionEntity, out var reformAction, comp.ActionPrototype); + + // See if the action should start with a delay, and give it that starting delay if so. + if (comp.StartDelayed && reformAction != null && reformAction.UseDelay != null) + { + var start = _gameTiming.CurTime; + var end = _gameTiming.CurTime + reformAction.UseDelay.Value; + + _actionsSystem.SetCooldown(comp.ActionEntity!.Value, start, end); + } + } + + private void OnCompRemove(EntityUid uid, ReformComponent comp, ComponentShutdown args) + { + _actionsSystem.RemoveAction(uid, comp.ActionEntity); + } + + private void OnReform(EntityUid uid, ReformComponent comp, ReformEvent args) + { + // Stun them when they use the action for the amount of reform time. + if (comp.ShouldStun) + _stunSystem.TryStun(uid, TimeSpan.FromSeconds(comp.ReformTime), true); + _popupSystem.PopupClient(Loc.GetString(comp.PopupText, ("name", uid)), uid, uid); + + // Create a doafter & start it + var doAfter = new DoAfterArgs(EntityManager, uid, comp.ReformTime, new ReformDoAfterEvent(), uid) + { + BreakOnUserMove = true, + BlockDuplicate = true, + BreakOnDamage = true, + CancelDuplicate = true, + RequireCanInteract = false, + }; + + _doAfterSystem.TryStartDoAfter(doAfter); + args.Handled = true; + } + + private void OnDoAfter(EntityUid uid, ReformComponent comp, ReformDoAfterEvent args) + { + if (args.Cancelled || args.Handled || comp.Deleted) + return; + + if (_netMan.IsClient) + return; + + // Spawn a new entity + // This is, to an extent, taken from polymorph. I don't use polymorph for various reasons- most notably that this is permanent. + var child = Spawn(comp.ReformPrototype, Transform(uid).Coordinates); + + // This transfers the mind to the new entity + if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) + _mindSystem.TransferTo(mindId, child, mind: mind); + + // Delete the old entity + QueueDel(uid); + } + + public sealed partial class ReformEvent : InstantActionEvent { } + + [Serializable, NetSerializable] + public sealed partial class ReformDoAfterEvent : SimpleDoAfterEvent { } +} diff --git a/Resources/Audio/Animals/attributions.yml b/Resources/Audio/Animals/attributions.yml index c9c20473c2..c34832a807 100644 --- a/Resources/Audio/Animals/attributions.yml +++ b/Resources/Audio/Animals/attributions.yml @@ -131,4 +131,10 @@ - files: ["dog_bark3.ogg"] license: "CC0-1.0" copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed" - source: "https://freesound.org/people/KFerentchak/sounds/235912/" \ No newline at end of file + source: "https://freesound.org/people/KFerentchak/sounds/235912/" + +- files: ["nymph_chirp.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from ParadiseSS13" + source: "https://github.com/ParadiseSS13/Paradise/commit/a34f1054cef5a44a67fdac3b67b811137c6071dd" + \ No newline at end of file diff --git a/Resources/Audio/Animals/nymph_chirp.ogg b/Resources/Audio/Animals/nymph_chirp.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e0e573d497d649c7ede71d0d75470356e86f46f9 GIT binary patch literal 6270 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 literal 0 HcmV?d00001 diff --git a/Resources/Locale/en-US/actions/actions/diona.ftl b/Resources/Locale/en-US/actions/actions/diona.ftl new file mode 100644 index 0000000000..3745e6fe49 --- /dev/null +++ b/Resources/Locale/en-US/actions/actions/diona.ftl @@ -0,0 +1,3 @@ +diona-gib-action-use = {$name} splits apart in an instant! + +diona-reform-attempt = {$name} attempts to reform! \ No newline at end of file diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index e18d85df2e..bb56233ff1 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -31,6 +31,7 @@ petting-success-bear = You reluctantly pet {THE($target)} on {POSS-ADJ($target)} petting-success-slimes = You pet {THE($target)} on {POSS-ADJ($target)} mucous surface. petting-success-snake = You pet {THE($target)} on {POSS-ADJ($target)} scaly large head. petting-success-monkey = You pet {THE($target)} on {POSS-ADJ($target)} mischevious little head. +petting-success-nymph = You pet {THE($target)} on {POSS-ADJ($target)} wooden little head. petting-failure-generic = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} aloof towards you. @@ -51,6 +52,7 @@ petting-failure-dragon = You raise your hand, but as {THE($target)} roars, you d petting-failure-hamster = You reach out to pet {THE($target)}, but {SUBJECT($target)} attempts to bite your finger and only your quick reflexes save you from an almost fatal injury. petting-failure-bear = You reach out to pet {THE($target)}, but {SUBJECT($target)} growls, making you think twice. petting-failure-monkey = You reach out to pet {THE($target)}, but {SUBJECT($target)} almost bites your fingers! +petting-failure-nymph = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} moves their branches away. petting-failure-shadow = You're trying to pet {THE($target)}, but your hand passes through the cold darkness of his body. ## Petting silicons diff --git a/Resources/Prototypes/Actions/diona.yml b/Resources/Prototypes/Actions/diona.yml new file mode 100644 index 0000000000..ac65d6861d --- /dev/null +++ b/Resources/Prototypes/Actions/diona.yml @@ -0,0 +1,21 @@ +- type: entity + id: DionaGibAction + name: Gib Yourself! + description: Split apart into 3 nymphs. + noSpawn: true + components: + - type: InstantAction + icon: Mobs/Species/Diona/organs.rsi/brain.png + event: !type:GibActionEvent {} + checkCanInteract: false + +- type: entity + id: DionaReformAction + name: Reform + description: Reform back into a whole Diona. + noSpawn: true + components: + - type: InstantAction + icon: Mobs/Species/Diona/parts.rsi/full.png + event: !type:ReformEvent {} + useDelay: 300 # Once every 10 minutes. Keep them dead for a fair bit before reforming diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml index 282bb224d8..23df396dd1 100644 --- a/Resources/Prototypes/Body/Organs/diona.yml +++ b/Resources/Prototypes/Body/Organs/diona.yml @@ -48,18 +48,6 @@ reagents: - ReagentId: UncookedAnimalProteins Quantity: 5 - - type: Brain - - type: InputMover - - type: Examiner - - type: Lung #lungs in they head. why they there tho? - - type: Metabolizer - removeEmpty: true - solutionOnBody: false - solution: "Lung" - metabolizerTypes: [ Plant ] - groups: - - id: Gas - rateModifier: 100.0 - type: entity id: OrganDionaEyes @@ -102,3 +90,104 @@ - id: Narcotic - id: Alcohol rateModifier: 0.1 + +- type: entity + id: OrganDionaLungs + parent: BaseDionaOrgan + name: lungs + description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier." + components: + - type: Sprite + sprite: Mobs/Species/Human/organs.rsi + layers: + - state: lung-l + - state: lung-r + - type: Lung + - type: Metabolizer + removeEmpty: true + solutionOnBody: false + solution: "Lung" + metabolizerTypes: [ Plant ] + groups: + - id: Gas + rateModifier: 100.0 + - type: SolutionContainerManager + solutions: + organ: + maxVol: 10 + reagents: + - ReagentId: Nutriment + Quantity: 10 + Lung: + maxVol: 100 + canReact: False + +# Organs that turn into nymphs on removal +- type: entity + id: OrganDionaBrainNymph + parent: OrganDionaBrain + noSpawn: true + name: brain + description: "The source of incredible, unending intelligence. Honk." + components: + - type: Brain + - type: Nymph # This will make the organs turn into a nymph when they're removed. + entityPrototype: OrganDionaNymphBrain + transferMind: true + +- type: entity + id: OrganDionaStomachNymph + parent: OrganDionaStomach + noSpawn: true + name: stomach + description: "Gross. This is hard to stomach." + components: + - type: Nymph + entityPrototype: OrganDionaNymphStomach + +- type: entity + id: OrganDionaLungsNymph + parent: OrganDionaLungs + noSpawn: true + name: lungs + description: "Filters oxygen from an atmosphere, which is then sent into the bloodstream to be used as an electron carrier." + components: + - type: Nymph + entityPrototype: OrganDionaNymphLungs + +# Nymphs that the organs will turn into +- type: entity + id: OrganDionaNymphBrain + parent: MobDionaNymph + noSpawn: true + name: diona nymph + suffix: Brain + description: Contains the brain of a formerly fully-formed Diona. Killing this would kill the Diona forever. You monster. + components: + - type: IsDeadIC + - type: Body + prototype: AnimalNymphBrain + +- type: entity + id: OrganDionaNymphStomach + parent: MobDionaNymph + noSpawn: true + name: diona nymph + suffix: Stomach + description: Contains the stomach of a formerly fully-formed Diona. It doesn't taste any better for it. + components: + - type: IsDeadIC + - type: Body + prototype: AnimalNymphStomach + +- type: entity + id: OrganDionaNymphLungs + parent: MobDionaNymph + noSpawn: true + name: diona nymph + suffix: Lungs + description: Contains the lungs of a formerly fully-formed Diona. Breathtaking. + components: + - type: IsDeadIC + - type: Body + prototype: AnimalNymphLungs diff --git a/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml b/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml new file mode 100644 index 0000000000..21aafe291c --- /dev/null +++ b/Resources/Prototypes/Body/Prototypes/Animal/nymph.yml @@ -0,0 +1,66 @@ +- type: body + id: AnimalNymphBrain + name: "nymph" + root: torso + slots: + torso: + part: TorsoAnimal + connections: + - legs + organs: + brain: OrganDionaBrain + lungs: OrganAnimalLungs + stomach: OrganAnimalStomach + liver: OrganAnimalLiver + heart: OrganAnimalHeart + kidneys: OrganAnimalKidneys + legs: + part: LegsAnimal + connections: + - feet + feet: + part: FeetAnimal + +- type: body + id: AnimalNymphLungs + name: "nymph" + root: torso + slots: + torso: + part: TorsoAnimal + connections: + - legs + organs: + lungs: OrganDionaLungs + stomach: OrganAnimalStomach + liver: OrganAnimalLiver + heart: OrganAnimalHeart + kidneys: OrganAnimalKidneys + legs: + part: LegsAnimal + connections: + - feet + feet: + part: FeetAnimal + +- type: body + id: AnimalNymphStomach + name: "nymph" + root: torso + slots: + torso: + part: TorsoAnimal + connections: + - legs + organs: + lungs: OrganAnimalLungs + stomach: OrganDionaStomach + liver: OrganAnimalLiver + heart: OrganAnimalHeart + kidneys: OrganAnimalKidneys + legs: + part: LegsAnimal + connections: + - feet + feet: + part: FeetAnimal \ No newline at end of file diff --git a/Resources/Prototypes/Body/Prototypes/diona.yml b/Resources/Prototypes/Body/Prototypes/diona.yml index f364d0f800..12ca203988 100644 --- a/Resources/Prototypes/Body/Prototypes/diona.yml +++ b/Resources/Prototypes/Body/Prototypes/diona.yml @@ -8,8 +8,7 @@ connections: - torso organs: - brain: OrganDionaBrain - eyes: OrganDionaEyes + brain: OrganDionaBrainNymph torso: part: TorsoDiona connections: @@ -18,7 +17,8 @@ - right leg - left leg organs: - stomach: OrganDionaStomach + stomach: OrganDionaStomachNymph + lungs: OrganDionaLungsNymph right arm: part: RightArmDiona connections: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 1251884965..855a2d89c6 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -3099,3 +3099,77 @@ factions: - Passive +- type: entity + name: diona nymph + parent: SimpleMobBase + id: MobDionaNymph + description: It's like a cat, only.... branch-ier. + components: + - type: Sprite + drawdepth: Mobs + layers: + - map: ["enum.DamageStateVisualLayers.Base"] + state: nymph + sprite: Mobs/Animals/nymph.rsi + - type: Physics + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 100 # High, because wood is heavy. + mask: + - MobMask + layer: + - MobLayer + - type: Inventory + speciesId: cat + templateId: pet + - type: InventorySlots + - type: Strippable + - type: Bloodstream + bloodReagent: Water + bloodMaxVolume: 60 + - type: UserInterface + interfaces: + - key: enum.StrippingUiKey.Key + type: StrippableBoundUserInterface + - type: DamageStateVisuals + states: + Alive: + Base: nymph + Critical: + Base: nymph_sleep + Dead: + Base: nymph_dead + - type: Butcherable + spawned: + - id: MaterialWoodPlank1 + amount: 2 + - type: InteractionPopup + successChance: 0.7 + interactSuccessString: petting-success-nymph + interactFailureString: petting-failure-nymph + interactSuccessSound: + path: /Audio/Animals/nymph_chirp.ogg + - type: MobThresholds + thresholds: + 0: Alive + 30: Critical + 60: Dead + - type: MovementSpeedModifier + baseWalkSpeed : 2.5 + baseSprintSpeed : 4.5 + - type: Grammar + attributes: + gender: epicene + - type: Speech + - type: Tag + tags: + - VimPilot + - type: Reform + actionPrototype: DionaReformAction + reformTime: 10 + popupText: diona-reform-attempt + reformPrototype: MobDionaReformed diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index 4e7bd7e0c9..4153250bbf 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -11,3 +11,13 @@ damageRecovery: types: Asphyxiation: -1.0 + +# Reformed Diona +- type: entity + parent: MobDiona + noSpawn: true + id: MobDionaReformed + name: Reformed Diona + components: + - type: IsDeadIC + - type: RandomHumanoidAppearance \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml index 6371fb74eb..7f726e2f2c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml @@ -94,6 +94,13 @@ - type: BodyEmotes soundsId: DionaBodyEmotes - type: IgnoreKudzu + - type: IgniteOnHeatDamage + fireStacks: 1 + threshold: 12 + - type: GibAction + actionPrototype: DionaGibAction + allowedStates: + - Dead - type: entity parent: BaseSpeciesDummy diff --git a/Resources/Textures/Mobs/Animals/nymph.rsi/icon.png b/Resources/Textures/Mobs/Animals/nymph.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f1b6a7923075b987efa37b2f7cfabef4c49d09dd GIT binary patch literal 611 zcmV-p0-XJcP)*Ap64!l>oaW}{-l}qIxzF;xr}y+czw@5= zepKO~7d1J|FVA3cK7sR# z8~Xuh-Wv3aTxqF9Y<37I>9`h$kyzRVwn_ltqB7syxpEbnNApmV7oFh{)=!dHS=z^7 z3?e??zZQfy1(4;G_cX_55PEYe`q#fI-Yium=mv_`MVJOV3P-@$=jmLivr*xytU+G zmC`qzG^S`y6>Dw^;I65_=s-8q{0l^X9Qx98_dM_VfEzjG4O!KN#>@wPBGU@+{3L|& z8t?P|zOZOG?wsaCs=6V>}l!YSa xv1z~i8Y&221w$E|)2vy|#w7#TDF?s-_ymH4ANCr&imm_v002ovPDHLkV1gH$8K?jN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Animals/nymph.rsi/meta.json b/Resources/Textures/Mobs/Animals/nymph.rsi/meta.json new file mode 100644 index 0000000000..c6bb6e0ac4 --- /dev/null +++ b/Resources/Textures/Mobs/Animals/nymph.rsi/meta.json @@ -0,0 +1,63 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/ParadiseSS13/Paradise/commit/f367d7de199969a5fb5054de44faa5618092f487", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "nymph", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "nymph_dead" + }, + { + "name": "nymph_sleep", + "directions": 4 + }, + { + "name": "icon" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Animals/nymph.rsi/nymph.png b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph.png new file mode 100644 index 0000000000000000000000000000000000000000..fe79c893d1496a32576414a61219f289877dcaed GIT binary patch literal 3891 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_sleep.png b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_sleep.png new file mode 100644 index 0000000000000000000000000000000000000000..4e2055d74adad40e2daf239d3420a573044d114b GIT binary patch literal 1306 zcmV+#1?BpQP)?W~f8_AYp6H>5nBB-Gy6z3F34~0N4 zz6A=s7efAp_K^Gwq0oCEkee@sLJu{xJ=7#70VkDe|AOgFN$ zo84^>Gas1Qo!xzJ-ZyV%SN`4z42LBEhQks7!(j=4;jje2a99FhI4l7$9F_pT4}AOe z=g#TWIBxv#YfSpSzxIVwY3$?2JNIIU7-9SOMF5@C3EOX$@{aV2bGeR)p!?@v^Y8$P zv1B0so(N#Dx0eesIwaWU&dm0%m!5C+`t|z}68hPruPc{7#m_4b6$!)cKMtMbSa?SLqlf z2@HPw#Q`>-msR=~OV!>oaN;w_WRq62VLm@SItI z?stJ7cqV|amZdLq&WVrWsQpn!YI5>lEx|qD_Hr~ILiEoKmVpWp1cTSlBl!>#EdNr9 zUHxiaEi|U$-JdpM`WGRuBSP@)qWhOuvwq#LP2ax-7_@s(_zw}bfBS0?hQks7!(j=4 z;jje2a99FhI4l7$9F_nW4od(Gha~`p!x9jtF$$A%EYfvQxm=gQ1z}3?fe8>TP*ho- zE9pEnu7pY!FX+V#e!ypGL!@{fyM6ud{}kl_s27yC8xZxFB4%o0Oesl!J$d%Qw)re| z2TJkO04t58@mdX*YWXSe~sJ{r6P2NEDDNJA`2pz~}hiF3J5I&u(2=Md?Ild4EUTBkevVSKPi z{U5VnhlLrMuiv+-NYx!h1Yf%>kzol93F4T&EWx2mKuD0yjAbZX-|>Z0>Nq`n^1Wh- zR(&$i=I4eir+A;jj8^?69*^vzwOa1oTi@O3jeVGHPkVrF=)3Ee9hRfal{>XM$F)H= zzkdFi*28=