Files
kiln/maps/start.toml
T
2026-06-21 18:27:45 -05:00

314 lines
13 KiB
TOML

[world]
name = "Kiln Demo"
start = "start"
# Named Rhai scripts shared across all boards in this world.
# Objects reference a script by name via `script_name`.
[scripts]
greeter = """
fn init() {
log(`hello from object — player at ${Board.player_x}, ${Board.player_y}`);
set_tile(2); // change my glyph to ☻ — proves the write path
say("Hello there,\\ntraveller!");
}
fn tick(dt) {
//log(`x: ${Me.x} ${Board.player_x} y: ${Me.y} ${Board.player_y} q: ${Queue.length()}`);
if Board.player_x == Me.x && Board.player_y == Me.y && Queue.length() == 0 {
say("Hey! Get offa me!");
delay(5.0);
}
}
"""
mover = """
fn init() {
if Registry.get("dancer_x") != () {
let new_x = Registry.get("dancer_x");
let new_y = Registry.get("dancer_y");
if Me.x != new_x || Me.y != new_y {
teleport(new_x, new_y);
}
} else {
Registry.set("dancer_x", Me.x);
Registry.set("dancer_y", Me.y);
log(`Set reg to ${Me.x} ${Me.y}`);
}
}
// move() costs 250 ms, so the object steps ~4 cells/sec no matter how often
// tick() runs. Queue.length() avoids piling up moves; blocked() avoids walking
// into a wall (or another object's already-queued move this tick).
fn tick(dt) {
if Queue.length() == 0 { dance(); }
}
fn dance() {
move(East);
move(South);
move(North);
move(East);
say("Hey!", 0.5);
delay(0.5);
move(West);
move(South);
move(North);
move(West);
say("Ho!", 0.5);
delay(0.5);
}
// Fires when something steps into this object; id is the bumper's object id,
// or -1 for the player.
fn bump(id) {
log(`mover bumped by ${id}`);
say("Ow!");
}
"""
muffin = """
fn bump(id) {
scroll([
"You find a small muffin on the ground, your favorite kind.",
"It smells of cinnamon and warm mornings.",
["eat", "Pick up the muffin and eat it."],
["ignore", "This is obviously a trap ignore it."]
]);
}
fn eat() {
log("You ate the muffin. Delicious.");
say("Mmm!");
}
fn ignore() {
log("You walk away from the muffin. Wise.");
say("Suspicious...");
}
"""
noticeboard = """
fn bump(id) {
scroll([
" TOWN NOTICE BOARD",
" ",
"ROAD CLOSURE The eastern road through Miller's Crossing remains closed",
"following flood damage to the main bridge. Repairs are underway but travellers",
"should expect delays of at least three weeks. The north fork via Ashwell is",
"passable, though it adds half a day to the journey.",
" ",
"LOST ANIMAL — One grey mule, answers to the name Pepper. Last seen grazing",
"near the old mill on the morning of the 14th. The animal has a notched left",
"ear and wears a blue rope halter. Any information to the innkeeper; a reward",
"of two silver pieces is offered for her safe return.",
" ",
"POSITION AVAILABLE — Captain Aldric of the town garrison seeks an experienced",
"wilderness guide for an expedition into the Darkwood. Duration: ten to fourteen",
"days. Pay is good and provisions will be supplied. Candidates must present",
"themselves at the barracks before the evening bell. Some risk is involved and",
"the captain asks that only those in sound health and good standing apply.",
" ",
"HARVEST FESTIVAL — The annual Harvest Festival will be held on the last",
"Saturday of the month. The market square will be closed to carts from dawn.",
"Stall permits must be obtained from the clerk's office no later than Thursday.",
"There will be music, a pie competition, and the traditional lantern parade at",
"dusk. All residents are warmly encouraged to attend.",
" ",
" Posted by order of the Town Council.",
" Unauthorised notices will be removed.",
]);
}
"""
bookshelf = """
fn bump(id) {
scroll([
" THE BOOKSHELF",
" ",
"A well-worn shelf packed with old volumes. You scan the spines:",
" ",
" 'Practical Herbalism and Country Remedies'",
" 'A History of the Seven Kingdoms, Vol. II'",
" 'Monsters of the Northern Reach'",
" 'The Innkeeper's Handbook'",
" 'Common Stars and Their Names'",
" 'Letters to No One in Particular' (handwritten)",
" ",
"One has a pressed flower tucked in as a bookmark.",
]);
}
"""
fireplace = """
fn bump(id) {
say("The fire crackles warmly.\\nYou feel at ease.");
}
"""
chest = """
fn bump(id) {
scroll([
" THE CHEST",
" ",
"A sturdy oak chest with iron fittings. The latch is unlocked.",
" ",
"Inside you find:",
"",
"- A wool blanket, slightly moth-eaten",
"- Three copper coins",
"- A half-empty bottle of something medicinal",
"- A child's wooden toy horse",
"- A folded letter, sealed but never sent",
]);
}
"""
yammerer = """
fn tick(dt) {
if Queue.length() == 0 {
say("blahblahblah");
delay(1);
}
}
"""
[boards.start.map]
name = "Starting Room"
width = 60
height = 25
# Layer 0 (bottom): the visual floor. Generators g/d/s roll a fresh textured
# glyph per cell; the space char is a fixed water glyph.
[[boards.start.layers]]
content = """
gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
ggggggwwwwwwgggggggggggggsggggdddddddddddddddddddddggggggggg
ggggggwwwwwwgggggggggggggsggggdddddddddddddddddddddggggggggg
ggggggwwwwwwgggggggggggggsggggdddddddddddddddddddddggggggggg
ggggggwwwwwwgggggggggggggsggggdddddddddddddddddddddggggggggg
gggggggggggggggggggggggggsggggdddddddddddddddddddddggggggggg
gggggggggggggggggggggggggsggggdddddddddddddddddddddggggggggg
gggggggggggggggggggggggggsggggdddddddddddddddddddddggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggsgggggggggggggggggggggggggggggggggg
gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
"""
[boards.start.layers.palette]
"g" = { kind = "floor", generator = "grass" }
"d" = { kind = "floor", generator = "dirt" }
"s" = { kind = "floor", generator = "stone" }
"w" = { kind = "floor", tile = "~", fg = "#6666ff", bg = "#000066" }
# Layer 1: terrain, the player, objects and the portal. A space is always a
# transparent empty cell, so the floor below shows through.
[[boards.start.layers]]
content = """
############################################################
# #
# #
# #
# #
# 1 #
# ###### B #
# # #
# +++ # #
# # #
# | #
# #
# V oo G - @ #
# /# #
# t #
# #
# >| #
# #
# - #
# ^ #
# M #
# #
# #
# #
############################################################
"""
[boards.start.layers.palette]
"#" = { kind = "wall", tile = "#", fg = "#808080", bg = "#606060" }
"+" = { kind = "banana", tile = "#", fg = "#808080", bg = "#606060" } # unknown kind -> ErrorBlock demo
"o" = { kind = "crate", tile = 254, fg = "#aaaaaa", bg = "#000000" }
"-" = { kind = "hcrate", tile = 29, fg = "#aaaaaa", bg = "#000000" }
"|" = { kind = "vcrate", tile = 18, fg = "#aaaaaa", bg = "#000000" }
">" = { kind = "pusher_east" }
"^" = { kind = "pusher_north" }
"@" = { kind = "player" }
"1" = { kind = "portal", name = "to_house", target_map = "house", target_entry = "from_start" }
"G" = { kind = "object", tile = "#", fg = "#aa3333", bg = "#000000", solid = false, script_name = "greeter" }
"V" = { kind = "object", tile = 1, fg = "#33aa33", bg = "#000000", script_name = "mover" }
"M" = { kind = "object", tile = 15, fg = "#ffdd88", bg = "#000000", solid = true, name = "muffin", script_name = "muffin" }
"B" = { kind = "object", tile = 240, fg = "#cc9944", bg = "#000000", solid = true, name = "noticeboard", script_name = "noticeboard" }
"/" = { kind = "spinner_cw" }
"t" = { kind = "gem" }
# Layer 2: a purely decorative, non-solid object drawn *above* the solid crate
# beneath it — only possible because draw order follows layer order.
[[boards.start.layers]]
sparse = [{ x = 30, y = 12, ch = "*" }]
[boards.start.layers.palette]
"*" = { kind = "object", tile = 15, fg = "#ffff66", bg = "#000000", solid = false }
[boards.house.map]
name = "The House"
width = 60
height = 25
# Layer 0: a single fixed floor glyph across the whole board.
[[boards.house.layers]]
fill = "f"
[boards.house.layers.palette]
"f" = { kind = "floor", tile = 176, fg = "#888888", bg = "#444444" }
# Layer 1: terrain, the player, objects and the return portal.
[[boards.house.layers]]
content = """
############################################################
# #
# K ###F### #
# # # #
# ####### #
# 1 #
# #
# ######### T #
# # # T #
# ######### #
# T T #
# #
# @ T #
# #
# T #
# ######C###### #
# T # # #
# ############# #
# #
# #
# #
# #
# #
# #
############################################################
"""
[boards.house.layers.palette]
"#" = { kind = "wall", tile = 178, fg = "#888888", bg = "#555555" }
"@" = { kind = "player" }
"1" = { kind = "portal", name = "from_start", target_map = "start", target_entry = "to_house" }
"K" = { kind = "object", tile = 240, fg = "#aa7733", bg = "#3d1c00", solid = true, name = "bookshelf", script_name = "bookshelf" }
"F" = { kind = "object", tile = 15, fg = "#ff8800", bg = "#220000", solid = true, name = "fireplace", script_name = "fireplace" }
"C" = { kind = "object", tile = 240, fg = "#ccaa44", bg = "#222200", solid = true, name = "chest", script_name = "chest" }
"T" = { kind = "object", tile = 1, fg = "#99ff44", bg = "#000000", solid = true, script_name = "yammerer" }