Files
website-cv/js/quest.js
T
2026-08-09 23:42:23 +02:00

1025 lines
51 KiB
JavaScript

/* The Quest for the Deleted Website (quest.html only).
The quest survives reloads (and even restoring the website): the save
file is questHero + questPronouns (JSON) + questWeapon + questHand +
questEncounters (JSON) + questEnc1 (JSON) + questEnc2 + questKid +
questEnc3 + questEnc4 + questEnc5 + questPrincess + questWeaponLost +
questVillain + questVillainPronouns (JSON) + questAttacked in
localStorage.
All story text lives in TEXT, written in full with {token} substitutions.
Tokens: {name} plus the pronoun forms {subj} {obj} {posd} {refl}.
Capitalize the token to capitalize the substitution: {Subj} -> "She" */
(function () {
var naming = document.getElementById('naming');
if (!naming) return;
var TEXT = {
intro: '{name} was but a simple farmer living in the magical kingdom of' +
' Grazaikya, until one day when gade.gg was deleted.',
setout: '{name} had wanted to log onto gade.gg, {posd} favorite website, but saw' +
' that it had been deleted, presumably by an evil, heartless monster.' +
' So {subj} picked up {posd} preferred weapon, and embarked on a quest' +
' to find the deleted website.',
traverse: 'Clutching {posd} {weapon} in {posd} {hand} hand, {name}' +
' traversed across the lands of Grazaikya, determined to recover the' +
' deleted site.',
enc1: '{name} attempted to cross a bridge over a river, but was' +
' accosted by a hideous creature. A bridge troll stopped {obj} and' +
' said "Before you may cross the river, you must first answer my' +
' riddle!".',
enc1riddle: '"Very well, then", said {name}, "tell me your riddle,' +
' hideous beast". "Wow, rude" said the troll, aghast. It then stood' +
' for a moment, waiting for an apology that never came, and then' +
' continued: "I run, but never walk; I babble, but never talk. What' +
' am I?".',
enc1attack: '{name} {attacked} the troll{withweapon}, but the' +
' troll attacked back, ripping off {posd} leg. {name} {attacked} the' +
' troll one more time, which ended its life. {name} hobbled away.',
enc1wrong: '"{answer}?" asked {name}, unsure of {refl}. "Nope", said' +
' the troll, picking up {name} above its head. With a horrible' +
" sound, the troll ripped off {name}'s leg, and threw {obj} across" +
' to the other side of the bridge. {name} hobbled away from the' +
' troll, who was laughing triumphantly.',
enc1correct: '"A river!" said {name}. "Yeah, that\'s right!", answered' +
' the troll, "you\'re, like, super smart!". "Now let me pass, hideous' +
' beast", demanded {name}. The troll obliged, despite being pretty' +
' hurt by the name-calling. {name} continued onwards on {posd} quest.',
enc2: 'While walking on a path through grassy fields, a young boy, no' +
' older than 16, ran up to {name}. "Are you an adventurer? Are you' +
' on a quest? Can I join?", the kid asked excitedly.',
enc2yes: '"Why, certainly. The more the merrier!", said {name},' +
' cheerfully. The kid jumped up and twirled around in the air.' +
' "You won\'t regret this!", he said, foreshadowingly, "My name\'s' +
' Breigan!". Breigan and {name} continued on their quest.',
enc2no: '"Shouldn\'t you be with your parents, kid?", asked {name}.' +
' The boy lowered his head and looked at the ground.' +
' "I don\'t have parents", he said, "not since the fire". He then' +
' slowly walked away, sulking, leaving {name} to continue {posd}' +
' quest alone.',
enc3: 'At nightfall, {name} came across an abandoned cottage. Feeling' +
' tired, {subj} decided to use it for shelter for the night. Inside' +
' the cottage, {name} saw a seemingly untouched chest amongst the' +
' rubble. {Subj} tried to open it, but it was locked.',
enc3pryBtn: 'Pry it open with your {weapon}',
enc3pry: '{name} attempted to force the chest open with {posd}' +
' {weapon}. After a few tries, the chest broke open, revealing a' +
' horrifying row of teeth inside. The mimic lunged forward towards' +
' {name}, who, in {posd} panic, let go of {posd} {weapon}. {name}' +
' left the cottage, continuing the quest without {posd} {weapon}.',
enc3leave: '"Better to leave things like that alone", {name} thought.' +
" {Subj} had a good night's rest in the cottage, and continued" +
' onwards on {posd} quest in the morning.',
enc4: 'While travelling along a road, {name} met an old man selling' +
' potions. "Potionseller!", {subj} said, "I am going into battle,' +
' and I need your strongest potions". "Well", the old man answered,' +
' "my strongest potions are quite expensive. Do you have the coin?".' +
' {name} did, in fact, not have any money.',
enc4steal: '{name} {attacked} the potionseller{withweapon}, and took' +
' one of his potions. Once {subj} was far enough away, {subj} drank' +
' it. Suddenly, {subj} could feel {posd} body changing: {posd} limbs' +
' shrinking and {posd} nose embiggening. Suddenly, {name} found' +
' {refl} in the body of a pig. {Subj} sulked for a bit, and then' +
' continued onwards on {posd} quest, as a pig.',
enc4explain: '"I have no money", {name} said, "but if you-", {subj}' +
' continued, but before {subj} could finish, the potionseller spat' +
' in {posd} face and said "piss off, poor-y!". {name} continued' +
' onwards on {posd} quest, potionless.',
enc5: '{name} was walking along a road when {subj} passed a tower' +
' standing by the path. A beautiful young woman stuck her head out' +
' of the tallest window and shouted at {name}, "Oi! Are you here to' +
' rescue me?". Flustered, {name} answered "I wasn\'t planning on' +
' it. Are you a princess or something?". "Yeah, probably", said the' +
' likely princess.',
enc5decline: '"Actually, I\'m quite busy", said {name}, walking away.' +
' "Aw, come on?", the probable princess asked. "No no, I simply' +
' must go", replied {name}, already too far away to hear whatever' +
' the potential princess said next.',
enc5agree: '"All right, then", said {name}, "I\'m sure saving you' +
' won\'t take too much time". {Subj} looked at {posd} options.',
enc5vines: '{name} started climbing up the side of the tower,' +
' grabbing on to the vines. The probable princess looked puzzled:' +
' "You know the door is unlocked, right?". {name}, already out of' +
' breath, replied "No, I\'ve committed now!". {Subj} had climbed up' +
' roughly 30 cm and was already straining all of {posd} muscles to' +
' hang on to the vines. "Seriously", said the princess, worried,' +
' "you should really just take the door". {name} lost {posd} grip' +
' on the vines and tumbled to the ground. Embarrassed, {subj}' +
' quickly ran away, continuing {posd} quest.',
enc5door: '{name} walked up to the front door, expecting it to be' +
' locked. It was not. {Subj} then walked up the spiral staircase,' +
' expecting to be jumped by a monster or something. {Subj} was not.' +
" Finally, {subj} reached the potential princess' door, which was" +
' already open. "I\'m confused", said {name}, "What did you need' +
' saving from?". "Boredom, mainly", replied the' +
' now-not-quite-so-likely princess. "I\'m Anastasia, by the way",' +
' she said, while walking down the stairs. Before {name} could' +
' protest, Anastasia had already joined {posd} quest.',
princessrename: "{name} didn't like Anastasia's name, so {subj}" +
' started calling her {princess} instead.',
kidrename: "{name} didn't like Breigan's name, so {subj} started" +
' calling him {kid} instead.',
arrival: '{name} arrived at the tower of the evil wizard {subj} had' +
' heard was behind the deletion of gade.gg, {posd} favorite website.',
confront: '{name} went inside the tower, seeing the massive dark' +
' gothic interior. There, sitting on a throne, was {vname}.' +
' "I suspect you have come to kill me", {vsubj} said, "for deleting' +
' gade.gg, your favorite website."'
};
/* The showdown endings, one handwritten text per situation. Key:
chosen encounters' 1-based pool positions, a colon, then one S/F
letter each, all in pool order — '123:SFS' = troll+kid+mimic with
only the kid failed. Success is: troll = riddle solved, Breigan = joined,
mimic = chest left alone. The wizard is only beatable with >= 2 S.
Villain tokens: {vname} {vsubj} {vobj} {vposd} {vrefl}.
Empty entries render nothing */
var ENDINGS = {
'123:SSS': '{name} ran towards {vname}, {attacking} {vobj} with {posd}' +
' {weapon}. {kid} came up behind {vname}, pushing {vobj}, and' +
' making {vobj} lose {vposd} balance. {vname} tried to cast a spell' +
' at either of them, but it was too late. {name} and {kid} killed' +
' {vname}, restoring the website for good.',
'123:SSF': '{name} and {kid} ran towards {vname}, ready to punch {vobj}.' +
' With a flick of {vposd} wrist, {vname} cast a spell on {kid},' +
' disintegrating him immediately. {name} yelled out towards him, but' +
' there was nothing {subj} could do. Nothing, except avenge him.' +
' {name} ran up to {vname} and delivered a powerful punch. A punch' +
' so powerful that {vposd} head exploded. {vname} was dead, and the' +
' website was restored for good.',
'123:SFS': '{name} ran towards {vname}. An epic duel commenced, with {vname}' +
' throwing spells and {name} {attacking} with {posd} {weapon}.' +
' Finally, when the dust settled, {name} stood victorious. {vname}' +
' was dead, and the website was restored for good.',
'123:SFF': '{name} ran towards {vname}, ready to punch {vobj}. With a flick' +
' of {vposd} wrist, {vname} cast a spell on {name}, disintegrating' +
' {obj} immediately.',
'123:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with {posd}' +
' {weapon}. {kid} came up behind {vname}, pushing {vobj}, and' +
' making {vobj} lose {vposd} balance. {vname} tried to cast a spell' +
' at either of them, but it was too late. {name} and {kid} killed' +
' {vname}, restoring the website for good.',
'123:FSF': '{name} hobbled towards {vname}, ready to punch {vobj}. With a' +
' flick of {vposd} wrist, {vname} cast a spell on {kid},' +
' disintegrating him immediately. {name} yelled out towards him, but' +
' there was nothing {subj} could do. With another flick of {vposd}' +
' wrist, {vname} cast the same spell on {name}, disintegrating {obj}' +
' as well.',
'123:FFS': '{name} hobbled towards {vname}, {attacking} {vobj} with {posd}' +
' {weapon}. With a flick of {vposd} wrist, {vname} cast a spell on' +
' {name}, disintegrating {obj} immediately.',
'123:FFF': '{name} hobbled towards {vname}, ready to punch {vobj}. With a' +
' flick of {vposd} wrist, {vname} cast a spell on {name},' +
' disintegrating {obj} immediately.',
/* Family 124 (troll, Breigan, potion): the one-legged pigs. The
other six situations are aliased below */
'124:FSF': '{name} hobbled towards {vname} on {posd} three remaining' +
' trotters, {posd} {weapon} clenched in {posd} pig mouth, with' +
' {kid} running ahead. With a flick of {vposd} wrist, {vname} cast' +
' a spell on {kid}, disintegrating him immediately. {name} let out' +
' a devastated squeal. With another flick of {vposd} wrist, {vname}' +
' cast the same spell on {name}, disintegrating {obj} as well.',
'124:FFF': '{name} hobbled towards {vname} on {posd} three remaining' +
' trotters, {attacking} {vobj} with {posd} {weapon}. {vname}' +
' watched the limping pig approach for a while, mildly fascinated.' +
' Then, with a flick of {vposd} wrist, {vsubj} cast a spell on' +
' {name}, disintegrating {obj} immediately.',
/* Family 134 (troll, mimic, potion): no Breigan, so the win
threshold lands differently — same body, different fate. The
three overlapping-outcome situations are aliased below */
'134:SSF': '{name} charged towards {vname}, clutching {posd} {weapon}' +
' in {posd} pig mouth. {vname} laughed at the sight, flicking' +
' {vposd} wrist to cast a spell. But the spell missed: {vname} had' +
' never fought a pig before, and pigs are much lower to the ground' +
' than the heroes {vsubj} was used to. {name} {attacked} {vobj}' +
' before {vsubj} could try again. {vname} was dead, and the website' +
' was restored for good.',
'134:SFS': '{name} ran towards {vname}, ready to punch {vobj}.' +
' {vname} flicked {vposd} wrist and cast a spell, but {name} dodged' +
' it and kept running. {Subj} reached the throne and delivered a' +
' powerful punch. A punch so powerful that {vposd} head exploded.' +
' {vname} was dead, and the website was restored for good.',
'134:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}. An epic duel commenced, with {vname} throwing' +
' spells and {name} deflecting them on one leg. Finally, when the' +
' dust settled, {name} stood victorious. {vname} was dead, and the' +
' website was restored for good.',
'134:FFS': '{name} hobbled towards {vname}, ready to punch {vobj}.' +
' {vname} watched {posd} slow approach with something between pity' +
' and boredom. With a flick of {vposd} wrist, {vname} cast a spell' +
' on {name}, disintegrating {obj} immediately.',
'134:FFF': '{name} hobbled towards {vname} on {posd} three remaining' +
' trotters, ready to bite {vobj}. {vname} waited politely for the' +
' pig to arrive. Then, with a flick of {vposd} wrist, {vsubj} cast' +
' a spell on {name}, disintegrating {obj} immediately.',
/* Family 234 (Breigan, mimic, potion): pig situations. The human
ones are aliased from family 123 below */
'234:SSF': '{name} charged towards {vname}, clutching {posd} {weapon}' +
' in {posd} pig mouth. {vname} hesitated. {Vsubj} had prepared for' +
' many things, but not for a pig with {aweapon}. {kid} used the' +
' moment to come up behind {vname}, pushing {vobj} and making {vobj}' +
' lose {vposd} balance. {name} {attacked} {vobj} before {vsubj}' +
' could get back up. {vname} was dead, and the website was restored' +
' for good.',
'234:SFF': '{kid} ran towards {vname}, ready to punch {vobj}, with' +
' {name} trotting closely behind. With a flick of {vposd} wrist,' +
' {vname} cast a spell on {kid}, disintegrating him immediately.' +
' {name} let out a devastated squeal. With another flick of {vposd}' +
' wrist, {vname} cast the same spell on {name}, disintegrating {obj}' +
' as well.',
'234:FSF': '{name} trotted towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}. {vname} was briefly impressed by the sight of a' +
' pig wielding {aweapon}, but not enough to be stopped. With a' +
' flick of {vposd} wrist, {vname} cast a spell on {name},' +
' disintegrating {obj} immediately.',
'234:FFF': '{name} trotted towards {vname}, ready to bite {vobj}.' +
' {vname} looked at the pig for a long moment, almost feeling sorry' +
' for it. Then, with a flick of {vposd} wrist, {vsubj} cast a spell' +
' on {name}, disintegrating {obj} immediately.',
/* Family 345 (mimic, potion, princess): Anastasia situations. The
princess-less four are aliased below */
'345:SSS': '{name} ran towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}. {vname} blocked the attack with a shield spell' +
' and began preparing a counterattack. While the wizard was busy,' +
' {princess} calmly walked up behind {vobj} and kicked {vobj} off' +
' the throne. {name} {attacked} {vobj} one final time before' +
' {vsubj} could get up. {vname} was dead, and the website was' +
' restored for good.',
'345:SFS': '{name} charged towards {vname}, clutching {posd} {weapon}' +
' in {posd} pig mouth. "Is that a pig?", asked {vname}, bewildered.' +
' "I\'m honestly as confused as you are", answered {princess},' +
' already walking up behind the throne. Before {vname} could figure' +
' out what was going on, {princess} pushed {vobj} to the ground,' +
' and {name} {attacked} {vobj}. {vname} was dead, and the website' +
' was restored for good.',
'345:FSS': '{name} ran towards {vname}, ready to punch {vobj}.' +
' {vname} flicked {vposd} wrist and cast a spell at {name}, but' +
' {princess} pulled {obj} out of the way at the last moment. Before' +
' {vname} could try again, {name} reached the throne and delivered' +
' a powerful punch. A punch so powerful that {vposd} head exploded.' +
' {vname} was dead, and the website was restored for good.',
'345:FFS': '{name} trotted towards {vname}, ready to bite {vobj},' +
' with {princess} walking behind. With a flick of {vposd} wrist,' +
' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
' {Vsubj} then cast the same spell at {name}, who did not sidestep' +
' it, and was disintegrated immediately. {princess} shrugged, and' +
' showed herself out.',
/* Family 145 (troll, potion, princess): the one-legged Anastasia
situations. The other six are aliased below */
'145:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}. {vname} aimed a spell at {posd} remaining leg,' +
' but {princess} threw a rock at {vposd} head, ruining {vposd}' +
' concentration. Before {vname} could recover, {name} reached the' +
' throne and {attacked} {vobj} one final time. {vname} was dead,' +
' and the website was restored for good.',
'145:FFS': '{name} hobbled towards {vname} on {posd} three remaining' +
' trotters, {posd} {weapon} clenched in {posd} pig mouth, with' +
' {princess} walking behind. With a flick of {vposd} wrist, {vname}' +
' cast a spell at {princess}, who calmly sidestepped it. {Vsubj}' +
' then cast the same spell at {name}, who, being a three-legged' +
' pig, could not. {princess} sighed, muttered something under her' +
' breath, and left the tower.',
/* Family 135 (troll, mimic, princess): one new situation — the rest
alias below */
'135:FFS': '{name} hobbled towards {vname}, ready to punch {vobj},' +
' leaning on {princess} for support. With a flick of {vposd} wrist,' +
' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
' {Vsubj} then cast the same spell at {name}, who could not' +
' sidestep anything, and was disintegrated immediately. {princess}' +
' stood in silence for a moment, then left the tower without a word.',
/* Family 125 (troll, Breigan, princess): armed human throughout, so
three losses have no armed-and-able precedent to alias */
'125:SSS': '{name}, {kid} and {princess} charged towards {vname}' +
' together. {vname} began casting a spell, but {princess} reached' +
' the throne first and pushed {vobj} to the floor. What followed' +
' was less of a battle and more of a group activity: the three of' +
' them simply kicked {vname} until {vsubj} stopped moving. {name}' +
' had briefly considered using {posd} {weapon}, but kicking had' +
' felt more appropriate. {vname} was dead, and the website was' +
' restored for good.',
'125:FSS': '{name} hobbled towards {vname}, but {kid} and {princess}' +
' had already run ahead. {princess} knocked {vname} to the ground,' +
' and {kid} sat down on {vposd} back to keep {vobj} there. By the' +
' time {name} finally reached the throne, {vname} was already dead.' +
' {Subj} tried not to feel left out. The website was restored for' +
' good.',
'125:SFF': '{name} ran towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}. An epic duel commenced, with {vname} throwing' +
' spells and {name} {attacking} back. Slowly, however, {name} began' +
' to tire. With a flick of {vposd} wrist, {vname} cast a spell on' +
' {name}, disintegrating {obj} immediately.',
'125:FSF': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}, with {kid} running ahead. With a flick of' +
' {vposd} wrist, {vname} cast a spell on {kid}, disintegrating him' +
' immediately. {name} let out a scream and {attacked} {vobj} with' +
' everything {subj} had left. It was not enough. With another flick' +
' of {vposd} wrist, {vname} cast the same spell on {name},' +
' disintegrating {obj} as well.',
'125:FFS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
' {posd} {weapon}, leaning on {princess} for support. With a flick' +
' of {vposd} wrist, {vname} cast a spell at {princess}, who calmly' +
' sidestepped it. {name}, who had been leaning on her, lost {posd}' +
' balance and fell. With another flick of {vposd} wrist, {vname}' +
' cast a spell on {name}, disintegrating {obj} immediately.' +
' {princess} gave {vname} a long, disappointed look, and left the' +
' tower.',
/* Family 235 (Breigan, mimic, princess): intact human throughout.
The weaponless group kicking needs its own entry (the 125 version
mentions the weapon); plus the unarmed one-companion losses */
'235:SFS': '{name}, {kid} and {princess} charged towards {vname}' +
' together. {vname} began casting a spell, but {princess} reached' +
' the throne first and pushed {vobj} to the floor. What followed' +
' was less of a battle and more of a group activity: the three of' +
' them simply kicked {vname} until {vsubj} stopped moving. {vname}' +
' was dead, and the website was restored for good.',
'235:SFF': '{name} and {kid} ran towards {vname}, ready to punch' +
' {vobj}. With a flick of {vposd} wrist, {vname} cast a spell on' +
' {kid}, disintegrating him immediately. {name} yelled out towards' +
' him, but there was nothing {subj} could do. With another flick of' +
' {vposd} wrist, {vname} cast the same spell on {name},' +
' disintegrating {obj} as well.',
'235:FFS': '{name} ran towards {vname}, ready to punch {vobj}, with' +
' {princess} running beside {obj}. With a flick of {vposd} wrist,' +
' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
' {Vsubj} then cast the same spell at {name}, who tried to sidestep' +
' it the same way {princess} had. {Subj} did not succeed, and was' +
' disintegrated immediately. {princess} pinched the bridge of her' +
' nose, turned around, and left the tower.',
/* Family 245 (Breigan, potion, princess): armed and able-bodied
throughout — the news are the pig situations */
'245:SFS': '{name}, {kid} and {princess} charged towards {vname}' +
' together. {vname} took a moment too long deciding whether to aim' +
' at the boy, the princess, or the pig with {aweapon} in its mouth.' +
' {princess} used that moment to push {vobj} off the throne, {kid}' +
' pinned {vposd} arms, and {name} {attacked} {vobj}. {vname} was' +
' dead, and the website was restored for good.',
'245:SFF': '{kid} ran towards {vname}, with {name} trotting behind,' +
' {posd} {weapon} clenched in {posd} pig mouth. With a flick of' +
' {vposd} wrist, {vname} cast a spell on {kid}, disintegrating him' +
' immediately. {name} let out a devastated squeal and charged. With' +
' another flick of {vposd} wrist, {vname} cast the same spell on' +
' {name}, disintegrating {obj} as well.',
'245:FFS': '{name} trotted towards {vname}, {posd} {weapon} clenched' +
' in {posd} pig mouth, with {princess} walking behind. With a flick' +
' of {vposd} wrist, {vname} cast a spell at {princess}, who calmly' +
' sidestepped it. {Vsubj} then cast the same spell at {name}. The' +
' {weapon} clattered to the floor, its owner now a pile of dust.' +
' {princess} picked it up, considered it for a moment, then put it' +
' down again and left the tower.'
};
/* Family 234 with a human hero (potion succeeded) is the same fight as
the corresponding two-legged 123 ending, reused verbatim */
ENDINGS['234:SSS'] = ENDINGS['123:SSS'];
ENDINGS['234:SFS'] = ENDINGS['123:SSF'];
ENDINGS['234:FSS'] = ENDINGS['123:SFS'];
ENDINGS['234:FFS'] = ENDINGS['123:SFF'];
/* Family 124 reuses: humans match 123 (same legs/kid/weapon), pigs
with both legs match 234 */
ENDINGS['124:SSS'] = ENDINGS['123:SSS'];
ENDINGS['124:SSF'] = ENDINGS['234:SSF'];
ENDINGS['124:SFS'] = ENDINGS['123:SFS'];
ENDINGS['124:SFF'] = ENDINGS['234:FSF'];
ENDINGS['124:FSS'] = ENDINGS['123:FSS'];
ENDINGS['124:FFS'] = ENDINGS['123:FFS'];
/* Family 134 reuses, matched on state AND outcome */
ENDINGS['134:SSS'] = ENDINGS['123:SFS'];
ENDINGS['134:SFF'] = ENDINGS['234:FFF'];
ENDINGS['134:FSF'] = ENDINGS['124:FFF'];
/* Family 345 reuses: no princess collapses to lone-hero situations */
ENDINGS['345:SSF'] = ENDINGS['123:SFS'];
ENDINGS['345:SFF'] = ENDINGS['234:FSF'];
ENDINGS['345:FSF'] = ENDINGS['123:SFF'];
ENDINGS['345:FFF'] = ENDINGS['234:FFF'];
/* Family 125 reuses (letters: troll, Breigan, princess) */
ENDINGS['125:SSF'] = ENDINGS['123:SSS'];
ENDINGS['125:SFS'] = ENDINGS['345:SSS'];
ENDINGS['125:FFF'] = ENDINGS['123:FFS'];
/* Family 245 reuses (letters: Breigan, potion, princess) */
ENDINGS['245:SSS'] = ENDINGS['125:SSS'];
ENDINGS['245:SSF'] = ENDINGS['123:SSS'];
ENDINGS['245:FSS'] = ENDINGS['345:SSS'];
ENDINGS['245:FSF'] = ENDINGS['125:SFF'];
ENDINGS['245:FFF'] = ENDINGS['234:FSF'];
/* Family 235 reuses (letters: Breigan, mimic, princess) */
ENDINGS['235:SSS'] = ENDINGS['125:SSS'];
ENDINGS['235:SSF'] = ENDINGS['123:SSS'];
ENDINGS['235:FSS'] = ENDINGS['345:SSS'];
ENDINGS['235:FSF'] = ENDINGS['125:SFF'];
ENDINGS['235:FFF'] = ENDINGS['123:SFF'];
/* Family 135 reuses (letters: troll, mimic, princess) */
ENDINGS['135:SSS'] = ENDINGS['345:SSS'];
ENDINGS['135:SSF'] = ENDINGS['123:SFS'];
ENDINGS['135:SFS'] = ENDINGS['345:FSS'];
ENDINGS['135:SFF'] = ENDINGS['123:SFF'];
ENDINGS['135:FSS'] = ENDINGS['145:FSS'];
ENDINGS['135:FSF'] = ENDINGS['123:FFS'];
ENDINGS['135:FFF'] = ENDINGS['134:FFS'];
/* Family 145 reuses (letters: troll, potion, princess) */
ENDINGS['145:SSS'] = ENDINGS['345:SSS'];
ENDINGS['145:SSF'] = ENDINGS['123:SFS'];
ENDINGS['145:SFS'] = ENDINGS['345:SFS'];
ENDINGS['145:SFF'] = ENDINGS['234:FSF'];
ENDINGS['145:FSF'] = ENDINGS['123:FFS'];
ENDINGS['145:FFF'] = ENDINGS['124:FFF'];
/* The encounter pool. ROLLED of these are drawn per hero when the hand
is chosen, stored in order in questEncounters; the ENDINGS set
signature uses 1-based pool positions. Each entry knows how its save
key resolves and what counts as success */
var POOL = ['troll', 'kid', 'mimic', 'potion', 'princess'];
var ROLLED = 3;
function rollEncounters() {
var pool = POOL.slice();
var picked = [];
while (picked.length < ROLLED && pool.length) {
picked.push(pool.splice(Math.floor(Math.random() * pool.length), 1)[0]);
}
return picked;
}
/* The hero. The weapon is an icon glyph dropped into the {w} cell of the
art (a fixed 2ch box, so the monospace grid survives). Keys are viewer
sides, not hands: the hero faces the viewer */
var ART = {
base: ' o\n/|\\\n/ \\',
right: ' o\n/|\\_{w}\n/ \\',
left: ' o\n{w}_/|\\\n / \\',
/* Breigan, age 16, shorter than the hero */
kid: ' o\n/|\\',
/* Anastasia. The circumflex is a crown */
princess: ' \u00f4\n/|\\\n/ \\',
/* The hero as a pig (potion theft). Still clutches the weapon */
pig: {
base: '^..^\n(oo)\n /\\',
right: '^..^\n(oo)_{w}\n /\\',
left: ' ^..^\n{w}_(oo)\n /\\'
}
};
/* fa: Font Awesome class; em: Noto Emoji glyph (subsetted into
fonts/noto-emoji.woff2 — resubset if the roster changes);
attacked/attacking: the combat verbs */
var WEAPONS = {
sword: { em: '\uD83D\uDDE1', rot: true, attacked: 'slashed', attacking: 'slashing' },
axe: { em: '\uD83E\uDE93', reversed: true, attacked: 'chopped', attacking: 'chopping' },
wand: { fa: 'fa-wand-sparkles', attacked: 'zapped', attacking: 'zapping' },
gun: { fa: 'fa-gun', attacked: 'shot', attacking: 'shooting' }
};
var PRESETS = {
she: { subj: 'she', obj: 'her', posd: 'her', refl: 'herself' },
he: { subj: 'he', obj: 'him', posd: 'his', refl: 'himself' },
they: { subj: 'they', obj: 'them', posd: 'their', refl: 'themself' }
};
var story = document.getElementById('story');
var pronouns = document.getElementById('pronouns');
var custom = document.getElementById('custom');
var weapon = document.getElementById('weapon');
var hand = document.getElementById('hand');
var vnaming = document.getElementById('vnaming');
var vpronouns = document.getElementById('vpronouns');
function loadKey(key) {
try { return localStorage.getItem(key); } catch (e) { return null; }
}
function saveKey(key, value) {
try { localStorage.setItem(key, value); } catch (e) {}
}
function state() {
var pron = null, enc1 = null, vpron = null, order = null;
try { pron = JSON.parse(loadKey('questPronouns')); } catch (e) {}
try { enc1 = JSON.parse(loadKey('questEnc1')); } catch (e) {}
try { vpron = JSON.parse(loadKey('questVillainPronouns')); } catch (e) {}
try { order = JSON.parse(loadKey('questEncounters')); } catch (e) {}
var weaponKey = loadKey('questWeapon');
return {
name: loadKey('questHero'),
pron: pron,
weapon: WEAPONS[weaponKey] ? weaponKey : null,
hand: loadKey('questHand'),
/* The rolled encounter ids, in play order */
order: order && order.length ? order : null,
/* Set by the mimic eating the weapon: bare fists from then on,
{attacked} becomes 'punched' */
weaponLost: loadKey('questWeaponLost') === '1',
/* { asked: bool, result: 'attack'|'solved'|'wrong'|null,
answer: string (wrong only) } */
enc1: enc1,
/* 'yes' (Breigan joins) | 'no' | null */
enc2: loadKey('questEnc2'),
/* The kid's name once the rename question is answered ('Breigan'
if declined); null while unanswered. He/him either way */
kid: loadKey('questKid'),
/* 'pry' (mimic eats the weapon) | 'leave' | null */
enc3: loadKey('questEnc3'),
/* 'steal' (hero becomes a pig) | 'explain' | null */
enc4: loadKey('questEnc4'),
/* 'decline' | 'agree' (mid-choice) | 'vines' | 'door' | null */
enc5: loadKey('questEnc5'),
/* The princess's name once the rename question is answered
('Anastasia' if declined); null while unanswered */
princess: loadKey('questPrincess'),
vname: loadKey('questVillain'),
vpron: vpron,
attacked: loadKey('questAttacked') === '1'
};
}
function fill(text, vars) {
return text.replace(/\{([A-Za-z]+)\}/g, function (token, key) {
var value = vars[key.toLowerCase()];
if (value === undefined) return token;
if (key[0] !== key[0].toLowerCase()) {
value = value.charAt(0).toUpperCase() + value.slice(1);
}
return value;
});
}
/* Everything on the page is a function of the save file */
function render() {
var s = state();
var vars = { name: s.name, kid: s.kid || 'Breigan',
princess: s.princess || 'Anastasia' };
if (s.pron) for (var k in s.pron) vars[k] = s.pron[k];
naming.style.display = s.name ? 'none' : '';
story.style.display = s.name ? '' : 'none';
pronouns.style.display = s.name && !s.pron ? '' : 'none';
weapon.style.display = s.pron && !s.weapon ? '' : 'none';
hand.style.display = s.weapon && !s.hand ? '' : 'none';
if (s.name) {
document.getElementById('intro').textContent = fill(TEXT.intro, vars);
}
var setout = document.getElementById('setout');
setout.style.display = s.pron ? '' : 'none';
if (s.pron) setout.textContent = fill(TEXT.setout, vars);
var traverse = document.getElementById('traverse');
var armed = s.weapon && s.hand;
traverse.style.display = armed ? '' : 'none';
if (armed) {
vars.weapon = s.weapon;
/* {aweapon}: article included — 'a sword' but 'an axe' */
vars.aweapon = (/^[aeiou]/.test(s.weapon) ? 'an ' : 'a ') + s.weapon;
vars.hand = s.hand;
traverse.textContent = fill(TEXT.traverse, vars);
}
/* The roll: which encounters this hero gets, in which order. Rolled
lazily so pre-roll saves pick one up on their next render */
var order = s.order;
if (armed && !order) {
order = rollEncounters();
saveKey('questEncounters', JSON.stringify(order));
}
var resolvedEnc = {
troll: !!(s.enc1 && s.enc1.result),
kid: s.enc2 === 'no' || (s.enc2 === 'yes' && !!s.kid),
mimic: !!s.enc3,
potion: !!s.enc4,
princess: s.enc5 === 'decline' || s.enc5 === 'vines' ||
(s.enc5 === 'door' && !!s.princess)
};
/* Reorder the story's encounter groups to match the roll, and find
the single encounter currently awaiting the player */
var active = null;
var arrival = document.getElementById('arrival');
if (armed && order) {
for (var oi = 0; oi < order.length; oi++) {
var g = document.getElementById(
'grp' + order[oi].charAt(0).toUpperCase() + order[oi].slice(1));
if (g) story.insertBefore(g, arrival);
if (active === null && !resolvedEnc[order[oi]]) active = order[oi];
}
}
function appeared(id) {
if (!armed || !order || order.indexOf(id) < 0) return false;
return resolvedEnc[id] || id === active;
}
/* Weapon state as of a given encounter: lost only if the mimic ate it
earlier in the order (texts must not change retroactively) */
function armedAt(id) {
var i = order ? order.indexOf(id) : -1;
for (var j = 0; j < i; j++) {
if (order[j] === 'mimic' && s.enc3 === 'pry') return false;
}
return true;
}
function combatVars(isArmed) {
vars.attacked = isArmed ? WEAPONS[s.weapon].attacked : 'punched';
vars.withweapon = isArmed ? ' with ' + vars.posd + ' ' + s.weapon : '';
}
/* The bridge troll's riddle */
var showTroll = appeared('troll');
if (showTroll) combatVars(armedAt('troll'));
var enc1 = document.getElementById('enc1');
enc1.style.display = showTroll ? '' : 'none';
if (showTroll) enc1.textContent = fill(TEXT.enc1, vars);
document.getElementById('enc1choice').style.display =
showTroll && !s.enc1 ? '' : 'none';
var asked = showTroll && s.enc1 && s.enc1.asked;
var enc1riddle = document.getElementById('enc1riddle');
enc1riddle.style.display = asked ? '' : 'none';
if (asked) enc1riddle.textContent = fill(TEXT.enc1riddle, vars);
document.getElementById('riddle').style.display =
asked && !s.enc1.result ? '' : 'none';
var attacked = showTroll && s.enc1 && s.enc1.result === 'attack';
var enc1attack = document.getElementById('enc1attack');
enc1attack.style.display = attacked ? '' : 'none';
if (attacked) enc1attack.textContent = fill(TEXT.enc1attack, vars);
var wrong = showTroll && s.enc1 && s.enc1.result === 'wrong';
var enc1wrong = document.getElementById('enc1wrong');
enc1wrong.style.display = wrong ? '' : 'none';
if (wrong) {
vars.answer = s.enc1.answer;
enc1wrong.textContent = fill(TEXT.enc1wrong, vars);
}
var solved = showTroll && s.enc1 && s.enc1.result === 'solved';
var enc1correct = document.getElementById('enc1correct');
enc1correct.style.display = solved ? '' : 'none';
if (solved) enc1correct.textContent = fill(TEXT.enc1correct, vars);
/* Breigan */
var showKid = appeared('kid');
var enc2 = document.getElementById('enc2');
enc2.style.display = showKid ? '' : 'none';
if (showKid) enc2.textContent = fill(TEXT.enc2, vars);
document.getElementById('enc2choice').style.display =
showKid && !s.enc2 ? '' : 'none';
var enc2yes = document.getElementById('enc2yes');
var joined = showKid && s.enc2 === 'yes';
enc2yes.style.display = joined ? '' : 'none';
if (joined) enc2yes.textContent = fill(TEXT.enc2yes, vars);
var enc2no = document.getElementById('enc2no');
var declined = showKid && s.enc2 === 'no';
enc2no.style.display = declined ? '' : 'none';
if (declined) enc2no.textContent = fill(TEXT.enc2no, vars);
/* The rename question holds up the journey until answered */
document.getElementById('rename').style.display =
joined && !s.kid ? '' : 'none';
/* The mimic chest */
var showMimic = appeared('mimic');
var enc3 = document.getElementById('enc3');
enc3.style.display = showMimic ? '' : 'none';
if (showMimic) enc3.textContent = fill(TEXT.enc3, vars);
var choosing3 = showMimic && !s.enc3;
document.getElementById('enc3choice').style.display = choosing3 ? '' : 'none';
if (choosing3) {
document.getElementById('pryBtn').textContent = fill(TEXT.enc3pryBtn, vars);
}
var pried = showMimic && s.enc3 === 'pry';
var enc3pry = document.getElementById('enc3pry');
enc3pry.style.display = pried ? '' : 'none';
if (pried) enc3pry.textContent = fill(TEXT.enc3pry, vars);
var left = showMimic && s.enc3 === 'leave';
var enc3leave = document.getElementById('enc3leave');
enc3leave.style.display = left ? '' : 'none';
if (left) enc3leave.textContent = fill(TEXT.enc3leave, vars);
/* The potion seller */
var showPotion = appeared('potion');
var enc4 = document.getElementById('enc4');
enc4.style.display = showPotion ? '' : 'none';
if (showPotion) enc4.textContent = fill(TEXT.enc4, vars);
document.getElementById('enc4choice').style.display =
showPotion && !s.enc4 ? '' : 'none';
var stole = showPotion && s.enc4 === 'steal';
var enc4steal = document.getElementById('enc4steal');
enc4steal.style.display = stole ? '' : 'none';
if (stole) {
combatVars(armedAt('potion'));
enc4steal.textContent = fill(TEXT.enc4steal, vars);
}
var explained = showPotion && s.enc4 === 'explain';
var enc4explain = document.getElementById('enc4explain');
enc4explain.style.display = explained ? '' : 'none';
if (explained) enc4explain.textContent = fill(TEXT.enc4explain, vars);
/* Breigan's rename line (only when he was actually renamed) */
var kidrename = document.getElementById('kidrename');
var kidRenamed = joined && s.kid && s.kid !== 'Breigan';
kidrename.style.display = kidRenamed ? '' : 'none';
if (kidRenamed) kidrename.textContent = fill(TEXT.kidrename, vars);
/* The probable princess */
var showPrincess = appeared('princess');
var enc5 = document.getElementById('enc5');
enc5.style.display = showPrincess ? '' : 'none';
if (showPrincess) enc5.textContent = fill(TEXT.enc5, vars);
document.getElementById('enc5choice').style.display =
showPrincess && !s.enc5 ? '' : 'none';
var declined5 = showPrincess && s.enc5 === 'decline';
var enc5decline = document.getElementById('enc5decline');
enc5decline.style.display = declined5 ? '' : 'none';
if (declined5) enc5decline.textContent = fill(TEXT.enc5decline, vars);
var agreed = showPrincess && (s.enc5 === 'agree' ||
s.enc5 === 'vines' || s.enc5 === 'door');
var enc5agree = document.getElementById('enc5agree');
enc5agree.style.display = agreed ? '' : 'none';
if (agreed) enc5agree.textContent = fill(TEXT.enc5agree, vars);
document.getElementById('enc5method').style.display =
showPrincess && s.enc5 === 'agree' ? '' : 'none';
var fell = showPrincess && s.enc5 === 'vines';
var enc5vines = document.getElementById('enc5vines');
enc5vines.style.display = fell ? '' : 'none';
if (fell) enc5vines.textContent = fill(TEXT.enc5vines, vars);
var rescued = showPrincess && s.enc5 === 'door';
var enc5door = document.getElementById('enc5door');
enc5door.style.display = rescued ? '' : 'none';
if (rescued) enc5door.textContent = fill(TEXT.enc5door, vars);
document.getElementById('prename').style.display =
rescued && !s.princess ? '' : 'none';
var princessrename = document.getElementById('princessrename');
var pRenamed = rescued && s.princess && s.princess !== 'Anastasia';
princessrename.style.display = pRenamed ? '' : 'none';
if (pRenamed) princessrename.textContent = fill(TEXT.princessrename, vars);
/* The wizard's tower: arrival, villain creation, then the ending */
var encountersDone = armed && order && active === null;
arrival.style.display = encountersDone ? '' : 'none';
if (encountersDone) arrival.textContent = fill(TEXT.arrival, vars);
vnaming.style.display = encountersDone && !s.vname ? '' : 'none';
vpronouns.style.display =
encountersDone && s.vname && !s.vpron ? '' : 'none';
var showdown = encountersDone && s.vname && s.vpron;
var confront = document.getElementById('confront');
confront.style.display = showdown ? '' : 'none';
if (showdown) {
vars.vname = s.vname;
for (var vk in s.vpron) vars['v' + vk] = s.vpron[vk];
/* Showdown-time forms: unlike the troll fight, the ending happens
after any weapon loss, so here punched/bare-handed applies */
vars.attacked = s.weaponLost ? 'punched' : WEAPONS[s.weapon].attacked;
vars.attacking = s.weaponLost ? 'punching' : WEAPONS[s.weapon].attacking;
vars.withweapon = s.weaponLost ? '' : ' with ' + vars.posd + ' ' + s.weapon;
confront.textContent = fill(TEXT.confront, vars);
}
document.getElementById('showdownAttack').style.display =
showdown && !s.attacked ? '' : 'none';
var ending = document.getElementById('ending');
var endingText = '';
var won = false;
if (showdown && s.attacked) {
/* The situation key: chosen encounters in pool order (1-based
positions), then their outcomes in the same order */
var successOf = {
troll: s.enc1 && s.enc1.result === 'solved',
kid: s.enc2 === 'yes',
mimic: s.enc3 === 'leave',
potion: s.enc4 === 'explain',
princess: s.enc5 === 'door'
};
var chosen = order.slice().sort(function (a, b) {
return POOL.indexOf(a) - POOL.indexOf(b);
});
var sig = '', letters = '', successes = 0;
chosen.forEach(function (id) {
sig += POOL.indexOf(id) + 1;
letters += successOf[id] ? 'S' : 'F';
successes += successOf[id] ? 1 : 0;
});
won = successes >= 2;
endingText = ENDINGS[sig + ':' + letters] || '';
}
ending.style.display = endingText ? '' : 'none';
if (endingText) ending.textContent = fill(endingText, vars);
document.getElementById('endWin').style.display =
showdown && s.attacked && won ? '' : 'none';
/* Restart is offered after every ending — losses need it, wins may
want another go */
document.getElementById('endRestart').style.display =
showdown && s.attacked ? '' : 'none';
var figure = document.getElementById('figure');
/* The hero faces the viewer: their left hand is on the viewer's
right, so the art side is the opposite of the handedness */
var side = s.hand === 'left' ? 'right' : 'left';
/* The potion theft turned the hero into a pig (weapon still in trotter) */
var isPig = s.enc4 === 'steal';
var artSet = isPig ? ART.pig : ART;
var hero;
if (armed && !s.weaponLost) {
var w = WEAPONS[s.weapon];
/* Mirror so the weapon faces away from the body; 'reversed' marks
glyphs whose natural facing is opposite the FA convention */
var mirrored = side === 'left';
if (w.reversed) mirrored = !mirrored;
var flip = mirrored ? ' wpn-flip' : '';
var icon = w.fa
? '<i class="fa-solid ' + w.fa + '"></i>'
: '<span class="wpn-em' + (w.rot ? ' wpn-rot' : '') + '">' +
w.em + '</span>';
icon = '<span class="wpn' + flip + '">' + icon + '</span>';
hero = artSet[side].replace('{w}', icon);
} else {
hero = artSet.base;
}
/* The troll took a leg (in combat or as a quiz penalty) */
if (armed && (attacked || wrong)) {
hero = hero.replace(isPig ? '/\\' : '/ \\', '/');
}
/* Companions line up on the hero's free side, away from the weapon —
and stay there even if the weapon is later lost */
var figs = ['<span class="fig">' + hero + '</span>'];
function addCompanion(art) {
var span = '<span class="fig">' + art + '</span>';
if (side === 'right') figs.unshift(span);
else figs.push(span);
}
if (joined) addCompanion(ART.kid);
if (rescued) addCompanion(ART.princess);
figure.innerHTML = figs.join('');
}
naming.addEventListener('submit', function (e) {
e.preventDefault();
var name = document.getElementById('heroName').value.trim();
if (!name) return;
saveKey('questHero', name);
render();
});
/* Hero and villain share the pronoun-picker wiring; ids differ by prefix */
function wirePronouns(form, customTable, customBtn, prefix, storageKey) {
form.addEventListener('click', function (e) {
var preset = e.target.getAttribute && e.target.getAttribute('data-preset');
if (!preset) return;
saveKey(storageKey, JSON.stringify(PRESETS[preset]));
render();
});
customBtn.addEventListener('click', function () {
customTable.style.display = customTable.style.display ? '' : 'none';
});
form.addEventListener('submit', function (e) {
e.preventDefault();
var pron = {
subj: document.getElementById(prefix + 'Subj').value.trim(),
obj: document.getElementById(prefix + 'Obj').value.trim(),
posd: document.getElementById(prefix + 'Posd').value.trim(),
refl: document.getElementById(prefix + 'Refl').value.trim()
};
for (var k in pron) if (!pron[k]) return;
saveKey(storageKey, JSON.stringify(pron));
render();
});
}
wirePronouns(pronouns, custom,
document.getElementById('customBtn'), 'pn', 'questPronouns');
wirePronouns(vpronouns, document.getElementById('vcustom'),
document.getElementById('vcustomBtn'), 'vpn', 'questVillainPronouns');
vnaming.addEventListener('submit', function (e) {
e.preventDefault();
var name = document.getElementById('villainName').value.trim();
if (!name) return;
saveKey('questVillain', name);
render();
});
document.getElementById('showdownAttack').addEventListener('click', function (e) {
if (e.target.tagName !== 'BUTTON') return;
saveKey('questAttacked', '1');
render();
});
/* A restart or a completed quest wipes the whole save file, hero
included — a fresh run starts at "Name your hero" */
function clearRun() {
try {
['questHero', 'questPronouns', 'questWeapon', 'questHand', 'questEncounters',
'questEnc1', 'questEnc2', 'questKid', 'questEnc3', 'questEnc4', 'questEnc5', 'questPrincess',
'questWeaponLost',
'questVillain', 'questVillainPronouns', 'questAttacked'
].forEach(function (k) { localStorage.removeItem(k); });
} catch (err) {}
}
/* Winning genuinely restores gade.gg: same keys the 404's restore
hatch clears, then home — where the guard no longer redirects */
document.getElementById('endWin').addEventListener('click', function (e) {
if (e.target.tagName !== 'BUTTON') return;
/* Permanent — survives the save wipe and the restore. The
achievements system on the main page reads it, so the Adventurer
toast greets the return home */
saveKey('questWon', '1');
clearRun();
try {
localStorage.removeItem('siteDeleted');
localStorage.removeItem('siteDeletedViews');
localStorage.removeItem('questStarted');
} catch (err) {}
location.href = '/';
});
document.getElementById('endRestart').addEventListener('click', function (e) {
if (e.target.tagName !== 'BUTTON') return;
clearRun();
render();
});
weapon.addEventListener('click', function (e) {
var chosen = e.target.getAttribute && e.target.getAttribute('data-weapon');
if (!chosen) return;
saveKey('questWeapon', chosen);
render();
});
hand.addEventListener('click', function (e) {
var chosen = e.target.getAttribute && e.target.getAttribute('data-hand');
if (!chosen) return;
saveKey('questHand', chosen);
render();
});
document.getElementById('enc1choice').addEventListener('click', function (e) {
var act = e.target.getAttribute && e.target.getAttribute('data-act');
if (!act) return;
saveKey('questEnc1', JSON.stringify(act === 'attack'
? { asked: false, result: 'attack' }
: { asked: true, result: null }));
render();
});
document.getElementById('riddle').addEventListener('submit', function (e) {
e.preventDefault();
var raw = document.getElementById('riddleAnswer').value.trim();
if (!raw) return;
var answer = raw.toLowerCase();
var enc1 = answer === 'a river' || answer === 'river' || answer === 'water'
? { asked: true, result: 'solved' }
: { asked: true, result: 'wrong', answer: raw };
saveKey('questEnc1', JSON.stringify(enc1));
render();
});
document.getElementById('riddleAttack').addEventListener('click', function () {
saveKey('questEnc1', JSON.stringify({ asked: true, result: 'attack' }));
render();
});
document.getElementById('enc2choice').addEventListener('click', function (e) {
var ans = e.target.getAttribute && e.target.getAttribute('data-ans');
if (!ans) return;
saveKey('questEnc2', ans);
render();
});
/* Breigan and Anastasia share the rename wiring */
function wireRename(divId, formId, inputId, storageKey, defaultName) {
var form = document.getElementById(formId);
document.getElementById(divId).addEventListener('click', function (e) {
var ans = e.target.getAttribute && e.target.getAttribute('data-rename');
if (!ans) return;
if (ans === 'no') {
saveKey(storageKey, defaultName);
render();
} else {
form.style.display = '';
}
});
form.addEventListener('submit', function (e) {
e.preventDefault();
var name = document.getElementById(inputId).value.trim();
if (!name) return;
saveKey(storageKey, name);
render();
});
}
wireRename('rename', 'renameForm', 'kidName', 'questKid', 'Breigan');
wireRename('prename', 'prenameForm', 'princessName',
'questPrincess', 'Anastasia');
document.getElementById('enc3choice').addEventListener('click', function (e) {
var act = e.target.getAttribute && e.target.getAttribute('data-act');
if (!act) return;
saveKey('questEnc3', act);
if (act === 'pry') saveKey('questWeaponLost', '1');
render();
});
document.getElementById('enc4choice').addEventListener('click', function (e) {
var act = e.target.getAttribute && e.target.getAttribute('data-act');
if (!act) return;
saveKey('questEnc4', act);
render();
});
document.getElementById('enc5choice').addEventListener('click', function (e) {
var act = e.target.getAttribute && e.target.getAttribute('data-act');
if (!act) return;
saveKey('questEnc5', act);
render();
});
document.getElementById('enc5method').addEventListener('click', function (e) {
var act = e.target.getAttribute && e.target.getAttribute('data-act');
if (!act) return;
saveKey('questEnc5', act);
render();
});
render();
})();