<!-- While the cellar collapses, every passage visit costs one move and undo is disabled. -->\
<!-- noTick passages are free, and so is the visit right after one (the Inventory's Return link). -->\
(if: (passage:)'s tags contains "noTick")[]\
(else-if: $free_return)[(set: $free_return to false)]\
<!-- The Buried check lives inside the tick branch: Buried is noTick, so it can't redirect to itself in a loop. -->\
(else-if: $collapsing)[(set: $moves_left to it - 1)(if: $moves_left < 0)[(goto: "Buried")]]\
<!-- No undoing out of the collapse. The sidebar is drawn before this header runs, so hide its now-dead undo icon. -->\
(if: $collapsing)[(forget-undos: -1)(replace: ?sidebar)[]]\
(if: $collapsing and not ((passage:)'s tags contains "noTick"))[(display: "CollapseStatus")]<!-- A sizing line (must contain "=") starting at the left edge makes the meter fill from the left; a centred one fills from the middle. -->\
(meter: bind $moves_left, $collapse_budget, "XXXXXXXXXXXXXXXXXXX=", "Moves left: " + (str: $moves_left), #8b1a1a)
(if: $moves_left >= 8)[''Dust trickles from the ceiling. The cellar is starting to give way.'']\
(else-if: $moves_left >= 5)[''Beams groan overhead, and cracks race across the stone.'']\
(else-if: $moves_left >= 2)[''Chunks of rock crash down around you. Hurry!'']\
(else-if: $moves_left is 1)[''The ceiling sags above you. You don't have long.'']\
(else:)[''The roof is coming down! Get out now, or you're buried.'']
---<script>pushEvent('Story', 'Finish', 'Buried')</script>\
With a final, deafening *crack*, the ceiling gives way. Stone and earth pour down around you, and the Heartstone's red glow fades beneath the rubble.
The Dark Cellar has claimed you.
(if: (saved-games:) contains "chalk")[(link: "Return to your chalk mark")[<script>pushEvent('Story', 'Load', 'chalk')</script>(load-game: "chalk")]
](link: "Try again")[(restart:)](set: $thud_lvl to 1)
(if: $lantern_lit is true)[(goto: "Crawlway1")]
You crouch in a dark tunnel, unable to see your hand in front of your face.
(display: "CurrentSoundMsg")
(if: ($has: "lantern"))[\
Light your [lantern]<lantern|.
(click: ?lantern)[\
(set: $lantern_lit to true)\
(goto: "Crawlway1")
]
]
[[Turn back->Storeroom]](set: $thud_lvl to 1)
Your lantern burns brightly.
The rock walls appear smooth, as if dug by flowing water pressure. The tunnel makes a turn up ahead out of sight.
(display: "CurrentSoundMsg")
[[Follow it.->Crawlway2]]
[[Turn back->Storeroom]](set: $thud_lvl to 2)
It takes some time to crawl through the narrow tunnel, but you make steady progress. Your lantern sputters but remains strong.
(display: "CurrentSoundMsg")
[[Continue.->Crawlway3]]
[[Turn back->Crawlway1]](set: $thud_lvl to 2)
At last the tunnel widens enough for you to nearly stand. Ahead, the floor drops away into a broad, dark cavern.
(display: "CurrentSoundMsg")
[[Climb down into the cavern->Junction]]
[[Turn back->Crawlway2]]<!-- Print the Inventory. Named so $move can (rerun:) it when items change mid-passage. -->
|footerinv>[(set: _footerItems to ($carried:))\
(if: _footerItems's length > 0)[
(if: (passage:)'s tags contains "noInvDisplay")[]\
(else:)[You are carrying (print: (joined: ", ", ...(altered: _x via ($name: _x), ..._footerItems)))]
(if: (passage:)'s tags contains "noInvLink")[]\
(else:)[Check [[inventory->Inventory]]]
]](storylet: when $collapsing)(urgency: 100)\
Not back the way you came. Up, through the drained shaft, and out!(storylet: when $wheel_stuck)(urgency: 60)\
In the room of pipes, iron has bitten iron. Strike it, and it will let go.(storylet: when not $wheel_stuck and not $cistern_drained)(urgency: 50)\
The still water waits for a wheel to turn it.(storylet: when $cistern_drained and not ((history:) contains "Echo Fork"))(urgency: 40)\
Below the water, the plate hungers for weight. Feed it something heavy.(storylet: when $inspected's length < 3 and not $heart_door_open)(urgency: 30)\
Marks are scratched and carved where the water ran and the wine was kept. Have you looked closely at them all?(storylet: when not $heart_door_open)(urgency: 20)\
Count the notches. Each one names a dial.(storylet: when $heart_door_open and $where's heartstone is "Heart Chamber")(urgency: 10)\
The door stands open. The heart is waiting for you.(storylet: when true)(urgency: -1)\
<!-- Always open, lowest urgency, so (open-storylets:) is never empty. -->\
Only the heartbeat answers.<!-- The Return link is a new passage visit; make it free so checking your bag never costs a move. -->\
(set: $free_return to true)\
(set: _items to ($carried:))\
(if: _items's length is 0)[You are carrying nothing.]\
(else:)[You are carrying:\
<ul>(for: each _id, ..._items)[<li>(link-repeat: ($name: _id))[(replace: ?desc)[(display: _id + "-item")]]</li>]</ul>]
|desc>[]
(link-goto: "Return", (history:)'s last)A copper, hooded lantern with a small oil burner, which easily illuminates a room. It appears to have plenty of oil.An old, rusted iron key.A solid iron sledgehammer.A fist-sized red gem with a low luminescence in its core. The stone is warm to the touch and pulses and jitters in your hand.A heavy cast-iron valve wheel, flaked with rust. Its square socket looks made to fit a valve stem.A coarse burlap sack packed tight with damp sand. It is very heavy.(set: $thud_lvl to 2)
The crawlway opens into a wide natural cavern. Water has carved the walls into smooth, rippling folds. The heartbeat is clearer here, rising from somewhere below.
(display: "CurrentSoundMsg")
To one side, a [[low doorway->Pump Room]] leads into a room full of pipes. Opposite it, a [[brick archway->Cistern]] smells of standing water.
<!-- Listening wall: shows the most urgent open storylet tagged "hint" (src/story/hints.tw). -->\
The far wall is cracked and hollow, and the heartbeat seems loudest there. (link-repeat: "Press your ear to the wall")[(replace: ?whisper)[You press your ear to the cold stone. A whisper rides the heartbeat: //(display: (open-storylets:)'s 1st's name)//]]
|whisper>[]
<!-- Save point. Disabled during the collapse, so a save can never capture a doomed position. -->\
(if: $collapsing)[The chalk mark on the wall has vanished under a layer of fallen dust.]\
(else:)[Someone has drawn a fresh (link-repeat: "chalk mark")[(replace: ?saveresult)[(if: (save-game: "chalk", "Junction"))[<script>pushEvent('Story', 'Save', 'chalk')</script>You trace over the chalk mark with your finger. If the worst happens, you can find your way back here.](else:)[You trace over the chalk mark, but it smudges away. (Your browser blocked saving.)]]] on the wall.]
|saveresult>[]
(if: $collapsing)[The crawlway behind you has collapsed into a wall of rubble.]\
(else:)[[[Climb back up the crawlway->Crawlway3]]](set: $thud_lvl to 2)
Rusted pipes crowd this low room, running from a great iron hand-pump into the wall toward the cistern. Water drips steadily from a cracked joint overhead.
|wheelspot>[(if: $wheel_stuck)[A (link-repeat: "valve wheel")[(replace: ?wheelresult)[($useOn: "the rusted valve wheel", (dm: "hammer", "use-hammer-wheel"), "You heave at the wheel, but it is rusted solid to the pipe.")(rerun: ?wheelspot)]] is rusted onto the end of a dead pipe.]]
|wheelresult>[]
(if: $where's sandbag is "Pump Room")[A sandbag slumps beneath the dripping joint.]<sandbag|
(click-replace: ?sandbag)[You heave the sandbag onto your shoulder.($move: "sandbag", "player")]
Scratched into the pump housing is a ($reveal: "pump-mark", "mark", ": ''a single notch beside a wavy line''").
(display: "CurrentSoundMsg")
[[Back to the cavern->Junction]]<script>pushEvent('Story', 'Puzzle', 'wheel')</script>\
(set: $wheel_stuck to false)($move: "valve-wheel", "player")\
*Clang!* The rust gives way, and the valve wheel drops into your hands.(set: $thud_lvl to 2)
|cisternspot>[(if: not $cistern_drained)[Black water fills this vaulted brick tank to chest height. Its surface trembles faintly with every heartbeat. An empty (link-repeat: "valve stem")[(replace: ?cisternresult)[($useOn: "the valve stem", (dm: "valve-wheel", "use-wheel-stem"), "That doesn't fit the square stem.")(rerun: ?cisternspot)]] pokes out of the wall beside the archway.]\
(else:)[The drained tank drips and echoes. Silt coats the brick floor. A flight of stone stairs, hidden until now, leads [[down into the dark->Weighing Room]]. Above, iron rungs climb a narrow [[drain shaft->Wine Cellar]].
Scratched into the floor of the tank is a ($reveal: "cistern-mark", "mark", ": ''two notches beside a branching root''").]]
|cisternresult>[]
(display: "CurrentSoundMsg")
[[Back to the cavern->Junction]]<script>pushEvent('Story', 'Puzzle', 'cistern')</script>\
($move: "valve-wheel", "gone")(set: $cistern_drained to true)\
You fit the valve wheel onto the stem and heave. It turns with a groan, and somewhere below, a sluice opens. With a deep gurgle, the water drains away.(set: $thud_lvl to 3)
A square chamber of fitted stone. An iron portcullis bars the passage onward, and a broad pressure plate is set into the floor before it.
<!-- The portcullis is open while any item rests here (on the plate); there is no separate flag. -->\
|platespot>[(set: _onPlate to (find: _x where $where's (_x) is "Weighing Room", ...(dm-names: $where)))\
(if: _onPlate's length is 0)[The (link-repeat: "pressure plate")[(replace: ?plateresult)[\
<!-- Any carried item tagged "heavy" works. -->\
(set: _heavy to (dm:))\
(for: each _x, ...($carried:))[(if: (passage: _x + "-item")'s tags contains "heavy")[(set: _heavy to it + (dm: _x, "use-plate"))]]\
($useOn: "the pressure plate", _heavy, "You set it on the plate, but nothing happens. It needs something heavier.")(rerun: ?platespot)]] sits level with the floor. The portcullis is down.]\
(else:)[The (print: ($name: _onPlate's 1st)) rests on the sunken pressure plate, and the portcullis hangs raised on its chains. (link-repeat: "Take back the " + ($name: _onPlate's 1st))[(replace: ?plateresult)[($move: _onPlate's 1st, "player")The plate rises, and the portcullis crashes down.(rerun: ?platespot)]]
[[Duck under the portcullis->Echo Fork]]]]
|plateresult>[]
(display: "CurrentSoundMsg")
[[Climb the stairs->Cistern]]<!-- Counted until the player first goes through the portcullis; later re-weighting is not a new solve. -->\
(unless: (history:) contains "Echo Fork")[<script>pushEvent('Story', 'Puzzle', 'plate')</script>]\
($move: $used_item, "Weighing Room")\
You set the (print: ($name: $used_item)) on the plate. It sinks with a heavy ''clunk'', and the portcullis grinds upward on its chains.(set: $thud_lvl to 3)
Beyond the portcullis, the passage splits into rough-cut tunnels that all look the same. The heartbeat echoes off every surface.
(display: "CurrentSoundMsg")
(if: ($has: "heartstone"))[The Heartstone glows brightest when you face the portcullis.]\
(else:)[From the left tunnel, the beat comes softly, smothered by stone. From the right tunnel, it rings sharp and close.]
[[Take the left tunnel->Echo Bend]]
[[Take the right tunnel->Echo Door]]
[[Back under the portcullis->Weighing Room]](set: $thud_lvl to 2)
The tunnel bends and narrows. The heartbeat is quieter here.
(display: "CurrentSoundMsg")
(if: ($has: "heartstone"))[The Heartstone dims in your hand. This is the wrong way.]\
(else:)[Ahead, the beat fades further still.]
[[Press on->Echo Hollow]]
[[Go back->Echo Fork]](set: $thud_lvl to 1)
A low, dead-end hollow. The heartbeat is barely a murmur. A crack in the far wall curls back the way you came.
(display: "CurrentSoundMsg")
[[Squeeze through the crack->Echo Fork]]
[[Go back->Echo Bend]](set: $thud_lvl to 4)
The tunnel ends at a stone edifice set with a worn [wooden door]<wooden|. Dull red light leaks from beneath it.
(click: ?wooden)[On closer inspection, the door has many thin spindle patterns inlaid in the wood. It once had a lacquer finish and a golden handle, but has since decayed from misuse.]
(display: "CurrentSoundMsg")
(if: ($has: "heartstone"))[The Heartstone flares when you face the tunnel behind you.]
<!-- (cycling-link: bind) resets the variable to its first string on every render, so each dial's
list must start at its current value, or the dials reset whenever the player returns.
(rotated:) can't do this: it rejects a rotation of 0. -->\
|heartdoor>[(set: _from to (dm:
"moon", (a: "moon", "root", "wave", "flame"),
"root", (a: "root", "wave", "flame", "moon"),
"wave", (a: "wave", "flame", "moon", "root"),
"flame", (a: "flame", "moon", "root", "wave"),
))\
(if: not $heart_door_open)[Three brass dials are set into the door, each engraved with a moon, a root, a wave, and a flame.
First dial: |dial1>[(cycling-link: bind $dial1, ...(_from's ($dial1)))]
Second dial: |dial2>[(cycling-link: bind $dial2, ...(_from's ($dial2)))]
Third dial: |dial3>[(cycling-link: bind $dial3, ...(_from's ($dial3)))]
(link-repeat: "Push the door")[(replace: ?heartdoorresult)[(if: $dial1 is "wave" and $dial2 is "root" and $dial3 is "flame")[<script>pushEvent('Story', 'Puzzle', 'dials')</script>(set: $heart_door_open to true)The dials click into place, and the door swings inward.](else:)[The door holds fast.](rerun: ?heartdoor)]]]\
(else:)[The wooden door stands open. [[Open the door.->Heart Chamber]]]]
|heartdoorresult>[]
[[Back down the tunnel->Echo Fork]](set: $thud_lvl to 4)
Behind the door is a small antechamber with rough-hewn stone covering the walls and floor. In each corner is a \
sconce with a luminous crystal casting red light across the floor.
(if: $where's heartstone is "Heart Chamber")[\
In the center is a stone pedestal with a fist-sized blood red gem. Its facets seem to shift and \
reverberate with the sound.
(display: "CurrentSoundMsg")
Take the Heartstone\
]<heartstone|\
(else:)[\
(display: "CurrentSoundMsg")
]
[[Flee->Echo Door]]\
(click: "Take the Heartstone")[\
<script>pushEvent('Story', 'Heartstone', 'Take')</script>\
($move: "heartstone", "player")\
(set: $collapsing to true)(forget-undos: -1)(replace: ?sidebar)[]\
(replace: ?heartstone)[\
---
The gem feels heavy, and warm in your hand. It seems to jostle and shake of its own accord.
Suddenly, the pulse quickens, slamming your mind with incessant pressure. Somewhere far behind you, the crawlway collapses with a roar. You must leave!
(display: "CurrentSoundMsg")
]\
]<!-- Print current sound level message -->\
(if: $where's heartstone is "Heart Chamber")[(print: $sound_msgs's ($thud_lvl + 1))]\
(else:)[(print: $panic_msgs's ($thud_lvl))]{
<!-- Set up Initial Variables -->\
<script>pushEvent('Story', 'Start', '');</script>\
\
<!-- Item locations: "player", a passage name, or "gone". Single source of truth for every item. -->\
<!-- Item IDs are hyphenated; each has an "<id>-item" description passage tagged "item". -->\
(set: $where to (dm:
"lantern", "player",
"rusty-key", "player",
"hammer", "Storeroom",
"valve-wheel", "Pump Room",
"sandbag", "Pump Room",
"heartstone", "Heart Chamber",
))\
\
<!-- Item helpers -->\
<!-- $move also reruns the footer's inventory list so it stays current when items change mid-passage. -->\
(set: $move to (macro: str-type _id, str-type _loc, [(output:)[(set: $where's (_id) to _loc)(rerun: ?footerinv)]]))\
(set: $has to (macro: str-type _id, [(output-data: $where's (_id) is "player")]))\
(set: $carried to (macro: [(output-data: (find: _x where $where's (_x) is "player", ...(dm-names: $where)))]))\
(set: $name to (macro: str-type _id, [(output-data: (str-replaced: "-", " ", _id))]))\
\
<!-- ($useOn: target, outcomes, [fallback]) -->\
<!-- Opens a dialog listing carried items. outcomes maps item ID -> passage to (display:) when that item is chosen. -->\
<!-- Any other item prints the fallback message, or "Nothing happens." Cancel prints nothing. -->\
<!-- Before an outcome passage is displayed, $used_item holds the chosen item ID, so one passage can serve several items. -->\
<!-- Note: a blocking (dialog:) breaks (else:) chains around it, so use separate (if:)s, not (if:)/(else:). -->\
(set: $useOn to (macro: str-type _target, dm-type _outcomes, ...str-type _fallback, [(output:)[\
(set: _items to ($carried:))\
(if: _items's length is 0)[(dialog: "You have nothing to use on " + _target + ".")]\
(if: _items's length > 0)[\
(set: _choice to "Cancel")\
(dialog: bind _choice, "Use what on " + _target + "?", ...(altered: _x via ($name: _x), ..._items), "Cancel")\
(unless: _choice is "Cancel")[\
(set: _id to (find: _x where ($name: _x) is _choice, ..._items)'s 1st)\
(if: _outcomes contains _id)[(set: $used_item to _id)(display: _outcomes's (_id))]\
(else-if: _fallback's length > 0)[(print: _fallback's 1st)]\
(else:)[Nothing happens.]\
]]]]))\
\
(set: $used_item to "")\
\
<!-- ($reveal: id, label, detail) -->\
<!-- Prints a clickable label; clicking it appends the detail and records the id in $inspected. -->\
<!-- Once inspected, it renders label + detail with no link, on every later visit. -->\
(set: $inspected to (a:))\
(set: $reveal to (macro: str-type _id, str-type _label, str-type _detail, [(output:)[\
(if: $inspected contains _id)[(print: _label + _detail)]\
(else:)[(link-reveal: _label)[(set: $inspected to it + (a: _id))(print: _detail)]]\
]]))\
\
<!-- World state -->\
(set: $door_locked to true)\
(set: $wall_intact to true)\
(set: $wheel_stuck to true)\
(set: $cistern_drained to false)\
(set: $wine_door_bolted to true)\
(set: $heart_door_open to false)\
(set: $dial1 to "moon")\
(set: $dial2 to "moon")\
(set: $dial3 to "moon")\
(set: $lantern_lit to false)\
(set: $thud_lvl to 1)\
\
<!-- Collapse timer: starts when the Heartstone is taken. See CollapseTick. -->\
(set: $collapsing to false)\
(set: $collapse_budget to 10)\
(set: $moves_left to $collapse_budget)\
(set: $free_return to false)\
\
(set: $sound_msgs to (a:
"",
"You feel slight tremors in the rock beneath your feet.",
"A faint but deep throbbing sound reaches you through the rock.",
"The throbbing sound comes from the rock all around you, permeating your thoughts.",
"*Bu-dum* *Bu-dum*. The walls themselves scream at you with a deafening cacophony.",
))\
(set: $panic_msgs to (a:
"",
"The low thudding is faint now.",
"The beating sound is more distant now. You still feel it in your feet, but can hear your thoughts again.",
"Panicked thudding echoes and shakes the tunnel behind you.",
"*Bu-dum-dum* *Bu-dum-dum*. The rising thrumming shakes the walls, which shower you in gravel in protest.",
))
}You stand at the bottom of a ladder into a dark cellar.
The air smells stale and dusty, as if it hasn't been moved in years.
<!-- Hotspot pattern: the hook is rerun after every use, so it always reflects current world state. -->\
|doorspot>[(if: $door_locked is true)[There is a (link-repeat: "door")[(replace: ?doorresult)[($useOn: "the iron lock", (dm: "rusty-key", "use-key-door"), "The door is locked and requires a key.")(rerun: ?doorspot)]] with a small, iron lock.]\
(else:)[There is an unlocked [[door->Storeroom]].]]
|doorresult>[]
(if: $wine_door_bolted)[A heavy door on the far wall is bolted from the other side.]\
(else:)[A [[heavy door->Wine Cellar]] on the far wall stands unbolted.]
(if: ($has: "heartstone"))[[[Escape->Escape]] with the Heartstone!]
<!-- Continue from a chalk-mark save, offered until the player first goes through to the Storeroom. -->\
(if: (saved-games:) contains "chalk" and not ((history:) contains "Storeroom"))[(link: "Return to your chalk mark")[<script>pushEvent('Story', 'Load', 'chalk')</script>(load-game: "chalk")]]<script>pushEvent('Story', 'Puzzle', 'door')</script>\
($move: "rusty-key", "gone")(set: $door_locked to false)\
You unlock the door with the Rusty Key.You stand in a musky Storeroom. The walls are lined with casks and barrels filled with long-forgotten wine.
(if: $where's hammer is "Storeroom")[There is a hammer resting on the table.]<hammer|
(click-replace: ?hammer)[You take the hammer.\
<script>pushEvent('Story', 'Hammer', 'Take')</script>\
($move: "hammer", "player")\
]
|wallspot>[(if: $wall_intact is true)[Some of the (link-repeat: "bricks")[(replace: ?wallresult)[($useOn: "the loose bricks", (dm: "hammer", "use-hammer-bricks"), "The brick wall sounds hollow, but you cannot budge it with your bare hands.")(rerun: ?wallspot)]] in the wall look loose.]\
(else-if: $collapsing)[Rubble chokes the passage behind the broken wall. The crawlway has collapsed.]\
(else:)[The broken wall reveals a [[dark passage->Crawlway1-dark]].]]
|wallresult>[]
There is a [[door->Entrance]] back to the entrance.<script>pushEvent('Story', 'Puzzle', 'bricks')</script>\
(set: $wall_intact to false)\
*Slam* Bricks fly and crumble under your hammer.(set: $thud_lvl to 1)
A long, vaulted wine cellar. Racks of dusty casks line both walls, their labels long since rotted away. In the floor, iron rungs lead down a narrow drain shaft.
Cut into the end of one rack is a ($reveal: "wine-mark", "vintner's mark", ": ''three notches beside a small flame''").
|winespot>[(if: $wine_door_bolted)[A heavy door at the far end is bolted from this side. (link-repeat: "Draw the bolt")[(replace: ?wineresult)[<script>pushEvent('Story', 'Puzzle', 'bolt')</script>(set: $wine_door_bolted to false)You draw back the stiff iron bolt with a screech.(rerun: ?winespot)]]]\
(else:)[The heavy [[door->Entrance]] at the far end stands unbolted.]]
|wineresult>[]
(display: "CurrentSoundMsg")
[[Climb down the shaft->Cistern]]<script>pushEvent('Story', 'Finish', 'Escape')</script>\
You climb out into the night air and run swiftly from the rickety house, still swaying in the wind like a dying animal.
You clutch the Heartstone tightly to your chest. You feel its warmth, and try to forget the Dark Cellar you've left behind.
You Win!Brandon Risberg