Change dwarves to use displacement maps instead of sprite scaling (#43816)

* ach, ye initial commit

* Review changes...?

* Change parentage

* Widen the dwarf sprite

* Widen the dwarf sprite

* Solve the murder at the Portermeister Estate

* The rest of the fucking owl

* Fix female displacement, fix the displacement error

* Review changes

* Review fixes

* IPrototypeManager to ProtoMan

* Review changes
This commit is contained in:
SlamBamActionman 2026-07-06 00:17:17 +02:00 • committed by GitHub
parent 22d3286b1b
commit 24485c39ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 560 additions and 38 deletions

View file

@ -1,3 +1,4 @@
using Content.Client.DisplacementMap;
using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Effects;
using Content.Shared.Humanoid;
@ -8,6 +9,9 @@ namespace Content.Client.Anomaly.Effects;
public sealed partial class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
{
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private DisplacementMapSystem _displacement = default!;
[Dependency] private EntityQuery<InnerBodyAnomalyVisualsComponent> _visualsQuery = default!;
public override void Initialize()
{
@ -37,6 +41,22 @@ public sealed partial class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomal
_sprite.LayerSetVisible((ent.Owner, sprite), index, true);
sprite.LayerSetShader(index, "unshaded");
if (_visualsQuery.TryGetComponent(ent, out var visuals) && visuals.Displacement != null)
{
if (ProtoMan.Resolve(visuals.Displacement, out var displacement))
{
_displacement.TryAddDisplacement(displacement.Displacement,
(ent.Owner, sprite),
index,
ent.Comp.LayerMap,
out _);
}
else
{
_displacement.EnsureDisplacementIsNotOnSprite((ent.Owner, sprite), ent.Comp.LayerMap);
}
}
}
private void OnCompShutdown(Entity<InnerBodyAnomalyComponent> ent, ref ComponentShutdown args)
@ -46,5 +66,7 @@ public sealed partial class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomal
var index = _sprite.LayerMapGet((ent.Owner, sprite), ent.Comp.LayerMap);
_sprite.LayerSetVisible((ent.Owner, sprite), index, false);
_displacement.EnsureDisplacementIsNotOnSprite((ent.Owner, sprite), ent.Comp.LayerMap);
}
}

View file

@ -1,3 +1,6 @@
using Content.Shared.DisplacementMap;
using Robust.Shared.Prototypes;
namespace Content.Client.Atmos.Components;
/// <summary>
@ -39,4 +42,10 @@ public sealed partial class FireVisualsComponent : Component
/// the burning entity as entities don't support having multiple point-lights.
/// </summary>
public EntityUid? LightEntity;
/// <summary>
/// Tracks the currently applied displacement, so that only new changes update the layer.
/// </summary>
[DataField]
public ProtoId<DisplacementDataPrototype>? CurrentDisplacement;
}

View file

@ -1,5 +1,7 @@
using Content.Client.Atmos.Components;
using Content.Client.DisplacementMap;
using Content.Shared.Atmos;
using Content.Shared.DisplacementMap;
using Robust.Client.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Utility;
@ -12,6 +14,7 @@ namespace Content.Client.Atmos.EntitySystems;
public sealed partial class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent>
{
[Dependency] private PointLightSystem _lights = default!;
[Dependency] private DisplacementMapSystem _displacement = default!;
public override void Initialize()
{
@ -65,6 +68,7 @@ public sealed partial class FireVisualizerSystem : VisualizerSystem<FireVisualsC
AppearanceSystem.TryGetData<bool>(uid, FireVisuals.OnFire, out var onFire, appearance);
AppearanceSystem.TryGetData<float>(uid, FireVisuals.FireStacks, out var fireStacks, appearance);
AppearanceSystem.TryGetData<string?>(uid, FireVisuals.FireDisplacement, out var fireDisplacement, appearance);
SpriteSystem.LayerSetVisible((uid, sprite), index, onFire);
if (!onFire)
@ -83,6 +87,16 @@ public sealed partial class FireVisualizerSystem : VisualizerSystem<FireVisualsC
else
SpriteSystem.LayerSetRsiState((uid, sprite), index, component.NormalState);
if (component.CurrentDisplacement != fireDisplacement)
{
if (fireDisplacement != null && ProtoMan.Resolve<DisplacementDataPrototype>(fireDisplacement, out var displacementProto))
_displacement.TryAddDisplacement(displacementProto.Displacement, (uid, sprite), index, FireVisualLayers.Fire, out _);
else
_displacement.EnsureDisplacementIsNotOnSprite((uid, sprite), FireVisualLayers.Fire);
component.CurrentDisplacement = fireDisplacement;
}
component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default));
var light = EnsureComp<PointLightComponent>(component.LightEntity.Value);

View file

@ -2,6 +2,7 @@ using System.Linq;
using Content.Client.DisplacementMap;
using Content.Shared.Body;
using Content.Shared.CCVar;
using Content.Shared.DisplacementMap;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid;
using Robust.Client.GameObjects;
@ -73,6 +74,16 @@ public sealed partial class VisualBodySystem : SharedVisualBodySystem
return;
_sprite.LayerSetData(target, index, ent.Comp.Data);
var displacement = ent.Comp.Displacement;
if (displacement != null && ProtoMan.Resolve(displacement, out var displacementProto))
{
_displacement.TryAddDisplacement(displacementProto.Displacement,
(target, Comp<SpriteComponent>(target)),
index,
ent.Comp.Layer,
out _);
}
}
private void RemoveVisual(Entity<VisualOrganComponent> ent, EntityUid target)
@ -81,6 +92,8 @@ public sealed partial class VisualBodySystem : SharedVisualBodySystem
return;
_sprite.LayerSetRsiState(target, index, RSI.StateId.Invalid);
_displacement.EnsureDisplacementIsNotOnSprite((target, Comp<SpriteComponent>(target)), ent.Comp.Layer);
}
private void OnMarkingsGotInserted(Entity<VisualOrganMarkingsComponent> ent, ref OrganGotInsertedEvent args)

View file

@ -1,4 +1,6 @@
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Prototypes;
using Content.Shared.DisplacementMap;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
@ -117,6 +119,13 @@ public sealed partial class DamageVisualsComponent : Component
/// </summary>
[DataField("damageOverlay")] public DamageVisualizerSprite? DamageOverlay;
/// <summary>
/// Applies a displacement map to the damage visuals.
/// Is set via <see cref="DamageableComponent.Displacement"/>.
/// </summary>
[DataField]
public DisplacementData? Displacement;
public readonly List<Enum> TargetLayerMapKeys = new();
public bool Disabled = false;
public bool Valid = true;

View file

@ -1,8 +1,10 @@
using System.Linq;
using Content.Client.DisplacementMap;
using Content.Shared.Damage;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.DisplacementMap;
using Content.Shared.FixedPoint;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
@ -29,6 +31,7 @@ namespace Content.Client.Damage;
public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponent>
{
[Dependency] private DamageableSystem _damageable = default!;
[Dependency] private DisplacementMapSystem _displacement = default!;
public override void Initialize()
{
@ -326,10 +329,14 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
/// </summary>
private void AddDamageLayerToSprite(Entity<SpriteComponent?> spriteEnt, DamageVisualizerSprite sprite, string state, string mapKey, int? index = null)
{
if (!Resolve(spriteEnt, ref spriteEnt.Comp))
return;
var newLayer = SpriteSystem.AddLayer(
spriteEnt,
new SpriteSpecifier.Rsi(
new(sprite.Sprite), state
new(sprite.Sprite),
state
),
index
);
@ -354,6 +361,12 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
if (damageVisComp.Disabled)
return;
if (AppearanceSystem.TryGetData<string>(uid, DamageVisualizerKeys.Displacement, out var displacement, args.Component) &&
ProtoMan.Resolve<DisplacementDataPrototype>(displacement, out var displacementProto))
damageVisComp.Displacement = displacementProto.Displacement;
else
damageVisComp.Displacement = null;
HandleDamage(uid, args.Component, damageVisComp);
}
@ -503,7 +516,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
else
{
UpdateOverlay((entity, spriteComponent), threshold);
UpdateOverlay((entity, spriteComponent), threshold, damageVisComp.Displacement);
}
}
@ -542,7 +555,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
}
else
{
UpdateOverlay((entity, spriteComponent, damageVisComp), damageGroup, threshold);
UpdateOverlay((entity, spriteComponent, damageVisComp), damageGroup, threshold, entity.Comp3.Displacement);
}
}
@ -614,7 +627,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
UpdateDamageLayerState(spriteEnt,
spriteLayer,
$"{layerState}",
threshold);
threshold,
$"{layerMapKey}trackDamage",
damageVisComp.Displacement);
}
}
else if (!damageVisComp.Overlay)
@ -625,7 +640,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
UpdateDamageLayerState(spriteEnt,
spriteLayer,
$"{layerState}",
threshold);
threshold,
$"{layerMapKey}",
damageVisComp.Displacement);
}
}
@ -648,7 +665,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
(entity, spriteComponent),
spriteLayer,
$"{layerState}_{damageGroup}",
threshold);
threshold,
$"{layerMapKey}{damageGroup}",
entity.Comp2.Displacement);
}
}
else if (!damageVisComp.Overlay)
@ -660,27 +679,31 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
(entity, spriteComponent),
spriteLayer,
$"{layerState}_{damageGroup}",
threshold);
threshold,
$"{layerMapKey}",
entity.Comp2.Displacement);
}
}
/// <summary>
/// Updates an overlay that is tracking all damage.
/// </summary>
private void UpdateOverlay(Entity<SpriteComponent> spriteEnt, FixedPoint2 threshold)
private void UpdateOverlay(Entity<SpriteComponent> spriteEnt, FixedPoint2 threshold, DisplacementData? displacement = null)
{
SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), $"DamageOverlay", out var spriteLayer, false);
UpdateDamageLayerState(spriteEnt,
spriteLayer,
$"DamageOverlay",
threshold);
threshold,
$"DamageOverlay",
displacement);
}
/// <summary>
/// Updates an overlay based on damage group.
/// </summary>
private void UpdateOverlay(Entity<SpriteComponent, DamageVisualsComponent> entity, string damageGroup, FixedPoint2 threshold)
private void UpdateOverlay(Entity<SpriteComponent, DamageVisualsComponent> entity, string damageGroup, FixedPoint2 threshold, DisplacementData? displacement = null)
{
var spriteComponent = entity.Comp1;
var damageVisComp = entity.Comp2;
@ -695,7 +718,9 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
(entity, spriteComponent),
spriteLayer,
$"DamageOverlay_{damageGroup}",
threshold);
threshold,
$"DamageOverlay{damageGroup}",
displacement);
}
}
}
@ -706,7 +731,7 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
/// function calls it), and what threshold
/// was passed into it.
/// </summary>
private void UpdateDamageLayerState(Entity<SpriteComponent> spriteEnt, int spriteLayer, string statePrefix, FixedPoint2 threshold)
private void UpdateDamageLayerState(Entity<SpriteComponent> spriteEnt, int spriteLayer, string statePrefix, FixedPoint2 threshold, string layerKey, DisplacementData? displacement)
{
if (threshold == 0)
{
@ -719,6 +744,14 @@ public sealed partial class DamageVisualsSystem : VisualizerSystem<DamageVisuals
SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, true);
}
SpriteSystem.LayerSetRsiState(spriteEnt.AsNullable(), spriteLayer, $"{statePrefix}_{threshold}");
if (displacement != null)
{
_displacement.TryAddDisplacement(displacement, spriteEnt, spriteLayer, layerKey, out _);
}
else
{
_displacement.EnsureDisplacementIsNotOnSprite(spriteEnt, layerKey);
}
}
}
}

View file

@ -41,7 +41,8 @@ public sealed partial class DisplacementMapSystem : EntitySystem
if (displacementKey is null)
return false;
EnsureDisplacementIsNotOnSprite(sprite, key);
if (EnsureDisplacementIsNotOnSprite(sprite, key))
index--;
if (data.ShaderOverride is not null)
{
@ -91,10 +92,21 @@ public sealed partial class DisplacementMapSystem : EntitySystem
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
// This previously assigned a string reading "this is impossible" if key.ToString eval'd to false.
// However, for the sake of sanity, we've changed this to assert non-null - !.
// If this throws an error, we're not sorry. Nanotrasen thanks you for your service fixing this bug.
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString()!;
if (key is Enum)
{
// We are doing this enum-to-string conversion here because CopyToShaderParameters.LayerKey only takes a string,
// but LayerMap keys are stored as objects, and therefore can take enums.
// There is a key parser in SpriteComponent but it requires the qualified (i.e. full) enum name.
// It feels like CopyToShaderParameters should be able to just take objects, but until then:
displacementLayer.CopyToShaderParameters!.LayerKey = $"enum.{key.GetType().Name}.{key}";
}
else
{
// This previously assigned a string reading "this is impossible" if key.ToString eval'd to false.
// However, for the sake of sanity, we've changed this to assert non-null - !.
// If this throws an error, we're not sorry. Nanotrasen thanks you for your service fixing this bug.
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString()!;
}
_sprite.AddLayer(sprite.AsNullable(), displacementLayer, index);
_sprite.LayerMapSet(sprite.AsNullable(), displacementKey, index);
@ -107,13 +119,13 @@ public sealed partial class DisplacementMapSystem : EntitySystem
/// </summary>
/// <param name="sprite">The sprite to remove the displacement layer from.</param>
/// <param name="key">The key of the layer that is referenced by the displacement layer we want to remove.</param>
/// <param name="logMissing">Whether to report an error if the displacement map isn't on the sprite.</param>
public void EnsureDisplacementIsNotOnSprite(Entity<SpriteComponent> sprite, object key)
/// <returns>Returns true if the displacement existed and was removed.</returns>
public bool EnsureDisplacementIsNotOnSprite(Entity<SpriteComponent> sprite, object key)
{
var displacementLayerKey = BuildDisplacementLayerKey(key);
if (displacementLayerKey is null)
return;
return false;
_sprite.RemoveLayer(sprite.AsNullable(), displacementLayerKey, false);
return _sprite.RemoveLayer(sprite.AsNullable(), displacementLayerKey, false);
}
}

View file

@ -1,6 +1,8 @@
using Content.Client.DisplacementMap;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.Client.Nutrition.EntitySystems;
@ -8,6 +10,7 @@ public sealed partial class CreamPieSystem : SharedCreamPieSystem
{
[Dependency] private SpriteSystem _sprite = default!;
[Dependency] private AppearanceSystem _appearance = default!;
[Dependency] private DisplacementMapSystem _displacement = default!;
public override void Initialize()
{
@ -27,6 +30,7 @@ public sealed partial class CreamPieSystem : SharedCreamPieSystem
private void OnComponentShutdown(Entity<CreamPiedComponent> ent, ref ComponentShutdown args)
{
_sprite.RemoveLayer(ent.Owner, CreamPiedVisualLayer.Key);
_displacement.EnsureDisplacementIsNotOnSprite((ent, Comp<SpriteComponent>(ent)), CreamPiedVisualLayer.Key);
}
private void OnAppearanceChange(Entity<CreamPiedComponent> ent, ref AppearanceChangeEvent args)
@ -54,6 +58,7 @@ public sealed partial class CreamPieSystem : SharedCreamPieSystem
if (creamPied.Sprite == null)
{
_sprite.RemoveLayer((ent.Owner, sprite), CreamPiedVisualLayer.Key);
_displacement.EnsureDisplacementIsNotOnSprite((ent.Owner, sprite), CreamPiedVisualLayer.Key);
return;
}
@ -62,5 +67,10 @@ public sealed partial class CreamPieSystem : SharedCreamPieSystem
_appearance.TryGetData<bool>(ent.Owner, CreamPiedVisuals.Creamed, out var isCreamPied, appearance);
_sprite.LayerSetSprite((ent.Owner, sprite), index, creamPied.Sprite);
_sprite.LayerSetVisible((ent.Owner, sprite), index, isCreamPied);
if (ProtoMan.Resolve(ent.Comp1.Displacement, out var displacementProto))
{
_displacement.TryAddDisplacement(displacementProto.Displacement, (ent.Owner, sprite), index, CreamPiedVisualLayer.Key, out _);
}
}
}

View file

@ -269,6 +269,11 @@ namespace Content.Server.Atmos.EntitySystems
_appearance.SetData(uid, FireVisuals.OnFire, flammable.OnFire, appearance);
_appearance.SetData(uid, FireVisuals.FireStacks, flammable.FireStacks, appearance);
if (flammable.Displacement != null)
_appearance.SetData(uid, FireVisuals.FireDisplacement, flammable.Displacement.Value.Id, appearance);
else
_appearance.RemoveData(uid, FireVisuals.FireDisplacement);
// Also enable toggleable-light visuals
// This is intended so that matches & candles can re-use code for un-shaded layers on in-hand sprites.
// However, this could cause conflicts if something is ACTUALLY both a toggleable light and flammable.

View file

@ -0,0 +1,18 @@
using Content.Shared.DisplacementMap;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Anomaly.Components;
/// <summary>
/// Complementary visuals component to <see cref="InnerBodyAnomalyComponent"/>.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class InnerBodyAnomalyVisualsComponent : Component
{
/// <summary>
/// If set, applies a displacement map to the anomaly sprites.
/// </summary>
[DataField, AutoNetworkedField]
public ProtoId<DisplacementDataPrototype>? Displacement;
}

View file

@ -1,5 +1,6 @@
using Content.Shared.Alert;
using Content.Shared.Damage;
using Content.Shared.DisplacementMap;
using Robust.Shared.GameStates;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Prototypes;
@ -109,5 +110,11 @@ namespace Content.Shared.Atmos.Components
[DataField]
public ProtoId<AlertPrototype> FireAlert = "Fire";
/// <summary>
/// If set, applies the displacement map associated with the <see cref="DisplacementDataPrototype"/>.
/// </summary>
[DataField]
public ProtoId<DisplacementDataPrototype>? Displacement;
}
}

View file

@ -7,5 +7,6 @@ namespace Content.Shared.Atmos
{
OnFire,
FireStacks,
FireDisplacement,
}
}

View file

@ -1,5 +1,7 @@
using Content.Shared.DisplacementMap;
using Content.Shared.Humanoid;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Body;
@ -35,6 +37,12 @@ public sealed partial class VisualOrganComponent : Component
/// </summary>
[DataField, AutoNetworkedField]
public OrganProfileData Profile = new();
/// <summary>
/// Displacement data prototype applied to the organ's visualization.
/// </summary>
[DataField, AutoNetworkedField]
public ProtoId<DisplacementDataPrototype>? Displacement;
}
/// <summary>

View file

@ -1,5 +1,6 @@
using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.DisplacementMap;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs;
using Content.Shared.StatusIcon;
@ -63,6 +64,13 @@ public sealed partial class DamageableComponent : Component
[DataField("radiationDamageTypes")]
// ReSharper disable once UseCollectionExpression - Cannot refactor this as it's a potential sandbox violation.
public List<ProtoId<DamageTypePrototype>> RadiationDamageTypeIDs = new() { "Radiation" };
/// <summary>
/// Sets the displacement map used for any of the DamageVisuals sprites for this entity.
/// TODO: The entirety of DamageVisualsSystem needs to be rewritten.
/// </summary>
[DataField]
public ProtoId<DisplacementDataPrototype>? Displacement;
}
[Serializable, NetSerializable]

View file

@ -10,7 +10,8 @@ namespace Content.Shared.Damage
Disabled,
DamageSpecifierDelta,
DamageUpdateGroups,
ForceUpdate
ForceUpdate,
Displacement,
}
[Serializable, NetSerializable]

View file

@ -66,6 +66,20 @@ public sealed partial class DamageableSystem : EntitySystem
new DamageVisualizerGroupData(ent.Comp.DamagePerGroup.Keys.ToList()),
appearance
);
if (ent.Comp.Displacement != null)
{
_appearance.SetData(
ent,
DamageVisualizerKeys.Displacement,
ent.Comp.Displacement.Value.Id,
appearance
);
}
else
{
_appearance.RemoveData(ent, DamageVisualizerKeys.Displacement);
}
}
// TODO DAMAGE

View file

@ -0,0 +1,20 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.DisplacementMap;
/// <summary>
/// Prototype wrapper for displacement maps, making it easier to network displacements from server to client.
/// </summary>
[Prototype]
public sealed partial class DisplacementDataPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// The displacement map this prototype is referencing.
/// </summary>
[DataField(required: true)]
public DisplacementData Displacement = default!;
}

View file

@ -1,5 +1,7 @@
using Content.Shared.DisplacementMap;
using Content.Shared.Nutrition.EntitySystems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
@ -26,6 +28,12 @@ public sealed partial class CreamPiedComponent : Component
/// </summary>
[DataField, AutoNetworkedField]
public SpriteSpecifier? Sprite;
/// <summary>
/// If set, applies a displacement map to the pie sprite.
/// </summary>
[DataField, AutoNetworkedField]
public ProtoId<DisplacementDataPrototype>? Displacement;
}
/// <summary>

View file

@ -5,26 +5,87 @@
name: dwarf appearance
components:
- type: Inventory
femaleDisplacements:
femaleDisplacements: { } # Necessary due to MobHuman inheritance for MobDwarf
displacements:
jumpsuit:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: jumpsuit-female
state: dwarfism
outerClothing:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
suitstorage:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
id:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
mask:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
belt:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
eyes:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
gloves:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
head:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
neck:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
back:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
ears:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
shoes:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: InitialBody
organs:
Torso: OrganHumanTorso
Head: OrganHumanHead
ArmLeft: OrganHumanArmLeft
ArmRight: OrganHumanArmRight
HandRight: OrganHumanHandRight
HandLeft: OrganHumanHandLeft
LegLeft: OrganHumanLegLeft
LegRight: OrganHumanLegRight
FootLeft: OrganHumanFootLeft
FootRight: OrganHumanFootRight
Torso: OrganDwarfTorso
Head: OrganDwarfHead
ArmLeft: OrganDwarfArmLeft
ArmRight: OrganDwarfArmRight
HandRight: OrganDwarfHandRight
HandLeft: OrganDwarfHandLeft
LegLeft: OrganDwarfLegLeft
LegRight: OrganDwarfLegRight
FootLeft: OrganDwarfFootLeft
FootRight: OrganDwarfFootRight
Brain: OrganHumanBrain
Eyes: OrganHumanEyes
Eyes: OrganDwarfEyes
Tongue: OrganHumanTongue
Appendix: OrganHumanAppendix
Ears: OrganHumanEars
@ -33,10 +94,27 @@
Stomach: OrganDwarfStomach
Liver: OrganDwarfLiver
Kidneys: OrganHumanKidneys
- type: Hands
leftHandDisplacement:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism_hand_left
rightHandDisplacement:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism_hand_right
- type: HumanoidProfile
species: Dwarf
- type: ScaleVisuals
scale: 1, 0.8
- type: displacementData
id: Dwarfism
displacement:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent:
@ -64,6 +142,14 @@
accent: scottish
- type: Speech
speechSounds: Bass
- type: CreamPied
displacement: Dwarfism
- type: Damageable
displacement: Dwarfism
- type: Flammable
displacement: Dwarfism
- type: InnerBodyAnomalyVisuals
displacement: Dwarfism
- type: entity
parent: OrganBaseOrganic
@ -72,12 +158,220 @@
suffix: Dwarf
- type: entity
parent: OrganDwarf
id: OrganDwarfAppearance
abstract: true
suffix: Dwarf
components:
- type: VisualOrgan
data:
sprite: Mobs/Species/Human/parts.rsi
displacement: Dwarfism
- type: entity
parent: OrganDwarf
id: OrganDwarfMetabolizer
abstract: true
components:
- type: Metabolizer
metabolizerTypes: [ Dwarf ]
- type: entity
parent: [ OrganHumanTorso, OrganDwarfAppearance ]
id: OrganDwarfTorso
components:
- type: VisualOrganMarkings
markingsDisplacement:
Chest:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
Tail:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
Overlay:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
TailOverlay:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
UndergarmentTop:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
UndergarmentBottom:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
Special:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanHead, OrganDwarfAppearance ]
id: OrganDwarfHead
components:
- type: VisualOrganMarkings
markingsDisplacement:
Head:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
Hair:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
FacialHair:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
Snout:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
SnoutCover:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
HeadSide:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
HeadTop:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanArmLeft, OrganDwarfAppearance ]
id: OrganDwarfArmLeft
components:
- type: VisualOrganMarkings
markingsDisplacement:
LArm:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanArmRight, OrganDwarfAppearance ]
id: OrganDwarfArmRight
components:
- type: VisualOrganMarkings
markingsDisplacement:
RArm:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanHandRight, OrganDwarfAppearance ]
id: OrganDwarfHandRight
components:
- type: VisualOrganMarkings
markingsDisplacement:
RHand:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanHandLeft, OrganDwarfAppearance ]
id: OrganDwarfHandLeft
components:
- type: VisualOrganMarkings
markingsDisplacement:
LHand:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanLegLeft, OrganDwarfAppearance ]
id: OrganDwarfLegLeft
components:
- type: VisualOrganMarkings
markingsDisplacement:
LLeg:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanLegRight, OrganDwarfAppearance ]
id: OrganDwarfLegRight
components:
- type: VisualOrganMarkings
markingsDisplacement:
RLeg:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanFootLeft, OrganDwarfAppearance ]
id: OrganDwarfFootLeft
components:
- type: VisualOrganMarkings
markingsDisplacement:
LFoot:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanFootRight, OrganDwarfAppearance ]
id: OrganDwarfFootRight
components:
- type: VisualOrganMarkings
markingsDisplacement:
RFoot:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganHumanEyes, OrganDwarfAppearance ]
id: OrganDwarfEyes
components:
- type: VisualOrgan
data:
sprite: Mobs/Customization/eyes.rsi
displacement: Dwarfism
- type: VisualOrganMarkings
markingsDisplacement:
Eyes:
sizeMaps:
32:
sprite: Mobs/Species/Human/displacement.rsi
state: dwarfism
- type: entity
parent: [ OrganDwarfMetabolizer, OrganHumanStomach ]
id: OrganDwarfStomach

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Made by TheShuEd",
"copyright": "jumpsuit-female made by TheShuEd, dwarfism sprites made by SlamBamActionman (Github)",
"size": {
"x": 32,
"y": 32
@ -13,6 +13,22 @@
{
"name": "jumpsuit-female",
"directions": 4
},
{
"name": "dwarfism",
"directions": 4
},
{
"name": "dwarfism_hand_left",
"directions": 4
},
{
"name": "dwarfism_hand_right",
"directions": 4
},
{
"name": "dwarfism_vertical",
"directions": 1
}
]
}