feat(vagrant): v0.15.0 stone-age slice — saw_planks property-constraint recipe (log→4 planks, cutting tool); crafting output-alias for bw-compat icon resolvers

This commit is contained in:
calic
2026-07-28 10:42:21 +00:00
parent 08413e9c29
commit 8994b24567
3 changed files with 124 additions and 4 deletions

View File

@@ -8,11 +8,20 @@ callback, foot-body-orientation ("tactical twist"), scale-deformation walk
cycle, and inheritance-decoupled foot sprites. End-to-end inventory pickup/drop
demo: pick up a rock into a backpack container, drop it back into the world.
**Version:** 0.14.0
**Version:** 0.15.0
**Module-ID:** vagrant-skeleton
**Requires:** lib-core.input >=0.4.0, lib-core.camera >=0.3.0, lib-core.render >=0.2.0, lib-core.maps >=0.1.2, lib-core.puppet >=0.4.4, lib-core.interaction >=0.1.0, lib-core.composition >=0.3.0, lib-core.actor >=0.1.0, lib-core.inventory-list >=0.1.0, lib-core.panel >=0.2.0, lib-core.inventory-list-display >=0.1.0, lib-core.notify >=0.1.0, lib-core.notify-display >=0.1.0, lib-core.world-overlay >=0.1.0, lib-core.crafting >=0.2.0, lib-core.crafting-display >=0.2.0, lib-asset.prototype-subterrain >=0.2.0, lib-asset.prototype-tc-basics >=0.1.0
**Requires:** lib-core.input >=0.4.0, lib-core.camera >=0.3.0, lib-core.render >=0.2.0, lib-core.maps >=0.1.2, lib-core.puppet >=0.4.4, lib-core.interaction >=0.1.0, lib-core.composition >=0.3.0, lib-core.actor >=0.1.0, lib-core.inventory-list >=0.1.0, lib-core.panel >=0.2.0, lib-core.inventory-list-display >=0.1.0, lib-core.notify >=0.1.0, lib-core.notify-display >=0.1.0, lib-core.world-overlay >=0.1.0, lib-core.crafting >=0.3.0, lib-core.crafting-display >=0.2.0, lib-asset.prototype-subterrain >=0.2.0, lib-asset.prototype-tc-basics >=0.1.0
**Tags:** test-chamber, puppet, walking-sim, interaction
> **v0.15.0:** First consumer of `lib-core.crafting` v0.3.0 (ADR-0055). New
> stone-age slice: a **Log** (heavy wood item) + a **Sharp Stone** (cutting
> tool) spawn in the world, and the `saw_planks` recipe matches its input by
> **property-constraint** (`composition.wood > 0.5` AND `weight > 5`) instead
> of template-id, requires the sharp-stone as a **non-consumed tool**
> (`affordance.cutting`), and yields **4 planks** (multi-output). A light plank
> (weight 2) is correctly not re-sawable. Existing `rock_pick`/`rock_pile`
> recipes are unchanged (template-id hybrid bw-compat).
>
> **v0.14.0:** Bed + Bench + Backpack visuals migrated from the proprietary
> Subterrain world-atlas to TC_Basics sprites (`single_bed1`, `bench1`,
> `sack1`). Bed + Bench promoted to composition-entities (renderable tag) —

111
init.lua
View File

@@ -212,6 +212,45 @@ composition.define_template{
tags = {"renderable", "item"},
}
-- Stone-Age crafting slice (crafting v0.3 / ADR-0055 consumer). `log` is a
-- heavy wood item; the `saw_planks` recipe matches it by property-constraint
-- (composition.wood > 0.5 AND weight > 5) rather than by template-id, so a
-- light `plank` (weight 2) is correctly NOT sawable into more planks.
composition.define_template{
id = "log",
properties = {
stack_mode = "individual",
name = "Log",
description = "A heavy wooden log. Saw it into planks with a cutting edge.",
weight = 20, -- kg — heavy (> saw threshold)
volume = 0.05,
["composition.wood"] = 1.0,
sprite_atlas = "",
sprite_uv = {x = 0, y = 0, w = 1, h = 1},
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
-- `sharp_stone` is a NON-consumed cutting TOOL: it carries the derived
-- affordance `affordance.cutting`, which `saw_planks` presence-checks.
composition.define_template{
id = "sharp_stone",
properties = {
stack_mode = "individual",
name = "Sharp Stone",
description = "A knapped stone with a cutting edge. Used as a tool, not consumed.",
weight = 1,
volume = 0.0004,
["composition.stone"] = 1.0,
["affordance.cutting"] = true, -- tool affordance (crafting v0.3)
sprite_atlas = "",
sprite_uv = {x = 0, y = 0, w = 1, h = 1},
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
-- NOTE: Crafted-output templates (rock_pick, rock_pile) are defined inside
-- M.init rather than at top-level, because their sprite_atlas defaults need
-- the resolved blob_rect_stone PNG path. Crafting calls composition.create
@@ -657,6 +696,28 @@ function M.init(ctx)
tags = {"renderable", "item"},
}
-- plank: crafted output of `saw_planks` (crafting v0.3, ×4 multi-output).
-- Placeholder visual reuses the TC_Basics bench sprite until a dedicated
-- plank decal lands.
local plank_uv = tc_sprites.bench1
composition.define_template{
id = "plank",
properties = {
stack_mode = "individual",
name = "Plank",
description = "A sawn wooden plank.",
weight = 2, -- light: NOT re-sawable (< 5)
volume = 0.004,
["composition.wood"] = 1.0,
sprite_atlas = tc_atlas_png,
sprite_uv = {x = plank_uv.x, y = plank_uv.y,
w = plank_uv.w, h = plank_uv.h},
sprite_scale = tc_scale,
position = {x = 0, y = 0},
},
tags = {"renderable", "item"},
}
-- Workbench-Template (Phase D v0.2). Container-kind=list so it can
-- accept items via inventory.add (crafting output landing spot).
-- Placeholder visual re-uses the blob_rect_stone atlas with
@@ -724,6 +785,36 @@ function M.init(ctx)
register_pickup(state.stick)
if CI_FRAME_PERF then engine.print("vagrant: stick_spawned") end
-- Stone-Age slice: a Log (saw-able) + a Sharp Stone (cutting tool) in the
-- world, so `saw_planks` (crafting v0.3 property-constraint recipe) is
-- demonstrable end-to-end: pick both up, craft at the workbench → 4 planks.
local LOG_X, LOG_Y = BACKPACK_X - 240, BACKPACK_Y
local log_uv = tc_sprites.log_pile1
state.log = composition.create{
template = "log",
properties = {
sprite_atlas = tc_atlas_png,
sprite_uv = {x = log_uv.x, y = log_uv.y, w = log_uv.w, h = log_uv.h},
sprite_scale = tc_scale,
position = {x = LOG_X, y = LOG_Y},
},
}
register_pickup(state.log)
local SAW_X, SAW_Y = BACKPACK_X - 240, BACKPACK_Y - 70
local saw_uv = tc_sprites.spade
state.sharp_stone = composition.create{
template = "sharp_stone",
properties = {
sprite_atlas = tc_atlas_png,
sprite_uv = {x = saw_uv.x, y = saw_uv.y, w = saw_uv.w, h = saw_uv.h},
sprite_scale = tc_scale,
position = {x = SAW_X, y = SAW_Y},
},
}
register_pickup(state.sharp_stone)
if CI_FRAME_PERF then engine.print("vagrant: stoneage_spawned") end
-- Workbench spawn (Phase D v0.2). Placed at (350, 380) — 20px above
-- the backpack (at 350, 400) so they are visually distinct but still
-- on the visible-on-spawn area. register_interaction_use registers a
@@ -756,6 +847,25 @@ function M.init(ctx)
name = "Rock Pile",
description = "Stack rocks for storage.",
}
-- saw_planks: first property-constraint recipe (crafting v0.3 / ADR-0055).
-- Input matched by MATERIAL, not template-id: any item that is mostly wood
-- and heavy enough (a log qualifies, a plank does not). Requires a cutting
-- TOOL (sharp_stone) that is checked for presence but NOT consumed.
-- Multi-output: one log yields four planks.
crafting.define_recipe{
id = "saw_planks",
inputs = {
{match = {["composition.wood"] = ">0.5", weight = ">5"}, count = 1},
},
tools = {
{match = {["affordance.cutting"] = true}},
},
outputs = {
{template = "plank", count = 4},
},
name = "Saw Planks",
description = "Saw a wooden log into four planks (needs a cutting edge).",
}
-- v0.14.0: per-recipe icon resolver for the Crafting + Workbench-Crafting
-- widgets. Maps recipe.output.template → {atlas, uv} for the icon
@@ -766,6 +876,7 @@ function M.init(ctx)
local craft_icons = {
rock_pick = { atlas = tc_atlas_png, uv = tc_sprites.spade },
rock_pile = { atlas = stone_atlas_png, uv = stone_uvs.slot_13_solid },
plank = { atlas = tc_atlas_png, uv = tc_sprites.bench1 },
}
local function craft_icon_for(recipe)
if recipe and recipe.output and recipe.output.template then

View File

@@ -1,6 +1,6 @@
{
"id": "vagrant-skeleton",
"version": "0.14.0",
"version": "0.15.0",
"kind": "module",
"api": "^0.1",
"ci_frames": 60,
@@ -26,7 +26,7 @@
{"id": "lib-core.puppet", "version": "0.5.0"},
{"id": "lib-core.interaction", "version": "0.1.0"},
{"id": "lib-core.inventory-list", "version": "0.1.0"},
{"id": "lib-core.crafting", "version": "0.2.0"},
{"id": "lib-core.crafting", "version": "0.3.0"},
{"id": "lib-core.crafting-display", "version": "0.3.0"},
{"id": "lib-asset.prototype-subterrain", "version": "0.2.0"},
{"id": "lib-asset.prototype-blob-geom", "version": "0.1.0"},