327 lines
13 KiB
TOML
327 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(me, state) {
|
|
log(`hello from object — player at ${state.player.x}, ${state.player.y}`);
|
|
set_tile(2); // change my glyph to ☻ — proves the write path
|
|
say("Hello there,\\ntraveller!");
|
|
log(`Player health: ${state.player.health}`);
|
|
}
|
|
|
|
fn tick(me, state, dt) {
|
|
if state.player.x == me.x && state.player.y == me.y && !me.waiting {
|
|
say("Hey! Get offa me!");
|
|
me.delay(5.0);
|
|
}
|
|
}
|
|
"""
|
|
|
|
mover = """
|
|
fn init(me, state) {
|
|
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(me, state, dt) {
|
|
if !me.waiting { dance(me); }
|
|
}
|
|
fn dance(me) {
|
|
move(East);
|
|
move(South);
|
|
move(North);
|
|
move(East);
|
|
say("Hey!", 0.5);
|
|
delay(me, 0.5);
|
|
move(West);
|
|
move(South);
|
|
move(North);
|
|
move(West);
|
|
say("Ho!", 0.5);
|
|
me.delay(0.5);
|
|
}
|
|
// Fires when something steps into this object; id is the bumper's object id,
|
|
// or -1 for the player.
|
|
fn bump(me, state, id) {
|
|
log(`mover bumped by ${id}`);
|
|
say("Ow!");
|
|
}
|
|
"""
|
|
|
|
muffin = """
|
|
fn bump(me, state, _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(me, state) {
|
|
say("Yeah it was poisoned.");
|
|
alter_health(-2);
|
|
}
|
|
fn ignore() {
|
|
log("You walk away from the muffin. Wise.");
|
|
say("Suspicious...");
|
|
}
|
|
"""
|
|
|
|
noticeboard = """
|
|
fn bump(me, state, 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.",
|
|
" Unauthorized notices will be removed.",
|
|
]);
|
|
}
|
|
"""
|
|
|
|
bookshelf = """
|
|
fn bump(me, state, 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(me, state, id) {
|
|
say("The fire crackles warmly.\\nYou feel at ease.");
|
|
}
|
|
"""
|
|
|
|
chest = """
|
|
fn bump(me, state, 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(me, state, dt) {
|
|
if !me.waiting {
|
|
say("blahblahblah");
|
|
delay(1);
|
|
}
|
|
}
|
|
"""
|
|
|
|
shifter = """
|
|
fn tick(me, state, dt) {
|
|
let x = me.x;
|
|
let y = me.y;
|
|
|
|
if !me.waiting {
|
|
shift([[x-1, y], [x, y-1], [x+1, y], [x, y+1]]);
|
|
delay(0.25);
|
|
}
|
|
}
|
|
"""
|
|
|
|
[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 = """
|
|
############################################################
|
|
# #
|
|
# o #
|
|
# oS #
|
|
# #
|
|
# 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" }
|
|
"S" = { kind = "object", tile = 240, fg = "#cc9944", bg = "#000000", solid = true, name = "shifter", script_name = "shifter" }
|
|
"/" = { 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" }
|
|
|