Add Mortar and Handheld Juicer (#42019)
* init * API * testing * review * return * good enough, fix later TODO: Proper prototype DoAfter Sounds * "proper" prototype TODO DoAfter Sprite * proper protos, mortar sprite * juicer sprites TODO: Juicer sounds Makeshift crafting recipes Add regular to vendors * sprite tweak * juicing sound, cleanup, construction * vendors * line end * attribution newline * small balance tweak * Let it be known id never webedit * meta * item size * review * handhelds * partial review * cache solution, looping * graph * review * popup --------- Co-authored-by: Janet Blackquill <uhhadd@gmail.com>
@@ -5,4 +5,3 @@ namespace Content.Client.Kitchen.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class ReagentGrinderSystem : SharedReagentGrinderSystem;
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Fluids;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Kitchen.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Kitchen.EntitySystems;
|
||||
|
||||
internal sealed class HandheldGrinderSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedReagentGrinderSystem _reagentGrinder = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
|
||||
[Dependency] private readonly SharedStackSystem _stackSystem = default!;
|
||||
[Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedPuddleSystem _puddle = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HandheldGrinderComponent, EntRemovedFromContainerMessage>(OnGrinderRemoved);
|
||||
SubscribeLocalEvent<HandheldGrinderComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<HandheldGrinderComponent, HandheldGrinderDoAfterEvent>(OnHandheldDoAfter);
|
||||
}
|
||||
|
||||
// prevent the infamous UdderSystem debug assert, see https://github.com/space-wizards/space-station-14/pull/35314
|
||||
// TODO: find a better solution than copy pasting this into every shared system that caches solution entities
|
||||
private void OnGrinderRemoved(Entity<HandheldGrinderComponent> entity, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
// Make sure the removed entity was our contained solution and set it to null
|
||||
if (args.Entity != entity.Comp.GrinderSolution?.Owner)
|
||||
return;
|
||||
|
||||
entity.Comp.GrinderSolution = null;
|
||||
}
|
||||
|
||||
private void OnInteractUsing(Entity<HandheldGrinderComponent> ent, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
var item = args.Used;
|
||||
|
||||
if (!CanGrinderBeUsed(ent, item, out var reason))
|
||||
{
|
||||
_popup.PopupClient(reason, ent, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_reagentGrinder.GetGrinderSolution(item, ent.Comp.Program) is null)
|
||||
return;
|
||||
|
||||
if (!_solution.ResolveSolution(ent.Owner, ent.Comp.SolutionName, ref ent.Comp.GrinderSolution))
|
||||
return;
|
||||
|
||||
if (_net.IsServer) // Cannot cancel predicted audio.
|
||||
ent.Comp.AudioStream = _audio.PlayPvs(ent.Comp.Sound, ent)?.Entity;
|
||||
|
||||
var doAfter = new DoAfterArgs(EntityManager, args.User, ent.Comp.DoAfterDuration, new HandheldGrinderDoAfterEvent(), ent, ent, item)
|
||||
{
|
||||
NeedHand = true,
|
||||
BreakOnDamage = true,
|
||||
BreakOnDropItem = true,
|
||||
BreakOnHandChange = true,
|
||||
BreakOnMove = true
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfter);
|
||||
}
|
||||
|
||||
private void OnHandheldDoAfter(Entity<HandheldGrinderComponent> ent, ref HandheldGrinderDoAfterEvent args)
|
||||
{
|
||||
ent.Comp.AudioStream = _audio.Stop(ent.Comp.AudioStream);
|
||||
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (args.Used is not { } item)
|
||||
return;
|
||||
|
||||
if (!CanGrinderBeUsed(ent, item, out var reason))
|
||||
{
|
||||
_popup.PopupClient(reason, ent, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_reagentGrinder.GetGrinderSolution(item, ent.Comp.Program) is not { } obtainedSolution)
|
||||
return;
|
||||
|
||||
if (!_solution.ResolveSolution(ent.Owner, ent.Comp.SolutionName, ref ent.Comp.GrinderSolution, out var solution))
|
||||
return;
|
||||
|
||||
_solution.TryMixAndOverflow(ent.Comp.GrinderSolution.Value, obtainedSolution, solution.MaxVolume, out var overflow);
|
||||
|
||||
if (overflow != null)
|
||||
_puddle.TrySpillAt(ent, overflow, out _);
|
||||
|
||||
if (TryComp<StackComponent>(item, out var stack))
|
||||
_stackSystem.ReduceCount((item, stack), 1);
|
||||
else
|
||||
_destructibleSystem.DestroyEntity(item);
|
||||
|
||||
_popup.PopupClient(Loc.GetString(ent.Comp.FinishedPopup, ("item", item)), ent, args.User);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the respective handheld grinder can currently be used.
|
||||
/// </summary>
|
||||
/// <param name="ent">The grinder entity.</param>
|
||||
/// <param name="item">The item it is being used on.</param>
|
||||
/// <param name="reason">Reason the grinder cannot be used. Null if the function returns true.</param>
|
||||
/// <returns>True if the grinder can be used, otherwise false.</returns>
|
||||
public bool CanGrinderBeUsed(Entity<HandheldGrinderComponent> ent, EntityUid item, [NotNullWhen(false)] out string? reason)
|
||||
{
|
||||
reason = null;
|
||||
if (ent.Comp.Program == GrinderProgram.Grind && !_reagentGrinder.CanGrind(item))
|
||||
{
|
||||
reason = Loc.GetString("handheld-grinder-cannot-grind", ("item", item));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ent.Comp.Program == GrinderProgram.Juice && !_reagentGrinder.CanJuice(item))
|
||||
{
|
||||
reason = Loc.GetString("handheld-grinder-cannot-juice", ("item", item));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DoAfter used to indicate the handheld grinder is in use.
|
||||
/// After it ends, the GrinderProgram from <see cref="HandheldGrinderComponent"/> is used on the contents.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class HandheldGrinderDoAfterEvent : SimpleDoAfterEvent;
|
||||
@@ -0,0 +1,54 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Kitchen.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates this entity is a handheld grinder.
|
||||
/// Entities with <see cref="ExtractableComponent"/> can be used on handheld grinders to extract their solutions.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class HandheldGrinderComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The length of the doAfter.
|
||||
/// After it ends, the respective GrinderProgram is used on the contents.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public TimeSpan DoAfterDuration = TimeSpan.FromSeconds(4f);
|
||||
|
||||
/// <summary>
|
||||
/// Popup to use after the current item is done processing.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public LocId FinishedPopup = "handheld-grinder-default";
|
||||
|
||||
/// <summary>
|
||||
/// The sound to play when the doAfter starts.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Items/Culinary/mortar_grinding.ogg", AudioParams.Default.WithLoop(true));
|
||||
|
||||
/// <summary>
|
||||
/// The grinder program to use.
|
||||
/// Decides whether this one will Juice or Grind the objects.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public GrinderProgram Program = GrinderProgram.Grind;
|
||||
|
||||
/// <summary>
|
||||
/// The solution into which the output reagents will go.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public string SolutionName = "grinderOutput";
|
||||
|
||||
/// <summary>
|
||||
/// Cached solution from the grinder.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Entity<SolutionComponent>? GrinderSolution;
|
||||
|
||||
// Used to cancel the sound.
|
||||
public EntityUid? AudioStream;
|
||||
}
|
||||
@@ -51,4 +51,3 @@ public sealed partial class ActiveReagentGrinderComponent : Component
|
||||
[ViewVariables]
|
||||
public GrinderProgram Program;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,4 +65,3 @@ public abstract class SharedReagentGrinderSystem : EntitySystem
|
||||
return ent.Comp.JuiceSolution is not null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
Resources/Audio/Items/Culinary/attributions.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
- files: ["mortar_grinding.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Taken from freesound, cleaned up and sped up. Coverted to .ogg"
|
||||
source: "https://freesound.org/people/OlyveBone/sounds/486995/"
|
||||
|
||||
- files: ["juicer_juicing.ogg"]
|
||||
license: "CC-BY-3.0"
|
||||
copyright: "Taken from freesound. Converted to .ogg"
|
||||
source: "https://freesound.org/people/Edo333/sounds/272208/"
|
||||
BIN
Resources/Audio/Items/Culinary/juicer_juicing.ogg
Normal file
BIN
Resources/Audio/Items/Culinary/mortar_grinding.ogg
Normal file
@@ -0,0 +1,6 @@
|
||||
handheld-grinder-cannot-juice = You cannot juice {THE($item)}!
|
||||
handheld-grinder-cannot-grind = You cannot grind {THE($item)}!
|
||||
|
||||
handheld-grinder-default = You finished processing {THE($item)}.
|
||||
handheld-grinder-juiced = You finished juicing {THE($item)}.
|
||||
handheld-grinder-grinded = You finished grinding {THE($item)}.
|
||||
@@ -27,6 +27,8 @@
|
||||
DrinkMugOne: 1
|
||||
DrinkMugRainbow: 2
|
||||
DrinkMugRed: 2
|
||||
MortarAndPestle: 1
|
||||
HandheldJuicer: 1
|
||||
contrabandInventory:
|
||||
CandyBowl: 1
|
||||
BarSpoon: 2
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
Bucket: 3
|
||||
BoxMouthSwab: 1
|
||||
BoxAgrichem: 1
|
||||
MortarAndPestle: 1
|
||||
HandheldJuicer: 1
|
||||
#TO DO:
|
||||
#plant analyzer
|
||||
contrabandInventory:
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseItem
|
||||
id: BaseHandheldGrinder
|
||||
components:
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
grinderOutput:
|
||||
maxVol: 20
|
||||
- type: SolutionTransfer
|
||||
- type: DrawableSolution
|
||||
solution: grinderOutput
|
||||
- type: RefillableSolution
|
||||
solution: grinderOutput
|
||||
- type: DrainableSolution
|
||||
solution: grinderOutput
|
||||
- type: Edible
|
||||
edible: Drink
|
||||
solution: grinderOutput
|
||||
destroyOnEmpty: false
|
||||
utensil: Spoon
|
||||
- type: MixableSolution
|
||||
solution: grinderOutput
|
||||
- type: ExaminableSolution
|
||||
solution: grinderOutput
|
||||
exactVolume: true
|
||||
- type: SolutionItemStatus
|
||||
solution: grinderOutput
|
||||
- type: SolutionContainerVisuals
|
||||
maxFillLevels: 4
|
||||
fillBaseName: fill-
|
||||
- type: DnaSubstanceTrace
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
- type: Spillable
|
||||
solution: grinderOutput
|
||||
- type: Appearance
|
||||
- type: HandheldGrinder
|
||||
|
||||
# Mortars
|
||||
- type: entity
|
||||
parent: BaseHandheldGrinder
|
||||
id: MortarAndPestle
|
||||
name: mortar and pestle
|
||||
description: Used for grinding small amounts of objects.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/mortar_and_pestle.rsi
|
||||
layers:
|
||||
- state: icon
|
||||
- map: ["enum.SolutionContainerLayers.Fill"]
|
||||
state: fill-1
|
||||
visible: false
|
||||
- type: HandheldGrinder
|
||||
finishedPopup: handheld-grinder-grinded
|
||||
|
||||
- type: entity
|
||||
parent: MortarAndPestle
|
||||
id: MortarAndPestleMakeshift
|
||||
name: makeshift mortar and pestle
|
||||
description: Used for grinding small amounts of objects. Inferior version made out of wood.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/mortar_and_pestle.rsi
|
||||
layers:
|
||||
- state: makeshift_icon
|
||||
- map: ["enum.SolutionContainerLayers.Fill"]
|
||||
state: fill-1
|
||||
visible: false
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: makeshift-inhand-left
|
||||
right:
|
||||
- state: makeshift-inhand-right
|
||||
- type: HandheldGrinder
|
||||
doAfterDuration: 6
|
||||
- type: Construction
|
||||
graph: MakeshiftMortarAndPestle
|
||||
node: mortarAndPestle
|
||||
|
||||
# Juicers
|
||||
- type: entity
|
||||
parent: BaseHandheldGrinder
|
||||
id: HandheldJuicer
|
||||
name: handheld juicer
|
||||
description: Used for juicing small amounts of objects.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/handheld_juicer.rsi
|
||||
layers:
|
||||
- state: juicer_base
|
||||
- map: ["enum.SolutionContainerLayers.Fill"]
|
||||
state: fill-1
|
||||
visible: false
|
||||
- state: cap
|
||||
- type: HandheldGrinder
|
||||
finishedPopup: handheld-grinder-juiced
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Items/Culinary/juicer_juicing.ogg # Pasta mixing sound. Close enough.
|
||||
params:
|
||||
loop: true
|
||||
program: Juice
|
||||
|
||||
- type: entity
|
||||
parent: HandheldJuicer
|
||||
id: HandheldJuicerMakeshift
|
||||
name: makeshift juicer
|
||||
description: Used for juicing small amounts of objects. Inferior version made out of wood.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/handheld_juicer.rsi
|
||||
layers:
|
||||
- state: makeshift_base
|
||||
- map: ["enum.SolutionContainerLayers.Fill"]
|
||||
state: fill-1
|
||||
visible: false
|
||||
- state: cap
|
||||
- type: Item
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: makeshift-inhand-left
|
||||
right:
|
||||
- state: makeshift-inhand-right
|
||||
- type: HandheldGrinder
|
||||
doAfterDuration: 6
|
||||
- type: Construction
|
||||
graph: MakeshiftJuicer
|
||||
node: juicer
|
||||
|
||||
# Construction
|
||||
- type: entity
|
||||
name: incomplete mortar and pestle
|
||||
parent: BaseItem
|
||||
id: IncompleteMortarAndPestle
|
||||
description: A few planks of wood stuck together.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/mortar_and_pestle.rsi
|
||||
state: makeshift_base
|
||||
- type: Item
|
||||
size: Normal
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: makeshift-inhand-left
|
||||
right:
|
||||
- state: makeshift-inhand-right
|
||||
- type: Construction
|
||||
graph: MakeshiftMortarAndPestle
|
||||
node: incompleteMortarAndPestle
|
||||
|
||||
- type: entity
|
||||
name: incomplete handheld juicer
|
||||
parent: BaseItem
|
||||
id: IncompleteHandheldJuicer
|
||||
description: A some wood and plastic stuck together.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Kitchen/handheld_juicer.rsi
|
||||
state: makeshift_base
|
||||
- type: Item
|
||||
size: Normal
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: makeshift-inhand-left
|
||||
right:
|
||||
- state: makeshift-inhand-right
|
||||
- type: Construction
|
||||
graph: MakeshiftJuicer
|
||||
node: incompleteJuicer
|
||||
@@ -46,6 +46,20 @@
|
||||
category: construction-category-tools
|
||||
objectType: Item
|
||||
|
||||
- type: construction
|
||||
id: MakeshiftMortarAndPestle
|
||||
graph: MakeshiftMortarAndPestle
|
||||
startNode: start
|
||||
targetNode: mortarAndPestle
|
||||
category: construction-category-tools
|
||||
objectType: Item
|
||||
|
||||
- type: construction
|
||||
id: MakeshiftJuicer
|
||||
graph: MakeshiftJuicer
|
||||
startNode: start
|
||||
targetNode: juicer
|
||||
|
||||
- type: construction
|
||||
id: MakeshiftCentrifuge
|
||||
graph: MakeshiftCentrifuge
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
# Mortar
|
||||
- type: constructionGraph
|
||||
id: MakeshiftMortarAndPestle
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
edges:
|
||||
- to: incompleteMortarAndPestle
|
||||
steps:
|
||||
- material: WoodPlank
|
||||
amount: 5
|
||||
doAfter: 4
|
||||
|
||||
- node: incompleteMortarAndPestle
|
||||
entity: IncompleteMortarAndPestle
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: MaterialWoodPlank1
|
||||
amount: 5
|
||||
- !type:DeleteEntity {}
|
||||
steps:
|
||||
- tool: Prying
|
||||
doAfter: 1
|
||||
- to: mortarAndPestle
|
||||
completed:
|
||||
- !type:AdminLog
|
||||
message: "Construction"
|
||||
impact: High
|
||||
steps:
|
||||
- tool: Slicing
|
||||
doAfter: 4
|
||||
|
||||
- node: mortarAndPestle
|
||||
entity: MortarAndPestleMakeshift
|
||||
|
||||
# Juicer
|
||||
- type: constructionGraph
|
||||
id: MakeshiftJuicer
|
||||
start: start
|
||||
graph:
|
||||
- node: start
|
||||
edges:
|
||||
- to: incompleteJuicer
|
||||
steps:
|
||||
- material: WoodPlank
|
||||
amount: 4
|
||||
doAfter: 2
|
||||
- material: Plastic
|
||||
amount: 2
|
||||
doAfter: 2
|
||||
|
||||
- node: incompleteJuicer
|
||||
entity: IncompleteHandheldJuicer
|
||||
edges:
|
||||
- to: start
|
||||
completed:
|
||||
- !type:SpawnPrototype
|
||||
prototype: MaterialWoodPlank1
|
||||
amount: 4
|
||||
- !type:SpawnPrototype
|
||||
prototype: SheetPlastic1
|
||||
amount: 2
|
||||
- !type:DeleteEntity {}
|
||||
steps:
|
||||
- tool: Prying
|
||||
doAfter: 1
|
||||
- to: juicer
|
||||
completed:
|
||||
- !type:AdminLog
|
||||
message: "Construction"
|
||||
impact: High
|
||||
steps:
|
||||
- tool: Slicing
|
||||
doAfter: 4
|
||||
|
||||
- node: juicer
|
||||
entity: HandheldJuicerMakeshift
|
||||
|
After Width: | Height: | Size: 229 B |
|
After Width: | Height: | Size: 124 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 158 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 411 B |
|
After Width: | Height: | Size: 294 B |
|
After Width: | Height: | Size: 292 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 310 B |
|
After Width: | Height: | Size: 328 B |
|
After Width: | Height: | Size: 421 B |
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-4.0",
|
||||
"copyright": "Created by TheShuEd (Github), edited into a juicer and inhands by ScarKy0(GitHub)",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon"
|
||||
},
|
||||
{
|
||||
"name": "makeshift_icon"
|
||||
},
|
||||
{
|
||||
"name": "fill-1"
|
||||
},
|
||||
{
|
||||
"name": "fill-2"
|
||||
},
|
||||
{
|
||||
"name": "fill-3"
|
||||
},
|
||||
{
|
||||
"name": "fill-4"
|
||||
},
|
||||
{
|
||||
"name": "juicer_base"
|
||||
},
|
||||
{
|
||||
"name": "cap"
|
||||
},
|
||||
{
|
||||
"name": "makeshift_base"
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "makeshift-inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "makeshift-inhand-left",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 124 B |
|
After Width: | Height: | Size: 145 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 392 B |
|
After Width: | Height: | Size: 283 B |
|
After Width: | Height: | Size: 278 B |
|
After Width: | Height: | Size: 302 B |
|
After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 353 B |
|
After Width: | Height: | Size: 414 B |
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-4.0",
|
||||
"copyright": "Created by TheShuEd (Github) | Small tweaks to fill states, makeshift and inhands by ScarKy0 (Github)",
|
||||
"states": [
|
||||
{
|
||||
"name": "icon"
|
||||
},
|
||||
{
|
||||
"name": "makeshift_icon"
|
||||
},
|
||||
{
|
||||
"name": "fill-1"
|
||||
},
|
||||
{
|
||||
"name": "fill-2"
|
||||
},
|
||||
{
|
||||
"name": "fill-3"
|
||||
},
|
||||
{
|
||||
"name": "fill-4"
|
||||
},
|
||||
{
|
||||
"name": "mortar_base"
|
||||
},
|
||||
{
|
||||
"name": "makeshift_base"
|
||||
},
|
||||
{
|
||||
"name": "pestle"
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "makeshift-inhand-right",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "makeshift-inhand-left",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 363 B |
|
After Width: | Height: | Size: 251 B |