CONTENT CONTRACT · VERSION 1
Your first item.
Give one handler two different parameter records.
1. Declare the item
The following complete record is extracted from the validated example package's definitions.json (ID core:healing_potion). Its name is a localized text key.
{
"icon": "core:healing_potion_icon",
"id": "core:healing_potion",
"kind": "item",
"max_stack": 20,
"name": "core:healing_potion_name",
"tags": [
"core:medicine",
"core:quick_heal"
],
"use": {
"cooldown_ticks": 50,
"parameters": {
"amount": 25
},
"reach_mm": 0,
"script": "core:heal",
"snapshot": {
"anchors": [],
"definitions_from": [
"core"
],
"radius_mm": 0,
"variables": []
},
"target_scope": "self"
}
}
2. Return effects
This is the package's scripts/heal.luau. The heal and consume_item effects form one atomic response. A stronger potion changes the amount parameter; the handler stays the same.
--!strict
local Game = require("@hearthwild/game-api")
local Core = require("@package/types")
return function(ctx: Core.HealContext): Game.UseResult
local event = ctx.event
local actor = ctx.read.actor(event.target)
if actor == nil or not actor.alive then
return {outcome = "rejected", reason = "core:unavailable"}
end
if actor.health >= actor.max_health then
return {outcome = "rejected", reason = "core:already_healthy"}
end
return {outcome = "used", effects = {
{kind = "consume_item", holder = event.actor, item = event.item, count = 1},
{kind = "heal", target = event.target, amount = ctx.parameters.amount},
}}
end
3. Test the response
A fixture freezes a snapshot and states the exact expected answer. Parameters come from the item, never from the fixture. This is the package's tests/healing_potion_60.json:
{
"event": {
"actor": "a1",
"item": "core:healing_potion",
"kind": "item_used",
"player": "p1",
"target": "a1"
},
"expect": {
"kind": "result",
"result": {
"effects": [
{
"count": 1,
"holder": "a1",
"item": "core:healing_potion",
"kind": "consume_item"
},
{
"amount": 25,
"kind": "heal",
"target": "a1"
}
],
"outcome": "used"
}
},
"handler": {
"item": "core:healing_potion",
"kind": "item_use"
},
"id": "healing_potion_60",
"owner": {
"kind": "player",
"player": "p1"
},
"snapshot": {
"actors": [
{
"active_lights": [],
"alive": true,
"definition": "core:traveller",
"health": 60,
"home": {
"map": "m1",
"x_mm": 0,
"y_mm": 0,
"z_mm": 0
},
"hunger": 100,
"max_health": 100,
"max_hunger": 100,
"max_stamina": 100,
"position": {
"map": "m1",
"x_mm": 0,
"y_mm": 0,
"z_mm": 0
},
"ref": "a1",
"stamina": 100,
"tags": []
}
],
"clock": {
"day": 0,
"minute": 0,
"season": "core:spring",
"tick": 1
},
"quests": [
{
"player": "p1",
"quest": "core:first_aid_quest",
"revision": 0,
"stage": "available"
}
],
"variables": []
}
}
4. Validate the package
hearthwild-content validate assets/content/packages/core --target desktopThe loader checks records, references, dependencies and files, then runs every fixture in the game's own interpreter: 98 fixtures pass for this package. Continue with the authoring tools to pack the package or reload it while the game runs.