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
This commit is contained in:
LankLTE
2024-02-16 18:54:44 -08:00
committed by GitHub
parent 699ee6e0c8
commit 407d4aed58
27 changed files with 743 additions and 17 deletions

View File

@@ -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<IgniteOnMeleeHitComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<ExtinguishOnInteractComponent, ActivateInWorldEvent>(OnExtinguishActivateInWorld);
SubscribeLocalEvent<IgniteOnHeatDamageComponent, DamageChangedEvent>(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<FlammableComponent>(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)
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -0,0 +1,8 @@
namespace Content.Shared.Mind.Components;
[RegisterComponent]
public sealed partial class IsDeadICComponent : Component
{
}

View File

@@ -0,0 +1,21 @@
using Content.Shared.Mind.Components;
namespace Content.Shared.Mind;
/// <summary>
/// This marks any entity with the component as dead
/// for stuff like objectives & round-end
/// used for nymphs & reformed diona.
/// </summary>
public sealed class IsDeadICSystem : EntitySystem
{
public override void Initialize()
{
SubscribeLocalEvent<IsDeadICComponent, GetCharactedDeadIcEvent>(OnGetDeadIC);
}
private void OnGetDeadIC(EntityUid uid, IsDeadICComponent component, ref GetCharactedDeadIcEvent args)
{
args.Dead = true;
}
}

View File

@@ -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
{
/// <summary>
/// The action to use.
/// </summary>
[DataField("actionPrototype", required: true)]
public EntProtoId ActionPrototype;
[DataField, AutoNetworkedField]
public EntityUid? ActionEntity;
/// <summary>
/// What mob states the action will appear in
/// </summary>
[DataField("allowedStates"), ViewVariables(VVAccess.ReadWrite)]
public List<MobState> AllowedStates = new();
/// <summary>
/// The text that appears when attempting to split.
/// </summary>
[DataField("popupText")]
public string PopupText = "diona-gib-action-use";
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Prototypes;
using Robust.Shared.GameStates;
namespace Content.Shared.Species.Components;
/// <summary>
/// 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.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class NymphComponent : Component
{
/// <summary>
/// The entity to replace the organ with.
/// </summary>
[DataField(required: true)]
public EntProtoId EntityPrototype = default!;
/// <summary>
/// Whether to transfer the mind to this new entity.
/// </summary>
[DataField]
public bool TransferMind = false;
}

View File

@@ -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
{
/// <summary>
/// The action to use.
/// </summary>
[DataField(required: true)]
public EntProtoId ActionPrototype = default!;
[DataField, AutoNetworkedField]
public EntityUid? ActionEntity;
/// <summary>
/// How long it will take to reform
/// </summary>
[DataField(required: true)]
public float ReformTime = 0;
/// <summary>
/// Whether or not the entity should start with a cooldown
/// </summary>
[DataField]
public bool StartDelayed = true;
/// <summary>
/// Whether or not the entity should be stunned when reforming at all
/// </summary>
[DataField]
public bool ShouldStun = true;
/// <summary>
/// The text that appears when attempting to reform
/// </summary>
[DataField(required: true)]
public string PopupText;
/// <summary>
/// The mob that our entity will reform into
/// </summary>
[DataField(required: true)]
public EntProtoId ReformPrototype { get; private set; }
}

View File

@@ -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<GibActionComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<GibActionComponent, GibActionEvent>(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<MobStateComponent>(uid, out var mobState))
return;
if (!_protoManager.TryIndex<EntityPrototype>(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 { }
}

View File

@@ -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<NymphComponent, RemovedFromPartInBodyEvent>(OnRemovedFromPart);
}
private void OnRemovedFromPart(EntityUid uid, NymphComponent comp, RemovedFromPartInBodyEvent args)
{
if (!_timing.IsFirstTimePredicted)
return;
if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OldBody))
return;
if (!_protoManager.TryIndex<EntityPrototype>(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);
}
}

View File

@@ -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<ReformComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<ReformComponent, ComponentShutdown>(OnCompRemove);
SubscribeLocalEvent<ReformComponent, ReformEvent>(OnReform);
SubscribeLocalEvent<ReformComponent, ReformDoAfterEvent>(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<EntityPrototype>(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 { }
}

View File

@@ -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/"
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"

Binary file not shown.

View File

@@ -0,0 +1,3 @@
diona-gib-action-use = {$name} splits apart in an instant!
diona-reform-attempt = {$name} attempts to reform!

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

View File

@@ -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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB