The typed buffers are slices: words/floats/fixeds/doubles/pointers(n) make
zeroed, bounds-checked []int/[]float/... and the type names mean them. buffer(n)
is a []byte, with text_of, Fs.read_bytes/write_bytes and view(xs, start, n).
bytes(), indexing a raw pointer or bytes, free, resize, Memory.*, raw file calls,
data_of and C externs are refused outside unsafe { } / unsafe function, and a
project's own files may write unsafe only with --unsafe; the runtime and packages
are the platform. A slice passed to an extern goes as its data.
What the change found: Sync's atomics on a slice header, words(n) uninitialised,
input's fixed axes in ints, truetype's fixed outlines as ints, skin matrices
typed int, gl_shader's source table made from raw bytes. render3d gets safe
entry points (safe_api.ludic). Rendering is byte-identical; a frame costs the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
83 lines
2.9 KiB
Text
83 lines
2.9 KiB
Text
# crafting.ludic — RPG Module C: a data-driven crafting registry (#59).
|
|
#
|
|
# Recipes are content, not code: register with Craft.recipe + Craft.ingredient, so a
|
|
# game or mod adds crafting with zero code. Craft.make consumes ingredients from the
|
|
# ludic.rpg Inventory and yields the output; every step is a veto-able event.
|
|
|
|
import "ludic.rpg/inventory.ludic"
|
|
|
|
const CRAFT_MAX: int = 128
|
|
const CRAFT_ING_MAX: int = 512
|
|
|
|
var recipe_reg: Dict = null # recipe name -> id
|
|
var recipe_n: int = 0
|
|
var recipe_out: pointers = null # output item name
|
|
var recipe_outqty: words = null
|
|
var ing_n: int = 0
|
|
var ing_rid: words = null # owning recipe id
|
|
var ing_name: pointers = null # ingredient item name
|
|
var ing_qty: words = null
|
|
|
|
function craft_ensure() -> void {
|
|
if recipe_reg == null {
|
|
recipe_reg = Dict.new()
|
|
recipe_out = pointers(CRAFT_MAX); recipe_outqty = words(CRAFT_MAX)
|
|
ing_rid = words(CRAFT_ING_MAX); ing_name = pointers(CRAFT_ING_MAX); ing_qty = words(CRAFT_ING_MAX)
|
|
}
|
|
}
|
|
|
|
event cancellable CraftRequested { e: int = 0, recipe: int = 0 }
|
|
event CraftCompleted { e: int = 0, recipe: int = 0 }
|
|
|
|
# Craft.recipe(name, out_item, out_qty) — declare a recipe; returns its id.
|
|
@Namespace(Craft) function craft_recipe(name: pointer, out_item: pointer, out_qty: int) -> int {
|
|
craft_ensure()
|
|
if recipe_n >= CRAFT_MAX { return -1 }
|
|
let id = recipe_n
|
|
recipe_out[id] = out_item; recipe_outqty[id] = out_qty
|
|
recipe_n += 1
|
|
Dict.set(recipe_reg, name, id)
|
|
return id
|
|
}
|
|
@Namespace(Craft) function craft_id(name: pointer) -> int { craft_ensure(); return Dict.get_or(recipe_reg, name, -1) }
|
|
# Craft.ingredient(recipe_name, item, qty) — add an ingredient requirement.
|
|
@Namespace(Craft) function craft_ingredient(recipe_name: pointer, item: pointer, qty: int) -> void {
|
|
craft_ensure()
|
|
let rid = craft_id(recipe_name)
|
|
if rid < 0 { return }
|
|
if ing_n >= CRAFT_ING_MAX { return }
|
|
ing_rid[ing_n] = rid; ing_name[ing_n] = item; ing_qty[ing_n] = qty
|
|
ing_n += 1
|
|
}
|
|
|
|
# Craft.can(e, recipe_name) — does the owner hold every ingredient?
|
|
@Namespace(Craft) function craft_can(e: int, recipe_name: pointer) -> int {
|
|
craft_ensure()
|
|
let rid = craft_id(recipe_name)
|
|
if rid < 0 { return 0 }
|
|
var i = 0
|
|
while i < ing_n {
|
|
if ing_rid[i] == rid {
|
|
if Inventory.count(e, ing_name[i]) < ing_qty[i] { return 0 }
|
|
}
|
|
i += 1
|
|
}
|
|
return 1
|
|
}
|
|
|
|
# Craft.make(e, recipe_name) — consume ingredients + produce output; 1 on success.
|
|
@Namespace(Craft) function craft_make(e: int, recipe_name: pointer) -> int {
|
|
craft_ensure()
|
|
let rid = craft_id(recipe_name)
|
|
if rid < 0 { return 0 }
|
|
if craft_can(e, recipe_name) == 0 { return 0 }
|
|
if emit CraftRequested(e: e, recipe: rid) != 0 { return 0 }
|
|
var i = 0
|
|
while i < ing_n {
|
|
if ing_rid[i] == rid { Inventory.remove(e, ing_name[i], ing_qty[i]) }
|
|
i += 1
|
|
}
|
|
Inventory.add(e, recipe_out[rid], recipe_outqty[rid])
|
|
emit CraftCompleted(e: e, recipe: rid)
|
|
return 1
|
|
}
|