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 0000000000..e0e573d497 Binary files /dev/null and b/Resources/Audio/Animals/nymph_chirp.ogg differ 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 0000000000..f1b6a79230 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/nymph.rsi/icon.png differ 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 0000000000..fe79c893d1 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph.png differ diff --git a/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_dead.png b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_dead.png new file mode 100644 index 0000000000..c3371bf949 Binary files /dev/null and b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_dead.png differ 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 0000000000..4e2055d74a Binary files /dev/null and b/Resources/Textures/Mobs/Animals/nymph.rsi/nymph_sleep.png differ