Skip to content

Instantly share code, notes, and snippets.

@smwhr
Last active June 17, 2022 08:19
Show Gist options
  • Save smwhr/7de51aba40e91d0ee77cb9858d5771ef to your computer and use it in GitHub Desktop.
Save smwhr/7de51aba40e91d0ee77cb9858d5771ef to your computer and use it in GitHub Desktop.
Crime Scene from Inkle to Binksi
Crime Scene -- Script by Inkle, adapted by @smwhr for binksi#TITLE
SPAWN_AT(lamp-on-desk, lamp)
-> murder_scene
// Helper function: popping elements from lists
=== function pop(ref list)
~ temp x = LIST_MIN(list)
~ list -= x
~ return x
//
// System: items can have various states
// Some are general, some specific to particular items
//
LIST OffOn = off, on
LIST SeenUnseen = unseen, seen
LIST GlassState = (none), steamed, steam_gone
LIST BedState = (made_up), covers_shifted, covers_off, bloodstain_visible
//
// System: inventory
//
LIST Inventory = (none), cane, knife
=== function get(x)
~ Inventory += x
//
// System: positioning things
// Items can be put in and on places
//
LIST Supporters = on_desk, on_floor, on_bed, under_bed, held, with_joe
=== function move_to_supporter(ref item_state, new_supporter) ===
~ item_state -= LIST_ALL(Supporters)
~ item_state += new_supporter
// System: Incremental knowledge.
// Each list is a chain of facts. Each fact supersedes the fact before
//
VAR knowledgeState = ()
=== function reached (x)
~ return knowledgeState ? x
=== function between(x, y)
~ return knowledgeState? x && not (knowledgeState ^ y)
=== function reach(statesToSet)
~ temp x = pop(statesToSet)
{
- not x:
~ return false
- not reached(x):
~ temp chain = LIST_ALL(x)
~ temp statesGained = LIST_RANGE(chain, LIST_MIN(chain), x)
~ knowledgeState += statesGained
~ reach (statesToSet) // set any other states left to set
~ return true // and we set this state, so true
- else:
~ return false || reach(statesToSet)
}
//
// Set up the game
//
VAR bedroomLightState = (off, on_desk)
VAR knifeState = (under_bed)
//
// Knowledge chains
//
LIST BedKnowledge = neatly_made, crumpled_duvet, hastily_remade, body_on_bed, murdered_in_bed, murdered_while_asleep
LIST KnifeKnowledge = prints_on_knife, joe_seen_prints_on_knife,joe_wants_better_prints, joe_got_better_prints
LIST WindowKnowledge = steam_on_glass, fingerprints_on_glass, fingerprints_on_glass_match_knife
//
// Content
//
=== murder_scene ===
The bedroom. This is where it happened. Now to look for clues.
- (top)
// run some checks to change the colors of the elements
// door is available after 5 loops
CUTSCENE(visited, exit-{top >= 5:available|disabled})
// bed is available if light is on floor
{darkunder && bedroomLightState ? on_floor && bedroomLightState ? on && not peerbed:
- CUTSCENE(visited, unvisit-bed)
}
// bed is not available if lamp is off
{darkunder && bedroomLightState ? on_floor && bedroomLightState ? off:
- CUTSCENE(visited, visit-bed)
}
// bed is always available when trying to reach
{reaching and not knock_with_cane:
- CUTSCENE(visited, unvisit-bed)
}
{ bedroomLightState ? seen: <- seen_light }
<- compare_prints(-> top)
* (dobed) [tag: bed]
The bed was low to the ground, but not so low something might not roll underneath. It was still neatly made.
~ reach (neatly_made)
- - (bedhub)
* * [Lift the bedcover]
I lifted back the bedcover. The duvet underneath was crumpled.
~ reach (crumpled_duvet)
~ BedState = covers_shifted
* * (uncover) {reached(crumpled_duvet)}
[Remove the cover]
Careful not to disturb anything beneath, I removed the cover entirely. The duvet below was rumpled.
Not the work of the maid, who was conscientious to a point. Clearly this had been thrown on in a hurry.
~ reach (hastily_remade)
~ BedState = covers_off
* * (duvet) {BedState == covers_off} [ Pull back the duvet ]
I pulled back the duvet. Beneath it was a sheet, sticky with blood.
~ BedState = bloodstain_visible
~ reach (body_on_bed)
Either the body had been moved here before being dragged to the floor - or this is was where the murder had taken place.
* * {BedState !? made_up} [ Remake the bed ]
Carefully, I pulled the bedsheets back into place, trying to make it seem undisturbed.
~ BedState = made_up
* * [Test the bed]
I pushed the bed with spread fingers. It creaked a little, but not so much as to be obnoxious.
* * (darkunder) [Look under the bed]
Lying down, I peered under the bed, but could make nothing out.
* * {TURNS_SINCE(-> dobed) > 1} [Something else?]
I took a step back from the bed and looked around.
CUTSCENE(visited, visit-bed)
-> top
- - -> bedhub
* (peerbed){darkunder && bedroomLightState ? on_floor && bedroomLightState ? on}
[tag: bed]
I peered under the bed. Something glinted back at me.
- - (reaching)
* * [ Reach for it ]
I fished with one arm under the bed, but whatever it was, it had been kicked far enough back that I couldn't get my fingers on it.
-> reaching
* * {Inventory ? cane} [Knock it with the cane]
-> knock_with_cane
* * {reaching > 1 } [ Stand up ]
I stood up once more, and brushed my coat down.
CUTSCENE(visited, visit-bed)
-> top
* (knock_with_cane) {reaching && TURNS_SINCE(-> reaching) >= 4 && Inventory ? cane } [tag: bed]
* * [Use the cane to reach under the bed ]
- - Positioning the cane above the carpet, I gave the glinting thing a sharp tap. It slid out from under the foot of the bed.
~ move_to_supporter( knifeState, on_floor )
SPAWN_AT(knife-on-floor, knife)
* * (standup) [Stand up]
Satisfied, I stood up, and saw I had knocked free a bloodied knife.
CUTSCENE(visited, visit-bed)
-> top
* * [Look under the bed once more]
Moving the cane aside, I looked under the bed once more, but there was nothing more there.
-> standup
+ (knock_with_what) {reaching && ( TURNS_SINCE(-> reaching) < 4 or Inventory !? cane ) } [tag: bed]
Whatever was under the bed was enough back that I wouldn't be able to reach it without some kind of tool.
* {knifeState ? on_floor} [tag: knife]
Careful not to touch the handle, I lifted the blade from the carpet.
~ get(knife)
The blood was dry enough. Dry enough to show up partial prints on the hilt!
~ reach (prints_on_knife)
* [tag: desk]
I turned my attention to the desk. A lamp sat in one corner, a neat, empty in-tray in the other. There was nothing else out.
{Inventory !? cane: Leaning against the desk was a wooden cane.}
~ bedroomLightState += seen
- - (deskstate)
* * { bedroomLightState !? on } [Turn on the lamp]
-> operate_lamp ->
* * [Look at the in-tray ]
I regarded the in-tray, but there was nothing to be seen. Either the victim's papers were taken, or his line of work had seriously dried up. Or the in-tray was all for show.
+ + (open) {open < 3} [Open a drawer]
I tried {a drawer at random|another drawer|a third drawer}. {Locked|Also locked|Unsurprisingly, locked as well}.
* * {deskstate >= 2} [Something else?]
I took a step away from the desk once more.
CUTSCENE(visited, visit-desk)
-> top
- - -> deskstate
* (pickup_cane) {Inventory !? cane} [tag: cane]
~ get(cane)
I picked up the wooden cane. It was heavy, and unmarked.
* * {(Inventory ? cane) && TURNS_SINCE(-> pickup_cane) <= 2} [Swoosh the cane]
I was still holding the cane: I gave it an experimental swoosh. It was heavy indeed, though not heavy enough to be used as a bludgeon.
But it might have been useful in self-defence. Why hadn't the victim reached for it? Knocked it over?
* * [Something else?]
* [tag: window]
I went over to the window and peered out. A dismal view of the little brook that ran down beside the house.
- - (window_opts)
<- compare_prints(-> window_opts)
* * (downy) [Look down at the brook]
{ GlassState ? steamed:
Through the steamed glass I couldn't see the brook. -> see_prints_on_glass -> window_opts
}
I watched the little stream rush past for a while. The house probably had damp but otherwise, it told me nothing.
* * (greasy) [Look at the glass]
{ GlassState ? steamed: -> downy }
The glass in the window was greasy. No one had cleaned it in a while, inside or out.
* * { GlassState ? steamed && not see_prints_on_glass && downy && greasy }
[ Look at the steam ]
A cold day outside. Natural my breath should steam. -> see_prints_on_glass ->
+ + {GlassState ? steam_gone} [ Breathe on the glass ]
I breathed gently on the glass once more. { reached (fingerprints_on_glass): The fingerprints reappeared. }
~ GlassState = steamed
+ + [Something else?]
{ window_opts < 2 || reached (fingerprints_on_glass) || GlassState ? steamed:
I looked away from the dreary glass.
{GlassState ? steamed:
~ GlassState = steam_gone
<> The steam from my breath faded.
}
CUTSCENE(visited, visit-window)
-> top
}
I leant back from the glass. My breath had steamed up the pane a little.
~ GlassState = steamed
- - -> window_opts
* {top >= 5} [tag: exit-room]
I'd seen enough. I {bedroomLightState ? on:switched off the lamp, then} turned and left the room.
CUTSCENE(visited, switch-light-off)
SPAWN_AT(lamp-on-desk, lamp)
-> joe_in_hall
- -> top
= operate_lamp
I flicked the light switch.
{ bedroomLightState ? on:
<> The bulb fell dark.
~ bedroomLightState += off
~ bedroomLightState -= on
CUTSCENE(visited, switch-light-off)
- else:
{ bedroomLightState ? on_floor:
- <> A little light spilled under the bed.
CUTSCENE(visited, light-floor)
}
{ bedroomLightState ? on_desk :
- <> The light gleamed on the polished tabletop.
CUTSCENE(visited, light-desk)
}
~ bedroomLightState -= off
~ bedroomLightState += on
}
->->
= compare_prints (-> backto)
* { between ((fingerprints_on_glass, prints_on_knife), fingerprints_on_glass_match_knife) }
[Compare the prints between knife and window ]
Holding the bloodied knife near the window, I breathed to bring out the prints once more, and compared them as best I could.
Hardly scientific, but they seemed very similar - very similiar indeed.
~ reach (fingerprints_on_glass_match_knife)
-> backto
= see_prints_on_glass
~ reach (fingerprints_on_glass)
{But I could see a few fingerprints, as though someone had pressed their palm against it.|The fingerprints were quite clear and well-formed.} They faded as I watched.
~ GlassState = steam_gone
->->
= seen_light
+ [tag: lamp]
+ + {bedroomLightState !? on} [ Turn on lamp ]
-> operate_lamp ->
+ + {bedroomLightState ? on} [ Turn off lamp ]
-> operate_lamp ->
* * { bedroomLightState !? on_bed && BedState ? bloodstain_visible }
[ Move the light to the bed ]
SPAWN_AT(lamp-on-bed, lamp)
{bedroomLightState ? on:
- CUTSCENE(visited, light-floor)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_bed)
I moved the light over to the bloodstain and peered closely at it. It had soaked deeply into the fibres of the cotton sheet.
There was no doubt about it. This was where the blow had been struck.
~ reach (murdered_in_bed)
* * { bedroomLightState !? on_desk } {TURNS_SINCE(-> floorit) >= 2 }
[ Move the light back to the desk ]
SPAWN_AT(lamp-on-desk, lamp)
{bedroomLightState ? on:
- CUTSCENE(visited, light-desk)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_desk)
I moved the light back to the desk, setting it down where it had originally been.
* * (floorit) { bedroomLightState !? on_floor && darkunder }
[Move the light to the floor ]
SPAWN_AT(lamp-on-floor, lamp)
CUTSCENE(visited, move-away-from-light-floor)
{bedroomLightState ? on:
- CUTSCENE(visited, light-floor)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_floor)
I picked the light up and set it down on the floor.
+ + [Something else?]
- -> top
=== joe_in_hall
My police contact, Joe, was waiting in the hall. #TITLE
SPAWN_AT(player-in-hall)
+ [tag: joe] 'So?' he demanded. 'Did you find anything interesting?'
- (found)
* {found == 1} [Nothing.]
He shrugged. 'Shame.'
-> done
* { Inventory ? knife } [I found the murder weapon]
'Good going!' Joe replied with a grin. 'We thought the murderer had gotten rid of it. I'll bag that for you now.'
~ move_to_supporter(knifeState, with_joe)
* {reached(prints_on_knife)} { knifeState ? with_joe } [There are prints on the blade]
He regarded them carefully.
'Hrm. Not very complete. It'll be hard to get a match from these.'
~ reach (joe_seen_prints_on_knife)
* { reached((fingerprints_on_glass_match_knife, joe_seen_prints_on_knife)) }
[They match some prints on the window]
'Anyone could have touched the window,' Joe replied thoughtfully. 'But if they're more complete, they should help us get a decent match!'
~ reach (joe_wants_better_prints)
* { between(body_on_bed, murdered_in_bed)}
[The body was moved to the bed.]
'And then, at some point, moved back to the floor.' I added
'Why?'
* * [I don't know]
Joe nods. 'All right.'
* * [To get something from the floor?]
'You wouldn't move a whole body for that.'
* * [Perhaps he was killed in bed]
'It's just speculation at this point,' Joe remarks.
* { reached(murdered_in_bed) }
[The victim was murdered in bed]
'And then the body was moved to the floor.' I added
'Why?'
* * [I don't know]
Joe nods. 'All right, then.'
* * [The murderer wanted to mislead us?]
'How so?'
'They wanted us to think...
* * * ...the victim was awake[.'], I replied thoughtfully. 'That they were meeting their attacker, rather than being stabbed in their sleep.'
* * * ...there was some kind of struggle[.'],' I replied. 'That the victim wasn't simply stabbed in their sleep.'
- - - 'But if they were killed in bed, that's most likely what happened. Stabbed, while sleeping.'
~ reach (murdered_while_asleep)
* * [They hoped to clean up the scene?]
'But they were disturbed? It's possible.'
* { found > 1} [That's it]
'All right. It's a start,' Joe replied.
-> done
- -> found
- (done)
{
- between(joe_wants_better_prints, joe_got_better_prints):
~ reach (joe_got_better_prints)
<> 'I'll get those prints from the window now.'
- reached(joe_seen_prints_on_knife):
<> 'I'll run those prints as best I can.'
- else:
<> 'Not much to go on.'
}
THE END #TITLE
CUTSCENE(visited, ending)
-> END
<html lang="en" data-remix-generation="1" data-editor-live="https://smwhr.github.io/binksi" style="--tile-px:8px; --tile-select-zoom:5; --tileset-background-size:640px 80px;" data-app-mode="player"><head><style id="ace-monokai">.ace-monokai .ace_gutter {background: #2F3129;color: #8F908A}.ace-monokai .ace_print-margin {width: 1px;background: #555651}.ace-monokai {background-color: #000000;color: #F8F8F2}.ace-monokai .ace_cursor {color: #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection {background: #49483E}.ace-monokai.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #000000;}.ace-monokai .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active-line {background: #202020}.ace-monokai .ace_gutter-active-line {background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected-word {border: 1px solid #49483E}.ace-monokai .ace_invisible {color: #52524d}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta.ace_tag,.ace-monokai .ace_storage {color: #F92672}.ace-monokai .ace_punctuation,.ace-monokai .ace_punctuation.ace_tag {color: #fff}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other {color: #AE81FF}.ace-monokai .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function {color: #66D9EF}.ace-monokai .ace_fold {background-color: #A6E22E;border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type {font-style: italic;color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable {color: #A6E22E}.ace-monokai .ace_variable.ace_parameter {font-style: italic;color: #FD971F}.ace-monokai .ace_string {color: #E6DB74}.ace-monokai .ace_comment {color: #75715E}.ace-monokai .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y}
/*# sourceURL=ace/css/ace-monokai */</style><style id="error_marker.css"> .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }
/*# sourceURL=ace/css/error_marker.css */</style><style id="ace-tm">.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}
/*# sourceURL=ace/css/ace-tm */</style><style id="ace_editor.css">.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_editor {position: relative;overflow: hidden;padding: 0;font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;direction: ltr;text-align: left;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;box-sizing: border-box;min-width: 100%;contain: style size layout;font-variant-ligatures: no-common-ligatures;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: '';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;contain: style size layout;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {position: absolute;top: 0;left: 0;right: 0;padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {contain: strict;position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;contain: strict;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: transparent;color: inherit;z-index: 1000;opacity: 1;}.ace_composition_placeholder { color: transparent }.ace_composition_marker { border-bottom: 1px solid;position: absolute;border-radius: 0;margin-top: 1px;}[ace_nocontext=true] {transform: none!important;filter: none!important;clip-path: none!important;mask : none!important;contain: none!important;perspective: none!important;mix-blend-mode: initial!important;z-index: auto;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;height: 1000000px;contain: style size layout;}.ace_text-layer {font: inherit !important;position: absolute;height: 1000000px;width: 1000000px;contain: style size layout;}.ace_text-layer > .ace_line, .ace_text-layer > .ace_line_group {contain: style size layout;position: absolute;top: 0;left: 0;right: 0;}.ace_hidpi .ace_text-layer,.ace_hidpi .ace_gutter-layer,.ace_hidpi .ace_content,.ace_hidpi .ace_gutter {contain: strict;will-change: transform;}.ace_hidpi .ace_text-layer > .ace_line, .ace_hidpi .ace_text-layer > .ace_line_group {contain: strict;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_hasPlaceholder .ace_hidden-cursors .ace_cursor {opacity: 0;}.ace_smooth-blinking .ace_cursor {transition: opacity 0.18s;}.ace_animate-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: step-end;animation-name: blink-ace-animate;animation-iteration-count: infinite;}.ace_animate-blinking.ace_smooth-blinking .ace_cursor {animation-duration: 1000ms;animation-timing-function: ease-in-out;animation-name: blink-ace-animate-smooth;}@keyframes blink-ace-animate {from, to { opacity: 1; }60% { opacity: 0; }}@keyframes blink-ace-animate-smooth {from, to { opacity: 1; }45% { opacity: 1; }60% { opacity: 0; }85% { opacity: 0; }}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_error_bracket {position: absolute;border-bottom: 1px solid #DE5555;border-radius: 0;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;box-sizing: border-box;}.ace_line .ace_fold {box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block; }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_inline_button {border: 1px solid lightgray;display: inline-block;margin: -1px 8px;padding: 0 5px;pointer-events: auto;cursor: pointer;}.ace_inline_button:hover {border-color: gray;background: rgba(200,200,200,0.2);display: inline-block;pointer-events: auto;}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_mobile-menu {position: absolute;line-height: 1.5;border-radius: 4px;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;background: white;box-shadow: 1px 3px 2px grey;border: 1px solid #dcdcdc;color: black;}.ace_dark > .ace_mobile-menu {background: #333;color: #ccc;box-shadow: 1px 3px 2px grey;border: 1px solid #444;}.ace_mobile-button {padding: 2px;cursor: pointer;overflow: hidden;}.ace_mobile-button:hover {background-color: #eee;opacity:1;}.ace_mobile-button:active {background-color: #ddd;}.ace_placeholder {font-family: arial;transform: scale(0.9);transform-origin: left;white-space: pre;opacity: 0.7;margin: 0 10px;}
/*# sourceURL=ace/css/ace_editor.css */</style>
<title>binksi</title>
<meta charset="utf-8">
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAALVJREFUOE+lk9sNxSAIQHWE+8EKDuHWruMKJF2hDUYoILY3aT8aRDi8JKePX478EfGM9ACw2BvFzlHDPEQAiHgAwA8Rxb6UknrvcgYAlsVPA042IIiWXQZp3g/f8aPUFd2UrzOiCxckGwBHfstgBiWYBWwmYtSPGbwBdJncBylB10dyrTW11gYz6k8I8BnsGjvt7inwJHbRPHgZIxs8jdNB1of0D0RHXp6kjhDtRLRI8hK/bPQFgQJxEaOqVxQAAAAASUVORK5CYII=">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Press+Start+2P" type="text/css">
<!-- scripts-->
<script>const wrap = {};
wrap.before = function(object, method, callback) {
const original = object[method];
object[method] = async function (...args) {
await callback.call(this, ...args);
const result = await original.call(this, ...args);
return result;
};
}
wrap.after = function(object, method, callback) {
const original = object[method];
object[method] = async function (...args) {
const result = await original.call(this, ...args);
await callback.call(this, ...args);
return result;
};
}
wrap.replace = function(object, method, callback) {
object[method] = async function (...args) {
return callback.call(this, ...args);
};
}
wrap.splice = function(object, method, callback) {
const original = object[method];
object[method] = async function (...args) {
return callback.call(this, original, ...args);
};
}
</script>
<script>"strict"
const maker = {};
const ui = {};
/**
* @template TProject
* @typedef {(project: TProject) => string[]} maker.ManifestFunction
*/
/**
* @typedef {Object} ResourceData
* @property {string} type
* @property {any} data
*/
/**
* @typedef {Object.<string, ResourceData>} maker.ResourceBundle
*/
/**
* @template TProject
* @typedef {Object} maker.ProjectBundle
* @property {TProject} project
* @property {maker.ResourceBundle} resources
*/
/**
* @template TData
* @template TInstance
* @typedef {Object} maker.ResourceHandler
* @property {(data: TData) => Promise<TInstance>} load
* @property {(instance: TInstance) => Promise<TInstance>} copy
* @property {(instance: TInstance) => Promise<TData>} save
*/
/** @type {Map<string, maker.ResourceHandler<any, any>>} */
maker.resourceHandlers = new Map();
// add a resource type called "canvas-datauri" that describes how to load a
// canvas rendering context from a datauri, how to copy one, and how to convert
// one back into a datauri
maker.resourceHandlers.set("canvas-datauri", {
load: async (data) => imageToRendering2D(await loadImage(data)),
copy: async (instance) => copyRendering2D(instance),
save: async (instance) => instance.canvas.toDataURL("image/png", 1),
});
maker.resourceHandlers.set("file-datauri", {
load: async (data) => new File([await fetch(data.uri).then((r) => r.blob())], data.name, { type: data.type }),
copy: async (instance) => new File([await instance.arrayBuffer()], instance.name, { type: instance.type }),
save: async (instance) => ({
name: instance.name,
uri: await maker.dataURIFromFile(instance),
type: instance.type,
}),
});
maker.ResourceManager = class {
constructor() {
this.lastId = 0;
/** @type {Map<string, { type: string, instance: any }>} */
this.resources = new Map();
}
/**
* Generate a new unique id for a resource.
* @returns {string}
*/
generateId() {
this.lastId += 1;
// just next lowest unused number
while (this.resources.has(this.lastId.toString())) {
this.lastId += 1;
}
return this.lastId.toString();
}
/**
* Clear all resources.
*/
clear() {
this.resources.clear();
}
/**
* Get the resource instance with the given id.
* @param {string} id
* @returns {any}
*/
get(id) {
return this.resources.get(id)?.instance;
}
/**
* Add a resource instance at a specific id.
* @param {string} id
* @param {any} instance
* @param {string} type
*/
set(id, instance, type) {
this.resources.set(id, { type, instance });
}
/**
* Add an instance as a new resource and return its new id.
* @param {any} instance
* @param {string} type
* @returns {string}
*/
add(instance, type) {
const id = this.generateId();
this.set(id, instance, type);
return id;
}
/**
* Copy the existing resource with the given id and add it as a new resource.
* @param {string} id
* @returns
*/
async fork(id) {
const source = this.resources.get(id);
const forkId = this.generateId();
const instance = await maker.resourceHandlers.get(source.type).copy(source.instance);
this.set(forkId, instance, source.type);
return { id: forkId, instance };
}
/**
* Discard all resources except those at the ids given.
* @param {Iterable<string>} keepIds
*/
prune(keepIds) {
const ids = new Set(keepIds);
this.resources.forEach((_, id) => {
if (!ids.has(id)) this.resources.delete(id);
});
}
/**
* Copy all resources from another resource manager.
* @param {maker.ResourceManager} other
*/
async copyFrom(other) {
const tasks = [];
Array.from(other.resources).forEach(([id, { type, instance }]) => {
const task = maker.resourceHandlers.get(type)
.copy(instance)
.then((copy) => this.set(id, copy, type));
tasks.push(task);
});
return Promise.all(tasks);
}
/**
* Save all resources in an object mapping id to type and save data.
* @param {Iterable<string>} ids
* @returns {Promise<maker.ResourceBundle>}
*/
async save(ids) {
/** @type {maker.ResourceBundle} */
const bundle = {};
const resourceIds = new Set(ids);
const relevant = Array.from(this.resources)
.filter(([id]) => resourceIds.has(id));
const tasks = [];
Array.from(relevant).forEach(([id, { type, instance }]) => {
const task = maker.resourceHandlers.get(type)
.save(instance)
.then((data) => bundle[id] = { type, data });
tasks.push(task);
});
await Promise.all(tasks);
return bundle;
}
/**
* Load all resources from the given bundle.
* @param {maker.ResourceBundle} bundle
*/
async load(bundle) {
const tasks = [];
Object.entries(bundle).forEach(([id, { type, data }]) => {
const task = maker.resourceHandlers.get(type)
.load(data)
.then((instance) => this.set(id, instance, type));
tasks.push(task);
});
return Promise.all(tasks);
}
}
/**
*
* @template TState
*/
maker.StateManager = class extends EventTarget {
/**
* Create a state manager, optionally providing a function that describes
* how to determine resource dependencies of a given state.
* @param {maker.ManifestFunction<TState>} getManifest
*/
constructor(getManifest = undefined) {
super();
/** @type {maker.ManifestFunction<TState>} */
this.getManifest = getManifest || (() => []);
this.resources = new maker.ResourceManager();
/** @type {TState[]} */
this.history = [];
this.index = -1;
this.historyLimit = 20;
}
/**
* The present state in history.
*/
get present() {
return this.history[this.index];
}
/**
* Is there any edit history to undo to?
*/
get canUndo() {
return this.index > 0;
}
/**
* Are there any undone edits to redo?
*/
get canRedo() {
return this.index < this.history.length - 1;
}
/**
* Replace all state with the project and resources in the given project
* bundle.
* @param {maker.ProjectBundle<TState>} bundle
*/
async loadBundle(bundle) {
this.history.length = 0;
this.history.push(bundle.project);
this.index = 0;
this.resources.clear();
await this.resources.load(bundle.resources);
this.changed();
}
/**
* Replace all state by copying from another state manager.
* @param {maker.StateManager<TState>} other
*/
async copyFrom(other) {
this.history = COPY(other.history);
this.index = other.index;
this.resources.clear();
await this.resources.copyFrom(other.resources);
this.changed();
}
/**
* Replace all state by copying just the present and dependent resources
* from another state manager.
* @param {maker.StateManager<TState>} other
*/
async copyPresentFrom(other) {
this.history = [COPY(other.present)];
this.index = 0;
this.resources.clear();
// TODO: only copy what's not going to be pruned..
await this.resources.copyFrom(other.resources);
this.pruneResources();
this.changed();
}
/**
* Copy the present state and dependent resources into a project bundle.
* @returns {Promise<maker.ProjectBundle<TState>>}
*/
async makeBundle() {
const project = COPY(this.present);
const resources = await this.resources.save(this.getManifest(this.present));
return { project, resources };
}
/**
* Save the current state as a checkpoint in history that can be returned to
* with undo/redo.
*/
makeCheckpoint() {
this.history.length = this.index + 1;
const currentData = this.present;
this.history[this.index] = COPY(currentData);
this.history.push(currentData);
if (this.index < this.historyLimit) {
this.index += 1;
} else {
// delete earliest history
this.history.splice(0, 1);
this.pruneResources();
}
}
/**
* Dispatch the change event signalling that the present state has been
* updated.
*/
changed() {
this.dispatchEvent(new CustomEvent("change"));
}
/**
* Discard all resources that are no longer required accord to the manifest
* function.
*/
pruneResources() {
this.resources.prune(this.history.flatMap(this.getManifest));
}
/**
* Make a history checkpoint, replace the current state with a forked
* version via callback, and then dispatch the change event.
* @param {(data: TState) => Promise} action
*/
async makeChange(action) {
this.makeCheckpoint();
await action(this.present);
this.changed();
}
/**
* Revert the state to the previous checkpoint in history.
*/
undo() {
if (!this.canUndo) return;
this.index -= 1;
this.changed();
}
/**
* Return the state to the most recently undone checkpoint in history.
*/
redo() {
if (!this.canRedo) return;
this.index += 1;
this.changed();
}
};
/**
* Ask the browser to download the given blob as a file with the given name.
* @param {Blob} blob
* @param {string} name
*/
maker.saveAs = function(blob, name) {
const element = document.createElement("a");
const url = window.URL.createObjectURL(blob);
element.href = url;
element.download = name;
element.click();
window.URL.revokeObjectURL(url);
};
/**
* Open the browser file picker, optionally restricted to files of a given file
* type pattern and optionally accepting multiple files.
* @param {string} accept
* @param {boolean} multiple
* @returns {Promise<File[]>}
*/
maker.pickFiles = async function(accept = "*", multiple = false) {
return new Promise((resolve) => {
const fileInput = html("input", { type: "file", accept, multiple });
fileInput.addEventListener("change", () => resolve(Array.from(fileInput.files)));
fileInput.click();
});
}
/**
* Read plain text from a file.
* @param {File} file
* @return {Promise<string>}
*/
maker.textFromFile = async function(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => resolve(/** @type {string} */ (reader.result));
reader.readAsText(file);
});
}
/**
* Read image from a file.
* @param {File} file
* @return {Promise<string>}
*/
maker.dataURIFromFile = async function(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => resolve(/** @type {string} */ (reader.result));
reader.readAsDataURL(file);
});
}
/**
* Create a DOM for an html page from html source code
* @param {string} source
* @returns
*/
maker.htmlFromText = function(source) {
const template = document.createElement('template');
template.innerHTML = source;
return template.content;
}
/**
* @param {string} text
*/
maker.textToBlob = function(text, type = "text/plain") {
return new Blob([text], { type });
}
/**
*
* @param {ParentNode} html
*/
maker.bundleFromHTML = function(html, query="#bundle-embed") {
let json = ONE(query, html)?.textContent;
const bundle = json ? JSON.parse(json.charCodeAt(0) == 123 ? json : json.substring(1)) : undefined;
return bundle;
}
/**
*
* @param {ParentNode} html
*/
maker.storyFromHTML = function(html, query="#story-source") {
let inktext = ONE(query, html)?.textContent;
return inktext;
}
class RadioGroupWrapper extends EventTarget {
/** @param {HTMLInputElement[]} inputs */
constructor(inputs) {
super();
const group = this;
this.onRadioChange = function() {
if (!this.checked) return;
group.dispatchEvent(new CustomEvent("change"));
}
this.inputs = [];
this.replaceInputs(inputs);
}
get selectedIndex() {
return this.inputs.findIndex((button) => button.checked);
}
set selectedIndex(value) {
this.inputs[value].click();
}
get selectedInput() {
return this.inputs[this.selectedIndex];
}
get value() {
return this.selectedInput?.value;
}
get valueAsNumber() {
return parseInt(this.selectedInput?.value ?? "-1", 10);
}
setSelectedIndexSilent(value) {
this.inputs.forEach((input, index) => input.checked = index === value);
}
setValueSilent(value) {
value = value.toString();
this.inputs.forEach((input) => input.checked = input.value === value);
}
/**
* @param {HTMLElement} element
* @param {...string} values
*/
tab(element, ...values) {
this.addEventListener("change", () => element.hidden = !values.includes(this.value));
}
/**
* @param {HTMLInputElement} radioElement
*/
add(radioElement) {
this.inputs.push(radioElement);
radioElement.addEventListener("change", this.onRadioChange);
}
/**
* @param {HTMLInputElement} radioElement
*/
remove(radioElement) {
arrayDiscard(this.inputs, radioElement);
radioElement.removeEventListener("change", this.onRadioChange);
}
removeAll() {
this.inputs.forEach((element) => element.removeEventListener("change", this.onRadioChange));
this.inputs.length = 0;
}
replaceInputs(inputs) {
this.removeAll();
inputs.forEach((input) => this.add(input));
}
}
class CheckboxWrapper extends EventTarget {
/** @param {HTMLInputElement[]} inputs */
constructor(inputs) {
super();
this.inputs = inputs;
inputs.forEach((input) => {
input.addEventListener("change", () => {
this.setCheckedSilent(input.checked);
this.dispatchEvent(new CustomEvent("change"));
});
});
}
get checked() {
return this.inputs[0].checked;
}
set checked(value) {
if (this.checked !== value) this.inputs[0].click();
}
setCheckedSilent(value) {
this.inputs.forEach((input) => input.checked = value);
}
}
class ButtonAction extends EventTarget {
/** @param {HTMLButtonElement[]} buttons */
constructor(buttons) {
super();
this.buttons = buttons;
this.disabled = false;
buttons.forEach((button) => {
button.addEventListener("click", () => this.invoke());
});
}
get disabled() {
return this._disabled;
}
set disabled(value) {
this._disabled = value;
this.buttons.forEach((button) => button.disabled = value);
}
invoke(force = false) {
if (!force && this.disabled) return;
this.dispatchEvent(new CustomEvent("invoke"));
}
}
/**
* Get a wrapper for the radio input elements sharing the given name.
* @param {string} name
* @returns {RadioGroupWrapper}
*/
ui.radio = (name) => new RadioGroupWrapper(ALL(`input[type="radio"][name="${name}"]`));
ui.toggle = (name) => new CheckboxWrapper(ALL(`input[type="checkbox"][name="${name}"]`));
/**
* @param {string} name
* @returns {HTMLInputElement}
*/
ui.slider = (name) => ONE(`input[type="range"][name=${name}]`);
/**
* @param {string} name
* @returns {HTMLInputElement | HTMLTextAreaElement}
*/
ui.text = (name) => ONE(`[name=${name}]`);
/** @type {Map<string, ButtonAction>} */
ui.actions = new Map();
/**
* Get an action linked to all button elements sharing the given name.
* Optionally provide a default listener for the action.
* @param {string} name
* @param {() => void} listener
* @returns {ButtonAction}
*/
ui.action = function (name, listener=undefined) {
const action = new ButtonAction(ALL(`button[name="${name}"]`));
ui.actions.set(name, action);
if (listener) action.addEventListener("invoke", listener);
return action;
}
/**
* Get the html select element with the given name.
* @param {string} name
* @returns {HTMLSelectElement}
*/
ui.select = (name) => ONE(`select[name="${name}"]`);
/**
* Get a child element matching CSS selector.
* @param {string} query
* @param {ParentNode} element
* @returns {HTMLElement}
*/
const ONE = (query, element = undefined) => (element || document).querySelector(query);
/**
* Get all children elements matching CSS selector.
* @param {string} query
* @param {HTMLElement | Document} element
* @returns {HTMLElement[]}
*/
const ALL = (query, element = undefined) => Array.from((element || document).querySelectorAll(query));
/**
* @template {any} T
* @param {T[]} array
* @param {T} value
* @returns {boolean}
*/
function arrayDiscard(array, value) {
const index = array.indexOf(value);
if (index >= 0) array.splice(index, 1);
return index >= 0;
}
ui.PointerDrag = class extends EventTarget {
/**
* @param {MouseEvent} event
*/
constructor(event, { clickMovementLimit = 5 } = {}) {
super();
this.pointerId = event["pointerId"];
this.clickMovementLimit = 5;
this.totalMovement = 0;
this.downEvent = event;
this.lastEvent = event;
this.listeners = {
"pointerup": (event) => {
if (event.pointerId !== this.pointerId) return;
this.lastEvent = event;
this.unlisten();
this.dispatchEvent(new CustomEvent("up", { detail: event }));
if (this.totalMovement <= clickMovementLimit) {
this.dispatchEvent(new CustomEvent("click", { detail: event }));
}
},
"pointermove": (event) => {
if (event.pointerId !== this.pointerId) return;
this.lastEvent = event;
this.totalMovement += Math.abs(event.movementX);
this.totalMovement += Math.abs(event.movementY);
this.dispatchEvent(new CustomEvent("move", { detail: event }));
}
}
document.addEventListener("pointerup", this.listeners.pointerup);
document.addEventListener("pointermove", this.listeners.pointermove);
}
unlisten() {
document.removeEventListener("pointerup", this.listeners.pointerup);
document.removeEventListener("pointermove", this.listeners.pointermove);
}
}
/**
* Wrap a pointer down event and track its subsequent movement until release.
* @param {PointerEvent} event
* @returns {ui.PointerDrag}
*/
ui.drag = (event) => new ui.PointerDrag(event);
/**
* @param {HTMLCanvasElement} canvas
* @param {MouseEvent} event
*/
function mouseEventToCanvasPixelCoords(canvas, event) {
const bounds = canvas.getBoundingClientRect();
const [mx, my] = [event.clientX - bounds.x, event.clientY - bounds.y];
const scale = canvas.width / canvas.clientWidth;
const [px, py] = [Math.floor(mx * scale), Math.floor(my * scale)];
return { x: px, y: py };
}
/**
* @param {HTMLCanvasElement} canvas
* @param {ui.PointerDrag} drag
*/
function trackCanvasStroke(canvas, drag) {
const positions = [mouseEventToCanvasPixelCoords(canvas, drag.downEvent)];
const update = (event) => positions.push(mouseEventToCanvasPixelCoords(canvas, event.detail));
drag.addEventListener("up", update);
drag.addEventListener("move", update);
return positions;
}
// from https://github.com/ai/nanoid/blob/master/non-secure/index.js
const urlAlphabet = 'ModuleSymbhasOwnPr-0123456789ABCDEFGHNRVfgctiUvz_KqYTJkLxpZXIjQW';
function nanoid(size = 21) {
let id = '';
let i = size;
while (i--) id += urlAlphabet[(Math.random() * 64) | 0];
return id
}
/**
* Deep copy an object by serializing it to json and parsing it again.
* @template T
* @param {T} object
* @returns {T}
*/
const COPY = (object) => JSON.parse(JSON.stringify(object));
/**
* Create an array of zeroes to the given length.
* @param {number} length
* @returns {number[]}
*/
const ZEROES = (length) => Array(length).fill(0);
/**
* Create an array of a value repeated to the given length.
* @template T
* @param {number} length
* @param {T} value
* @returns {T[]}
*/
const REPEAT = (length, value) => Array(length).fill(value);
/**
* Create an html element with the given attributes and children.
* @template {keyof HTMLElementTagNameMap} K
* @param {K} tagName
* @param {*} attributes
* @param {...(Node | string)} children
* @returns {HTMLElementTagNameMap[K]}
*/
function html(tagName, attributes = {}, ...children) {
const element = /** @type {HTMLElementTagNameMap[K]} */ (document.createElement(tagName));
Object.entries(attributes).forEach(([name, value]) => element.setAttribute(name, value));
children.forEach((child) => element.append(child));
return element;
}
/** @param {number} milliseconds */
function sleep(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
/**
* @template T
* @param {IDBRequest<T>} request
* @returns {Promise<T>}
*/
function promisfyRequest(request) {
return new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
}
/**
* @param {IDBTransaction} transaction
* @returns {Promise}
*/
function promisfyTransaction(transaction) {
return new Promise((resolve, reject) => {
transaction.oncomplete = () => resolve();
transaction.onabort = () => reject(transaction.error);
transaction.onerror = () => reject(transaction.error);
});
}
maker.ProjectStorage = class {
constructor(appID, generateMeta=undefined) {
this.appID = appID;
this.generateMeta = generateMeta;
this.error = undefined;
this.openDatabase().then(
(request) => request.close(),
(reason) => this.error = reason,
);
}
get available() {
return this.error === undefined;
}
async openDatabase() {
const request = indexedDB.open(this.appID);
request.addEventListener("upgradeneeded", () => {
request.result.createObjectStore("projects");
request.result.createObjectStore("projects-meta");
});
return promisfyRequest(request);
}
async stores(mode) {
const db = await this.openDatabase();
const transaction = db.transaction(["projects", "projects-meta"], mode);
const projects = transaction.objectStore("projects");
const meta = transaction.objectStore("projects-meta");
return { transaction, projects, meta };
}
/**
* @returns {Promise<any[]>}
*/
async list() {
const stores = await this.stores("readonly");
return promisfyRequest(stores.meta.getAll());
}
/**
* @param {any} projectData
* @returns {Promise}
*/
async save(projectData, key) {
const meta = { date: (new Date()).toISOString() };
if (this.generateMeta) Object.assign(meta, this.generateMeta(projectData));
const stores = await this.stores("readwrite");
stores.projects.put(projectData, key);
stores.meta.put(meta, key);
return promisfyTransaction(stores.transaction);
}
/**
* @param {string} key
* @returns {Promise<any>}
*/
async load(key) {
const stores = await this.stores("readonly");
return promisfyRequest(stores.projects.get(key));
}
/**
* @param {string} key
*/
async delete(key) {
const stores = await this.stores("readwrite");
stores.projects.delete(key);
stores.meta.delete(key);
return promisfyTransaction(stores.transaction);
}
}
</script>
<script>/**
* @param {number} width
* @param {number} height
* @returns {CanvasRenderingContext2D}
*/
function createRendering2D(width, height) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const context = canvas.getContext('2d');
context.imageSmoothingEnabled = false;
return context;
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {string | CanvasGradient | CanvasPattern | undefined} fillStyle
*/
function fillRendering2D(rendering, fillStyle = undefined) {
if (fillStyle !== undefined) {
const prevStyle = rendering.fillStyle;
rendering.fillStyle = fillStyle;
rendering.fillRect(0, 0, rendering.canvas.width, rendering.canvas.height);
rendering.fillStyle = prevStyle;
} else {
rendering.clearRect(0, 0, rendering.canvas.width, rendering.canvas.height);
}
}
/**
* @param {CanvasRenderingContext2D} source
* @param {CanvasRenderingContext2D} destination
* @param {{ x: number, y: number, w: number, h: number }} rect
*/
function copyRendering2D(
source,
destination = undefined,
rect = undefined,
) {
rect = rect ?? { x: 0, y: 0, w: source.canvas.width, h: source.canvas.height };
destination = destination || createRendering2D(rect.w, rect.h);
destination.canvas.width = rect.w;
destination.canvas.height = rect.h;
destination.drawImage(
source.canvas,
rect.x, rect.y, rect.w, rect.h,
0, 0, rect.w, rect.h,
);
return destination;
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {number} width
* @param {number} height
*/
function resizeRendering2D(rendering, width, height) {
const copy = copyRendering2D(rendering);
rendering.canvas.width = width;
rendering.canvas.height = height;
rendering.drawImage(copy.canvas, 0, 0);
}
/**
* @param {CanvasRenderingContext2D} rendering
*/
function invertMask(rendering) {
withPixels(rendering, (pixels) => {
for (let i = 0; i < pixels.length; ++i) {
pixels[i] = 0xFFFFFFFF - pixels[i];
}
});
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {number} dx
* @param {number} dy
*/
function cycleRendering2D(rendering, dx, dy) {
const { width, height } = rendering.canvas;
const sx = -Math.sign(dx);
const sy = -Math.sign(dy);
const temp = copyRendering2D(rendering);
fillRendering2D(rendering);
rendering.drawImage(temp.canvas, dx, dy );
rendering.drawImage(temp.canvas, dx + width*sx, dy );
rendering.drawImage(temp.canvas, dx + width*sx, dy + height*sy);
rendering.drawImage(temp.canvas, dx, dy + height*sy);
}
/**
* @param {CanvasRenderingContext2D} rendering
*/
function mirrorRendering2D(rendering) {
const prevComposite = rendering.globalCompositeOperation;
rendering.globalCompositeOperation = "copy";
rendering.scale(-1, 1);
rendering.drawImage(rendering.canvas, -rendering.canvas.width, 0);
rendering.globalCompositeOperation = prevComposite;
}
/**
* @param {CanvasRenderingContext2D} rendering
*/
function flipRendering2D(rendering) {
const prevComposite = rendering.globalCompositeOperation;
rendering.globalCompositeOperation = "copy";
rendering.scale(1, -1);
rendering.drawImage(rendering.canvas, 0, -rendering.canvas.height);
rendering.globalCompositeOperation = prevComposite;
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {number} turns
*/
function turnRendering2D(rendering, turns=1) {
const { width, height } = rendering.canvas;
const prevComposite = rendering.globalCompositeOperation;
rendering.globalCompositeOperation = "copy";
rendering.setTransform(1, 0, 0, 1, width/2, height/2);
rendering.rotate(turns * Math.PI / 2);
rendering.drawImage(rendering.canvas, -width/2, -height/2);
rendering.globalCompositeOperation = prevComposite;
}
/**
* @callback pixelsAction
* @param {Uint32Array} pixels
*/
/**
* @param {CanvasRenderingContext2D} rendering
* @param {pixelsAction} action
*/
function withPixels(rendering, action) {
const imageData = rendering.getImageData(0, 0, rendering.canvas.width, rendering.canvas.height);
action(new Uint32Array(imageData.data.buffer));
rendering.putImageData(imageData, 0, 0);
}
/**
* @param {CanvasRenderingContext2D} mask
* @param {string} style
* @param {CanvasRenderingContext2D} destination
*/
function recolorMask(mask, style, destination = undefined) {
const recolored = copyRendering2D(mask, destination);
recolored.globalCompositeOperation = "source-in";
fillRendering2D(recolored, style);
return recolored;
}
/**
* @param {number} x0
* @param {number} y0
* @param {number} x1
* @param {number} y1
* @param {(x: number, y: number) => void} plot
*/
// adapted from https://stackoverflow.com/a/34267311
function lineplot(x0, y0, x1, y1, plot) {
x0 |= 0; y0 |= 0; x1 |= 0; y1 |= 0;
const steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep) [x0, y0, x1, y1] = [y0, x0, y1, x1];
const dx = Math.abs(x1 - x0);
const dy = Math.abs(y1 - y0);
const ystep = Math.sign(y1 - y0);
const xstep = Math.sign(x1 - x0);
let err = Math.floor(dx / 2);
let y = y0;
if (dx === 0 && dy === 0) {
plot(x0, y0);
}
for (let x = x0; x != (x1 + xstep); x += xstep) {
plot(steep ? y : x, steep ? x : y);
err -= dy;
if (err < 0) {
y += ystep;
err += dx;
}
}
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {number} x
* @param {number} y
* @param {number} color
*/
function floodfill(rendering, x, y, color, tolerance = 5) {
const [width, height] = [rendering.canvas.width, rendering.canvas.height];
withPixels(rendering, pixels => {
const queue = [[x, y]];
const done = new Array(width * height);
const initial = pixels[y * width + x];
const ir = initial >>> 0 & 0xFF;
const ig = initial >>> 8 & 0xFF;
const ib = initial >>> 16 & 0xFF;
function enqueue(x, y) {
const within = x >= 0 && y >= 0 && x < width && y < height;
if (within && !done[y * width + x]) {
const pixel = pixels[y * width + x];
const pr = pixel >>> 0 & 0xFF;
const pg = pixel >>> 8 & 0xFF;
const pb = pixel >>> 16 & 0xFF;
const dist = Math.abs(pr - ir) + Math.abs(pg - ig) + Math.abs(pb - ib);
if (dist <= tolerance) queue.push([x, y]);
}
}
while (queue.length > 0) {
const [x, y] = queue.pop();
pixels[y * width + x] = color;
done[y * width + x] = true;
enqueue(x - 1, y);
enqueue(x + 1, y);
enqueue(x, y - 1);
enqueue(x, y + 1);
}
});
};
/**
* @param {CanvasRenderingContext2D} rendering
* @param {number} x
* @param {number} y
* @param {number} color
* @returns {CanvasRenderingContext2D}
*/
function floodfillOutput(rendering, x, y, color) {
const [width, height] = [rendering.canvas.width, rendering.canvas.height];
const output = createRendering2D(width, height);
withPixels(rendering, srcPixels =>
withPixels(output, dstPixels => {
const queue = [[x, y]];
const done = new Array(width * height);
const initial = srcPixels[y * width + x];
function enqueue(x, y) {
const within = x >= 0 && y >= 0 && x < width && y < height;
if (within && srcPixels[y * width + x] === initial && !done[y * width + x]) {
queue.push([x, y]);
}
}
while (queue.length > 0) {
const [x, y] = queue.pop();
dstPixels[y * width + x] = color;
done[y * width + x] = true;
enqueue(x - 1, y);
enqueue(x + 1, y);
enqueue(x, y - 1);
enqueue(x, y + 1);
}
}));
return output;
};
/**
* @param {{r:number,g:number,b:number}} rgb
*/
function rgbToHex(rgb) {
const packed = (0xFF000000 + (rgb.r << 16) + (rgb.g << 8) + (rgb.b << 0));
return "#" + packed.toString(16).substr(-6);
}
/**
* @param {string} hex
* @param {number} alpha
*/
function hexToUint32(hex, alpha = undefined) {
if (hex.charAt(0) === '#') hex = hex.substring(1);
if (alpha === undefined && hex.length === 8) alpha = parseInt(hex.substr(6, 2), 16);
if (alpha === undefined) alpha = 255;
hex = hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2);
return (parseInt(hex, 16) | (alpha << 24)) >>> 0;
}
/**
* @param {number} number
* @param {string} prefix
*/
function numberToHex(number, prefix = '#') {
number = (number | 0xff000000) >>> 0;
let hex = number.toString(16).substring(2, 8);
hex = hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2);
return prefix + hex;
}
const MASK_PALETTE = {
'_': hexToUint32('#000000', 0),
default: hexToUint32('#FFFFFF', 255),
};
/**
* @param {string} text
* @param {Record<string, number>} palette
* @returns {CanvasRenderingContext2D}
*/
function textToRendering2D(text, palette = MASK_PALETTE) {
text = text.trim();
const lines = text.split('\n').map((line) => [...line.trim()]);
const width = lines[0].length;
const height = lines.length;
const rendering = createRendering2D(width, height);
withPixels(rendering, (pixels) => {
lines.forEach((line, y) => line.forEach((char, x) => {
const color = palette[char];
pixels[y * width + x] = color !== undefined ? color : palette.default;
}));
});
return rendering;
}
/**
* @param {{ h: number, s: number, v: number }} hsv
*/
function HSVToRGB(hsv) {
const { h, s, v } = hsv;
let r, g, b;
const i = Math.floor(h * 6);
const f = h * 6 - i;
const p = (1 - s);
const q = (1 - f * s);
const t = (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = 1, g = t, b = p; break;
case 1: r = q, g = 1, b = p; break;
case 2: r = p, g = 1, b = t; break;
case 3: r = p, g = q, b = 1; break;
case 4: r = t, g = p, b = 1; break;
case 5: r = 1, g = p, b = q; break;
}
r *= v * 255;
g *= v * 255;
b *= v * 255;
return { r, g, b };
}
/**
* @param {{ r: number, g: number, b: number }} rgb
*/
function RGBToHSV(rgb) {
const { r, g, b } = rgb;
var max = Math.max(r, g, b), min = Math.min(r, g, b),
d = max - min,
h,
s = (max === 0 ? 0 : d / max),
v = max / 255;
switch (max) {
case min: h = 0; break;
case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;
case g: h = (b - r) + d * 2; h /= 6 * d; break;
case b: h = (r - g) + d * 4; h /= 6 * d; break;
}
return { h, s, v };
}
function HSVToCone(hsv) {
const a = Math.PI * hsv.h;
const r = hsv.s * .5 * hsv.v;
const x = Math.cos(a) * r;
const y = Math.sin(a) * r;
return { x, y, z: hsv.v };
}
function uint32ToRGB(uint32) {
return {
r: uint32 >>> 0 & 0xFF,
g: uint32 >>> 8 & 0xFF,
b: uint32 >>> 16 & 0xFF,
uint32,
};
}
function hexToRGB(hex) {
if (hex.charAt(0) === '#') hex = hex.substring(1);
return {
b: parseInt(hex.substr(4, 2), 16),
g: parseInt(hex.substr(2, 2), 16),
r: parseInt(hex.substr(0, 2), 16),
uint32: hexToUint32(hex),
};
}
function RGBToUint32(rgb) {
return rgb.r | rgb.g << 8 | rgb.b << 16 | 0xFF << 24;
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {string[]} palette
*/
function recolorToPalette(rendering, palette) {
const paletteConverted = palette.map((hex) => {
const cone = HSVToCone(RGBToHSV(hexToRGB(hex)));
const uint32 = hexToUint32(hex);
return { ...cone, uint32 };
});
const mapping = new Map();
function chooseColor(uint32) {
const alpha = (uint32 >>> 24) < 16;
if (alpha) return 0;
const existing = mapping.get(uint32);
if (existing) return existing;
const actual = HSVToCone(RGBToHSV(uint32ToRGB(uint32)));
let bestSqrDistance = Infinity;
let best = paletteConverted[0];
for (let candidate of paletteConverted) {
const dx = Math.abs(actual.x - candidate.x);
const dy = Math.abs(actual.y - candidate.y);
const dz = Math.abs(actual.z - candidate.z);
const sqrDistance = dx*dx + dy*dy + dz*dz;
if (sqrDistance < bestSqrDistance) {
bestSqrDistance = sqrDistance;
best = candidate;
}
}
mapping.set(uint32, best.uint32);
return best.uint32;
}
withPixels(rendering, (pixels) => {
for (let i = 0; i < pixels.length; ++i) {
pixels[i] = chooseColor(pixels[i]);
}
});
}
/**
* Copy image contents to a new canvas rendering context.
* @param {HTMLImageElement} image
*/
function imageToRendering2D(image) {
const rendering = createRendering2D(image.naturalWidth, image.naturalHeight);
rendering.drawImage(image, 0, 0);
return rendering;
}
/**
* Create an html image from a given src (probably a datauri).
* @param {string} src
* @returns {Promise<HTMLImageElement>}
*/
async function loadImage(src) {
return new Promise((resolve, reject) => {
const image = document.createElement("img");
image.addEventListener("load", () => resolve(image));
image.addEventListener("error", reject);
image.src = src;
});
}
function loadImageLazy(src) {
const image = document.createElement("img");
image.src = src;
return image;
}
/**
* In the given rendering, replace every instance of a color in the prev palette
* with the corresponding color in the next palette, ignoring colors that don't
* appear. This is broken in firefox because colors are not stored exactly.
* @param {CanvasRenderingContext2D} rendering
* @param {string[]} prev
* @param {string[]} next
*/
function swapPalette(rendering, prev, next) {
const mapping = new Map();
prev.forEach((pixel, index) => mapping.set(prev[index], next[index]));
withPixels(rendering, (pixels) => {
for (let i = 0; i < pixels.length; ++i) {
pixels[i] = mapping.get(pixels[i]) || pixels[i];
}
});
}
/**
* Replace every color in the given rendering. Each existing color is matched
* to the closest color in the prev palette and replaced with the corresponding
* color in the next palette.
* @param {CanvasRenderingContext2D} rendering
* @param {number[]} prev
* @param {number[]} next
*/
function swapPaletteSafe(rendering, prev, next) {
const mapping = new Map();
for (let i = 0; i < prev.length; ++i) {
mapping.set(prev[i], next[i % next.length]);
}
function addMissing(prevPixel) {
let bestDistance = Infinity;
let bestNextPixel = next[0];
const pr = prevPixel >>> 0 & 0xFF;
const pg = prevPixel >>> 8 & 0xFF;
const pb = prevPixel >>> 16 & 0xFF;
for (let i = 0; i < prev.length; ++i) {
const target = prev[i];
const tr = target >>> 0 & 0xFF;
const tg = target >>> 8 & 0xFF;
const tb = target >>> 16 & 0xFF;
const dist = Math.abs(pr - tr)
+ Math.abs(pg - tg)
+ Math.abs(pb - tb);
if (dist < bestDistance) {
bestDistance = dist;
bestNextPixel = next[i];
}
}
mapping.set(prevPixel, bestNextPixel);
return bestNextPixel;
}
withPixels(rendering, (pixels) => {
for (let i = 0; i < pixels.length; ++i) {
const prev = pixels[i];
pixels[i] = mapping.get(prev) ?? addMissing(prev);
}
});
}
/**
* @param {HTMLCanvasElement} canvas
*/
async function canvasToBlob(canvas) {
return new Promise((resolve) => canvas.toBlob(resolve));
}
</script>
<script>/**
* @typedef {Object} Vector2
* @property {number} x
* @property {number} y
*/
/**
* @typedef {Object} Rect
* @property {number} x
* @property {number} y
* @property {number} width
* @property {number} height
*/
/**
* @param {number} min
* @param {number} max
*/
function range(min, max) {
return Array.from(new Array(max-min+1), (x, i) => i + min);
}
/**
* @typedef {Object} BlitsyFontCharacter
* @property {number} codepoint
* @property {CanvasImageSource} image
* @property {number} spacing
*/
/**
* @typedef {Object} BlitsyFont
* @property {string} name
* @property {number} lineHeight
* @property {Map<number, BlitsyFontCharacter>} characters
*/
/**
* @typedef {Object} BlitsyGlyph
* @property {HTMLCanvasElement} image
* @property {Vector2} position
* @property {Vector2} offset
* @property {boolean} hidden
* @property {string} fillStyle
* @property {Map<string, any>} styles
*/
/**
* @typedef {Object} BlitsyTextRenderOptions
* @property {BlitsyFont} font
* @property {number} lineCount
* @property {number} lineWidth
*/
/** @typedef {BlitsyGlyph[]} BlitsyPage */
/** @param {HTMLScriptElement} script */
async function loadBasicFont(script) {
const atlasdata = script.innerHTML;
const charWidth = parseInt(script.getAttribute("data-char-width"), 10);
const charHeight = parseInt(script.getAttribute("data-char-height"), 10);
const indexes = parseRuns(script.getAttribute("data-runs"));
const atlas = await loadImage(atlasdata);
const cols = atlas.naturalWidth / charWidth;
const font = {
name: "font",
lineHeight: charHeight,
characters: new Map(),
};
indexes.forEach((codepoint, i) => {
const col = i % cols;
const row = Math.floor(i / cols);
const rect = {
x: col * charWidth,
y: row * charHeight,
width: charWidth,
height: charHeight,
};
const image = copyImageRect(atlas, rect).canvas;
font.characters.set(codepoint, { codepoint, image, spacing: charWidth });
});
return font;
}
/** @param {string} data */
function parseRuns(data) {
const runs = data.split(",").map((run) => {
const [start, end] = run.split("-").map((index) => parseInt(index, 10));
return [ start, end ?? start ];
});
const indexes = [];
runs.forEach(([min, max]) => indexes.push(...range(min, max)));
return indexes;
}
/**
* @param {CanvasImageSource} source
* @param {Rect} rect
*/
function copyImageRect(source, rect) {
const rendering = createRendering2D(rect.width, rect.height);
rendering.drawImage(source, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height);
return rendering;
}
/**
* @param {BlitsyFont} font
* @param {string} char
*/
function getFontChar(font, char) {
const codepoint = char.codePointAt(0);
return font.characters.get(codepoint);
}
/**
* @param {BlitsyPage} page
* @param {number} width
* @param {number} height
* @param {number} ox
* @param {number} oy
*/
function renderPage(page, width, height, ox = 0, oy = 0)
{
const result = createRendering2D(width, height);
const buffer = createRendering2D(width, height);
for (const glyph of page)
{
if (glyph.hidden) continue;
// padding + position + offset
const x = ox + glyph.position.x + glyph.offset.x;
const y = oy + glyph.position.y + glyph.offset.y;
// draw tint layer
result.fillStyle = glyph.fillStyle;
result.fillRect(x, y, glyph.image.width, glyph.image.height);
// draw text layer
buffer.drawImage(glyph.image, x, y);
}
// draw text layer in tint color
result.globalCompositeOperation = 'destination-in';
result.drawImage(buffer.canvas, 0, 0);
return result;
}
const defaultStyleHandler = (styles, style) => {
if (style.substr(0, 1) === "+") {
styles.set(style.substring(1), true);
} else if (style.substr(0, 1) === "-") {
styles.delete(style.substring(1));
} else if (style.includes("=")) {
const [key, val] = style.split(/\s*=\s*/);
styles.set(key, val);
}
}
/**
* @param {string} script
* @param {BlitsyTextRenderOptions} options
* @param {*} styleHandler
* @returns {BlitsyPage[]}
*/
function scriptToPages(script, options, styleHandler = defaultStyleHandler) {
const tokens = tokeniseScript(script);
const commands = tokensToCommands(tokens);
return commandsToPages(commands, options, styleHandler);
}
function tokeniseScript(script) {
const tokens = [];
let buffer = "";
let braceDepth = 0;
function openBrace() {
if (braceDepth === 0) flushBuffer();
braceDepth += 1;
}
function closeBrace() {
if (braceDepth === 1) flushBuffer();
braceDepth -= 1;
}
function newLine() {
flushBuffer();
tokens.push(["markup", "br"]);
}
function flushBuffer() {
if (buffer.length === 0) return;
const type = braceDepth > 0 ? "markup" : "text";
tokens.push([type, buffer]);
buffer = "";
}
const actions = {
"{": openBrace,
"}": closeBrace,
"\n": newLine,
}
for (const char of script) {
if (char in actions)
actions[char]();
else
buffer += char;
}
flushBuffer();
return tokens;
}
function textBufferToCommands(buffer) {
const chars = Array.from(buffer);
return chars.map((char) => ({ type: "glyph", char, breakable: char === " " }));
}
function markupBufferToCommands(buffer) {
if (buffer === "pg") return [{ type: "break", target: "page" }];
if (buffer === "br") return [{ type: "break", target: "line" }];
else return [{ type: "style", style: buffer }];
}
/** @param {any[]} tokens */
function tokensToCommands(tokens) {
const handlers = {
"text": textBufferToCommands,
"markup": markupBufferToCommands,
};
const tokenToCommands = ([type, buffer]) => handlers[type](buffer);
return tokens.flatMap(tokenToCommands);
}
/**
* @param {*} commands
* @param {BlitsyTextRenderOptions} options
* @param {*} styleHandler
*/
function commandsToPages(commands, options, styleHandler) {
commandsBreakLongSpans(commands, options);
const styles = new Map();
const pages = [];
let page = [];
let currLine = 0;
function newPage() {
pages.push(page);
page = [];
currLine = 0;
}
function endPage() {
do { endLine(); } while (currLine % options.lineCount !== 0)
}
function endLine() {
currLine += 1;
if (currLine === options.lineCount) newPage();
}
function doBreak(target) {
if (target === "line") endLine();
else if (target === "page") endPage();
}
function findNextBreakIndex() {
let width = 0;
for (let i = 0; i < commands.length; ++i) {
const command = commands[i];
if (command.type === "break") return i;
if (command.type === "style") continue;
width += computeLineWidth(options.font, command.char);
// if we overshot, look backward for last possible breakable glyph
if (width > options.lineWidth) {
const result = find(commands, i, -1, command => command.type === "glyph" && command.breakable);
if (result) return result[1];
}
};
}
function addGlyph(command, offset) {
const char = getFontChar(options.font, command.char) ?? getFontChar(options.font, "?");
const position = { x: offset, y: currLine * (options.font.lineHeight + 4) };
const glyph = {
char: command.char,
image: char.image,
position,
offset: { x: 0, y: 0 },
hidden: true,
fillStyle: "white",
styles: new Map(styles.entries()),
};
page.push(glyph);
return char.spacing;
}
function generateGlyphLine(commands) {
let offset = 0;
for (const command of commands) {
if (command.type === "glyph") {
offset += addGlyph(command, offset);
} else if (command.type === "style") {
styleHandler(styles, command.style);
}
}
}
let index;
while ((index = findNextBreakIndex()) !== undefined) {
generateGlyphLine(commands.slice(0, index));
commands = commands.slice(index);
const command = commands[0];
if (command.type === "break") {
doBreak(command.target);
commands.shift();
} else {
if (command.type === "glyph" && command.char === " ") {
commands.shift();
}
endLine();
}
}
generateGlyphLine(commands);
endPage();
return pages;
}
/**
* Find spans of unbreakable commands that are too long to fit within a page
* width and amend those spans so that breaking permitted in all positions.
* @param {*} commands
* @param {BlitsyTextRenderOptions} options
*/
function commandsBreakLongSpans(commands, options) {
const canBreak = (command) => command.type === "break"
|| (command.type === "glyph" && command.breakable);
const spans = filterToSpans(commands, canBreak);
for (const span of spans) {
const glyphs = span.filter(command => command.type === "glyph");
const charWidths = glyphs.map(command => computeLineWidth(options.font, command.char));
const spanWidth = charWidths.reduce((x, y) => x + y, 0);
if (spanWidth > options.lineWidth) {
for (const command of glyphs) command.breakable = true;
}
}
}
/**
* @param {BlitsyFont} font
* @param {string} line
*/
function computeLineWidth(font, line) {
const chars = Array.from(line).map((char) => getFontChar(font, char));
const widths = chars.map((char) => char ? char.spacing : 0);
return widths.reduce((a, b) => a + b);
}
/**
* Segment the given array into contiguous runs of elements that are not
* considered breakable.
*/
function filterToSpans(array, breakable) {
const spans = [];
let buffer = [];
array.forEach((element, index) => {
if (!breakable(element, index)) {
buffer.push(element);
} else if (buffer.length > 0) {
spans.push(buffer);
buffer = [];
}
});
if (buffer.length > 0) {
spans.push(buffer);
}
return spans;
}
function find(array, start, step, predicate) {
for (let i = start; 0 <= i && i < array.length; i += step) {
if (predicate(array[i], i)) return [array[i], i];
}
}
</script>
<script>/**
* @typedef {Object} DialoguePage
* @property {BlitsyPage} glyphs
* @property {Partial<DialogueOptions>} options
*/
/**
* @typedef {Object} DialogueOptions
* @property {*} font
* @property {number} anchorX
* @property {number} anchorY
* @property {number} lines
* @property {number} lineGap
* @property {number} lineWidth
* @property {number} padding
* @property {number} glyphRevealDelay
* @property {string} backgroundColor
* @property {string} panelColor
* @property {string} textColor
*/
const DIALOGUE_DEFAULTS = {
anchorX: 0.5,
anchorY: 0.5,
lines: 2,
lineGap: 4,
padding: 8,
glyphRevealDelay: .05,
backgroundColor: undefined,
panelColor: "#000000",
textColor: "#FFFFFF",
};
const CONT_ICON_DATA = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAAAXNSR0IArs4c6QAAADNJREFUCJmNzrENACAMA0E/++/8NAhRBEg6yyc5SePUoNqwDICnWP04ww1tWOHfUqqf1UwGcw4T9WFhtgAAAABJRU5ErkJggg==";
const STOP_ICON_DATA = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAGCAYAAAD68A/GAAAAAXNSR0IArs4c6QAAACJJREFUCJljZICC/////2fAAhgZGRn////PwIRNEhsYCgoBIkQHCf7H+yAAAAAASUVORK5CYII="
class DialoguePlayback extends EventTarget {
constructor(width, height) {
super();
this.dialogueRendering = createRendering2D(width, height);
/** @type {DialoguePage[]} */
this.queuedPages = [];
this.pagesSeen = 0;
this.options = {};
// an awaitable that generates a new promise that resolves once no dialogue is active
/** @type {PromiseLike<void>} */
this.waiter = {
then: (resolve, reject) => {
if (this.empty) {
resolve();
} else {
return wait(this, "empty").then(resolve, reject);
}
},
}
this.clear();
}
get empty() {
return this.currentPage === undefined;
}
async load() {
this.contIcon = imageToRendering2D(await loadImage(CONT_ICON_DATA));
this.stopIcon = imageToRendering2D(await loadImage(STOP_ICON_DATA));
}
clear() {
this.queuedPages = [];
this.pagesSeen = 0;
this.setPage(undefined);
}
/** @param {DialoguePage} page */
setPage(page) {
const prev = this.currentPage;
this.currentPage = page;
this.pageTime = 0;
this.showGlyphCount = 0;
this.showGlyphElapsed = 0;
this.pageGlyphCount = page ? page.glyphs.length : 0;
this.dispatchEvent(new CustomEvent("next-page", { detail: { prev, next: page } }));
if (page === undefined) {
this.dispatchEvent(new CustomEvent("empty"));
}
}
/**
* @param {string} script
* @param {Partial<DialogueOptions>} options
* @returns {Promise}
*/
async queue(script, options={}) {
const { font, lines } = this.getOptions(options);
const lineWidth = options.lineWidth ||192;
script = parseFakedown(script);
const glyphPages = scriptToPages(script, { font, lineWidth, lineCount: lines });
const pages = glyphPages.map((glyphs) => ({ glyphs, options }));
this.queuedPages.push(...pages);
if (this.empty) this.moveToNextPage();
const last = pages[pages.length - 1];
return new Promise((resolve) => {
const onNextPage = (event) => {
const { prev, next } = event.detail;
if (prev === last) {
this.removeEventListener("next-page", onNextPage);
resolve();
}
};
this.addEventListener("next-page", onNextPage);
});
}
/** @param {number} dt */
update(dt) {
if (this.empty) return;
this.pageTime += dt;
this.showGlyphElapsed += dt;
this.applyStyle();
const options = this.getOptions(this.currentPage.options);
while (this.showGlyphElapsed > options.glyphRevealDelay && this.showGlyphCount < this.pageGlyphCount) {
this.showGlyphElapsed -= options.glyphRevealDelay;
this.revealNextChar();
this.applyStyle();
}
}
render() {
const options = this.getOptions(this.currentPage.options);
const height = options.padding * 2
+ (options.font.lineHeight + options.lineGap) * options.lines;
const width = (options.lineWidth || 192) + 16;
fillRendering2D(this.dialogueRendering, options.backgroundColor);
const { width: displayWidth, height: displayHeight } = this.dialogueRendering.canvas;
const spaceX = displayWidth - width;
const spaceY = displayHeight - height;
const margin = options.noMargin ? 0 : Math.ceil(Math.min(spaceX, spaceY) / 2);
const minX = margin;
const maxX = displayWidth - margin;
const minY = margin;
const maxY = displayHeight - margin;
const x = Math.floor(minX + (maxX - minX - width ) * options.anchorX);
const y = Math.floor(minY + (maxY - minY - height) * options.anchorY);
this.dialogueRendering.fillStyle = options.panelColor;
this.dialogueRendering.fillRect(x, y, width, height);
this.applyStyle();
const render = renderPage(
this.currentPage.glyphs,
width, height,
options.padding, options.padding,
);
this.dialogueRendering.drawImage(render.canvas, x, y);
if (this.showGlyphCount === this.pageGlyphCount) {
const prompt = this.queuedPages.length > 0
? this.contIcon
: this.stopIcon;
this.dialogueRendering.drawImage(
recolorMask(prompt, options.textColor).canvas,
x+width-options.padding-prompt.canvas.width,
y+height-options.lineGap-prompt.canvas.height,
);
}
}
getOptions(options) {
return Object.assign({}, DIALOGUE_DEFAULTS, this.options, options);
}
revealNextChar() {
if (this.empty) return;
this.showGlyphCount = Math.min(this.showGlyphCount + 1, this.pageGlyphCount);
this.currentPage.glyphs.forEach((glyph, i) => {
if (i < this.showGlyphCount) glyph.hidden = false;
});
}
revealAll() {
if (this.empty) return;
this.showGlyphCount = this.currentPage.glyphs.length;
this.revealNextChar();
}
cancel() {
this.queuedPages.length = 0;
this.currentPage = undefined;
}
skip() {
if (this.empty) return;
if (this.showGlyphCount === this.pageGlyphCount) {
this.moveToNextPage();
} else {
this.showGlyphCount = this.pageGlyphCount;
this.currentPage.glyphs.forEach((glyph) => glyph.hidden = false);
}
}
completed() {
return this.showGlyphCount === this.pageGlyphCount;
}
moveToNextPage() {
const nextPage = this.queuedPages.shift();
this.pagesSeen += 1;
this.setPage(nextPage);
}
applyStyle() {
if (this.empty) return;
const currentGlyph = this.currentPage.glyphs[this.showGlyphCount];
const options = this.getOptions(this.currentPage.options);
if (currentGlyph) {
if (currentGlyph.styles.has("delay")) {
this.showCharTime = parseFloat(currentGlyph.styles.get("delay"));
} else {
this.showCharTime = this.currentPage.options.glyphRevealDelay;
}
}
this.currentPage.glyphs.forEach((glyph, i) => {
glyph.fillStyle = glyph.styles.get("clr") ?? options.textColor;
if (glyph.styles.has("r"))
glyph.hidden = false;
if (glyph.styles.has("shk"))
glyph.offset = { x: getRandomInt(-1, 2), y: getRandomInt(-1, 2) };
if (glyph.styles.has("wvy"))
glyph.offset.y = (Math.sin(i + this.pageTime * 5) * 3) | 0;
if (glyph.styles.has("rbw")) {
const h = Math.abs(Math.sin(performance.now() / 600 - i / 8));
glyph.fillStyle = rgbToHex(HSVToRGB({ h, s: 1, v: 1 }));
}
});
}
}
/**
* @param {EventTarget} target
* @param {string} event
* @returns
*/
async function wait(target, event) {
return new Promise((resolve) => {
target.addEventListener(event, resolve, { once: true });
});
}
/**
* Return a random integer at least min and below max. Why is that the normal
* way to do random ints? I have no idea.
* @param {number} min
* @param {number} max
* @returns {number}
*/
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
function getRandomFloat(min, max) {
return Math.random() * (max - min) + min;
}
</script>
<script>const URL_PARAMS = new URLSearchParams(window.location.search);
const BIPSI_HD = URL_PARAMS.get("hd") === "true" || document.documentElement.dataset.hd;
const SAVE_SLOT = URL_PARAMS.get("save") ?? "slot0";
// browser saves will be stored under the id "bipsi"
const storage = new maker.ProjectStorage(BIPSI_HD ? "bipsi-hd" : "bipsi");
// type definitions for the structure of bipsi project data. useful for the
// code editor, ignored by the browser
/**
* @typedef {Object} BipsiDataSettings
* @property {string} title
*/
/**
* @typedef {Object} BipsiDataEventField
* @property {string} key
* @property {string} type
* @property {any} data
*/
/**
* @typedef {Object} BipsiDataEvent
* @property {number} id
* @property {number[]} position
* @property {BipsiDataEventField[]} fields
*/
/**
* @typedef {Object} BipsiDataRoom
* @property {number} id
* @property {number} palette
* @property {number[][]} tilemap
* @property {number[][]} backmap
* @property {number[][]} foremap
* @property {number[][]} wallmap
* @property {BipsiDataEvent[]} events
*/
/**
* @typedef {Object} BipsiDataTile
* @property {number} id
* @property {number[]} frames
*/
/**
* @typedef {Object} BipsiDataPalette
* @property {number} id
* @property {string[]} colors
*/
/**
* @typedef {Object} BipsiDataProject
* @property {BipsiDataRoom[]} rooms
* @property {BipsiDataPalette[]} palettes
* @property {string} tileset
* @property {BipsiDataTile[]} tiles
*/
/**
* @typedef {Object} BipsiDataLocation
* @property {number} room
* @property {number[]} position
*/
/**
* Return a list of resource ids that a particular bipsi project depends on.
* @param {BipsiDataProject} data
* @returns {string[]}
*/
function getManifest(data) {
// all embedded files
const files = allEvents(data)
.flatMap((event) => event.fields)
.filter((field) => field.type === "file")
.map((field) => field.data);
// + tileset
return [data.tileset, ...files];
}
const TILE_PX = BIPSI_HD ? 16 : 8;
const ROOM_SIZE = 16;
const SCREEN_ZOOM = 2;
const ROOM_PX = TILE_PX * ROOM_SIZE;
const SCREEN_PX = ROOM_PX * SCREEN_ZOOM;
const constants = {
frameInterval: 400,
tileset: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAjUlEQVR42u3XMQ4AEBAEwPv/p2kUIo5ScmYqQWU3QsSkDbu5TFBHVoDTfqemAFQKfy3BOs7WKBT+HLQCfBB+dgPcHnoKULAIp7ECfFoA30AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOCFDjCu5xlD93/uAAAAAElFTkSuQmCC",
wallTile: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAAXNSR0IArs4c6QAAAAlQTFRFAAAA////AAAAc8aDcQAAAAN0Uk5TAP//RFDWIQAAADlJREFUGJVlj0EOACAIw2D/f7QmLAa7XeyaKFgVkfSjum1M9xhDeN24+pjdbVYPwSt8lGMDcnV+DjlaUACpjVBfxAAAAABJRU5ErkJggg==",
eventTile: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAAXNSR0IArs4c6QAAAAlQTFRFAAAA////AAAAc8aDcQAAAAN0Uk5TAP//RFDWIQAAACVJREFUGJVjYMAATCgAJMCIBCACCHmYAFz3AAugOwzd6eieQwMAdfAA3XvBXggAAAAASUVORK5CYII=",
startTile: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAAXNSR0IArs4c6QAAAAZQTFRFAAAA////pdmf3QAAAAJ0Uk5TAP9bkSK1AAAAJUlEQVQYlWNgwACMKAC7ALJqnALIqkEETD8lAhiGEnIHIb+gAQBFEACBGFbz9wAAAABJRU5ErkJggg==",
pluginTile: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAAAXNSR0IArs4c6QAAAFJJREFUKJGVkVEOwCAIQ4vp/a/MPkwUisOtXxBfaQTgIgPg3TvREAaAu1RNG3Ob3QmIUyI8dKxLoABVzK2VCAHqh/9EnNe1gNOqAvB+DnbuT3oAhXsLLn/W2IoAAAAASUVORK5CYII=",
colorwheelMargin: 12,
}
const TEMP_ROOM = createRendering2D(ROOM_PX, ROOM_PX);
const TEMP_SCREEN = createRendering2D(SCREEN_PX, SCREEN_PX);
/**
* @param {HTMLCanvasElement} tileset
* @param {number} index
*/
function getTileCoords(tileset, index) {
const cols = tileset.width / TILE_PX;
return {
x: TILE_PX * (index % cols),
y: TILE_PX * Math.floor(index / cols),
size: TILE_PX,
}
}
/**
* @param {CanvasRenderingContext2D} tileset
* @param {number} tileIndex
* @param {CanvasRenderingContext2D} destination
* @returns {CanvasRenderingContext2D}
*/
function copyTile(tileset, tileIndex, destination = undefined) {
const { x, y, size } = getTileCoords(tileset.canvas, tileIndex);
const tile = copyRendering2D(tileset, destination, { x, y, w: size, h: size });
return tile;
}
/**
* @param {CanvasRenderingContext2D} tileset
* @param {number} tileIndex
* @param {CanvasRenderingContext2D} tile
*/
function drawTile(tileset, tileIndex, tile) {
const { x, y, size } = getTileCoords(tileset.canvas, tileIndex);
tileset.clearRect(x, y, size, size);
tileset.drawImage(tile.canvas, x, y);
}
/**
* @param {BipsiDataTile[]} tiles
* @param {number} frame
* @returns {Map<number, number>}
*/
function makeTileToFrameMap(tiles, frame) {
/** @type {[number, number][]} */
return new Map(tiles.map((tile) => [
tile.id,
tile.frames[frame % tile.frames.length],
]));
}
/**
* @param {CanvasRenderingContext2D} destination
* @param {CanvasRenderingContext2D} tileset
* @param {Map<number, number>} tileToFrame
* @param {BipsiDataPalette} palette
* @param {{ tilemap: number[][], backmap: number[][], foremap: number[][] }} layer
*/
function drawTilemapLayer(destination, tileset, tileToFrame, palette, { tilemap, backmap, foremap }) {
drawRecolorLayer(destination, (backg, color, tiles) => {
for (let ty = 0; ty < ROOM_SIZE; ++ty) {
for (let tx = 0; tx < ROOM_SIZE; ++tx) {
let back = backmap[ty][tx];
let fore = foremap[ty][tx];
let tileIndex = tilemap[ty][tx];
if (tileIndex === 0) {
fore = back;
tileIndex = 1;
}
const frameIndex = tileToFrame.get(tileIndex);
const { x, y, size } = getTileCoords(tileset.canvas, frameIndex);
if (back > 0) {
backg.fillStyle = palette.colors[back];
backg.fillRect(tx * size, ty * size, size, size);
}
if (fore > 0) {
color.fillStyle = palette.colors[fore];
color.fillRect(tx * size, ty * size, size, size);
}
tiles.drawImage(
tileset.canvas,
x, y, size, size,
tx * size, ty * size, size, size,
);
}
}
});
}
/**
* @param {CanvasRenderingContext2D} destination
* @param {CanvasRenderingContext2D} tileset
* @param {Map<number, number>} tileToFrame
* @param {BipsiDataPalette} palette
* @param {BipsiDataEvent[]} events
*/
function drawEventLayer(destination, tileset, tileToFrame, palette, events) {
drawRecolorLayer(destination, (backg, color, tiles) => {
events.forEach((event) => {
const [tx, ty] = event.position;
const graphicField = oneField(event, "graphic", "tile");
if (graphicField) {
let { fg, bg } = FIELD(event, "colors", "colors") ?? { bg: 1, fg: 3 };
const frameIndex = tileToFrame.get(graphicField.data) ?? 0;
const { x, y, size } = getTileCoords(tileset.canvas, frameIndex);
if (eventIsTagged(event, "transparent")) {
bg = 0;
}
if (bg > 0) {
backg.fillStyle = palette.colors[bg];
backg.fillRect(tx * size, ty * size, size, size);
}
if (fg > 0) {
color.fillStyle = palette.colors[fg];
color.fillRect(tx * size, ty * size, size, size);
}
tiles.drawImage(
tileset.canvas,
x, y, size, size,
tx * size, ty * size, size, size,
);
}
});
});
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {BipsiDataPalette} palette
* @param {BipsiDataRoom} room
*/
function drawRoomThumbnail(rendering, palette, room) {
rendering.canvas.width = ROOM_SIZE;
rendering.canvas.height = ROOM_SIZE;
const [, background, foreground, highlight] = palette.colors;
for (let y = 0; y < ROOM_SIZE; ++y) {
for (let x = 0; x < ROOM_SIZE; ++x) {
const foreground = palette.colors[room.foremap[y][x]];
const background = palette.colors[room.backmap[y][x]];
const color = room.wallmap[y][x] === 1 ? foreground : background;
rendering.fillStyle = color;
rendering.fillRect(x, y, 1, 1);
}
}
rendering.fillStyle = highlight;
room.events.forEach((event) => {
const [x, y] = event.position;
rendering.fillRect(x, y, 1, 1);
});
}
/**
* @param {CanvasRenderingContext2D} rendering
* @param {BipsiDataPalette} palette
*/
function drawPaletteThumbnail(rendering, palette) {
for (let y = 0; y < 2; ++y) {
for (let x = 0; x < 4; ++x) {
rendering.fillStyle = palette.colors[y * 4 + x];
rendering.fillRect(x, y, 1, 1);
}
}
rendering.clearRect(0, 0, 1, 1);
}
/**
* @param {any[][]} map
* @param {number} dx
* @param {number} dy
*/
function cycleMap(map, dx, dy) {
const x = dx > 0 ? dx : ROOM_SIZE + dx;
const y = dy > 0 ? dy : ROOM_SIZE + dy;
map.push(...map.splice(0, y));
map.forEach((row) => {
row.push(...row.splice(0, x));
});
}
/**
* @param {BipsiDataEvent[]} events
* @param {number} dx
* @param {number} dy
*/
function cycleEvents(events, dx, dy) {
events.forEach((event) => {
event.position[0] = (event.position[0] + ROOM_SIZE + dx) % ROOM_SIZE;
event.position[1] = (event.position[1] + ROOM_SIZE + dy) % ROOM_SIZE;
});
}
/**
* @param {BipsiDataEvent[]} events
* @param {number} x
* @param {number} y
*/
function getEventsAt(events, x, y, ignore=undefined) {
return events.filter((event) => event.position[0] === x
&& event.position[1] === y
&& event !== ignore);
}
/**
* @template {{id: number}} T
* @param {T[]} items
* @param {number} id
* @returns {T}
*/
function getById(items, id) {
return items.find((item) => item.id === id);
}
/**
* @param {BipsiDataProject} data
* @param {number} id
* @returns {BipsiDataRoom}
*/
function getRoomById(data, id) {
return getById(data.rooms, id);
}
/**
* @param {BipsiDataProject} data
* @param {number} id
* @returns {BipsiDataPalette}
*/
function getPaletteById(data, id) {
return getById(data.palettes, id);
}
/**
* @param {BipsiDataProject} data
* @param {number} id
* @returns {BipsiDataEvent}
*/
function getEventById(data, id) {
return getById(allEvents(data), id);
}
/**
* @param {BipsiDataProject} data
* @param {number} id
* @returns {BipsiDataTile}
*/
function getTileById(data, id) {
return getById(data.tiles, id);
}
/**
* @param {BipsiDataTile[]} tiles
*/
function findFreeFrame(tiles) {
const frames = new Set(tiles.flatMap((tile) => tile.frames));
const max = Math.max(...frames);
for (let i = 0; i < max; ++i) {
if (!frames.has(i)) return i;
}
return max + 1;
}
/**
* @param {{id: number}[]} items
* @returns {number}
*/
function nextId(items) {
const max = Math.max(0, ...items.map((item) => item.id ?? 0));
return max + 1;
}
/** @param {BipsiDataProject} data */
const nextRoomId = (data) => nextId(data.rooms);
/** @param {BipsiDataProject} data */
const nextTileId = (data) => nextId(data.tiles);
/** @param {BipsiDataProject} data */
const nextEventId = (data) => nextId(data.rooms.flatMap((room) => room.events));
/** @param {BipsiDataProject} data */
const nextPaletteId = (data) => nextId(data.palettes);
/**
* @param {CanvasRenderingContext2D} tileset
* @param {BipsiDataTile[]} tiles
*/
function resizeTileset(tileset, tiles) {
const maxFrame = Math.max(...tiles.flatMap((tile) => tile.frames));
const cols = 16;
const rows = Math.ceil((maxFrame + 1) / cols);
resizeRendering2D(tileset, cols * TILE_PX, rows * TILE_PX);
}
</script>
<script>/**
* Use inline style to resize canvas to fit its parent, preserving the aspect
* ratio of its internal dimensions.
* @param {HTMLCanvasElement} canvas
*/
function fitCanvasToParent(canvas) {
const [tw, th] = [canvas.parentElement.clientWidth, canvas.parentElement.clientHeight];
const [sw, sh] = [tw / canvas.width, th / canvas.height];
let scale = Math.min(sw, sh);
if (canvas.width * scale > 512) scale = Math.floor(scale);
canvas.style.setProperty("width", `${canvas.width * scale}px`);
canvas.style.setProperty("height", `${canvas.height * scale}px`);
}
/**
* @param {HTMLElement} element
*/
function scaleElementToParent(element, margin=0) {
const parent = element.parentElement;
const [tw, th] = [parent.clientWidth-margin*2, parent.clientHeight-margin*2];
const [sw, sh] = [tw / element.clientWidth, th / element.clientHeight];
let scale = Math.min(sw, sh);
if (scale > 1) scale = Math.floor(scale);
element.style.setProperty("transform", `translate(-50%, -50%) scale(${scale})`);
return scale;
}
// async equivalent of Function constructor
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor
/**
* @param {any} message
* @param {string} origin
*/
function postMessageParent(message, origin) {
const target = window.parent ?? window.opener;
target?.postMessage(message, origin);
}
/**
* @param {BipsiDataEvent} event
* @param {string} key
*/
function eventIsTagged(event, key) {
return oneField(event, key, "tag") !== undefined;
}
/**
* @param {BipsiDataRoom} room
* @param {number} x
* @param {number} y
*/
function cellIsSolid(room, x, y) {
const wall = room.wallmap[y][x] > 0;
const solid = getEventsAt(room.events, x, y).some((event) => eventIsTagged(event, "solid"));
return solid || wall;
}
/**
*
* @param {BipsiDataEvent} event
* @param {string} name
* @param {string} type
*/
function allFields(event, name, type=undefined) {
return event.fields.filter((field) => field.key === name && field.type === (type ?? field.type));
}
/**
*
* @param {BipsiDataEvent} event
*/
function allTags(event) {
return event.fields.filter((field) => field.type === "tag").map((field) => field.key);
}
/**
*
* @param {BipsiDataEvent} event
* @param {string} name
* @param {string} type
*/
function oneField(event, name, type=undefined) {
return event.fields.find((field) => field.key === name && field.type === (type ?? field.type));
}
/**
* @param {BipsiDataProject} data
*/
function allEvents(data) {
return data.rooms.flatMap((room) => room.events);
}
/**
* @param {BipsiDataProject} data
* @param {BipsiDataEvent} event
*/
function roomFromEvent(data, event) {
return data.rooms.find((room) => room.events.includes(event));
}
/**
* @param {BipsiDataProject} data
* @param {BipsiDataLocation} location
* @returns {BipsiDataEvent?}
*/
function getEventAtLocation(data, location) {
const room = data.rooms.find((room) => room.id === location.room);
const [x, y] = location.position;
const [event] = getEventsAt(room.events, x, y);
return event;
}
/**
* @param {BipsiDataProject} data
* @param {BipsiDataEvent} event
* @returns {BipsiDataLocation}
*/
function getLocationOfEvent(data, event) {
const room = roomFromEvent(data, event);
return { room: room.id, position: [...event.position] };
}
/**
* @param {BipsiDataProject} data
* @param {BipsiDataEvent} event
* @param {BipsiDataLocation} location
*/
function moveEvent(data, event, location) {
const room = data.rooms.find((room) => room.id === location.room);
if (!room) throw Error("NO ROOM WITH ID " + location.room);
removeEvent(data, event);
room.events.push(event);
event.position = [...location.position];
}
/**
* @param {BipsiDataProject} data
* @param {number} eventId
* @param {BipsiDataLocation} location
*/
function moveEventById(data, eventId, location) {
const event = findEventById(data, eventId);
moveEvent(data, event, location);
}
/**
* @param {BipsiDataProject} data
* @param {BipsiDataEvent} event
*/
function removeEvent(data, event) {
const prevRoom = roomFromEvent(data, event);
arrayDiscard(prevRoom.events, event);
}
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
/**
* @param {BipsiDataProject} data
* @param {number} eventId
*/
function findEventById(data, eventId) {
return allEvents(data).filter((event) => event.id === eventId)[0];
}
function findEventsByTag(data, tag) {
return allEvents(data).filter((event) => eventIsTagged(event, tag));
}
function findEventByTag(data, tag) {
return allEvents(data).filter((event) => eventIsTagged(event, tag))[0];
}
/**
* @param {BipsiDataEvent} event
*/
function allEventTags(event) {
return event.fields.filter((field) => field.type === "tag").map((field) => field.key);
}
const ERROR_STYLE = {
glyphRevealDelay: 0,
lines: 8,
panelColor: "#FF0000",
textColor: "#FFFFFF",
anchorX: .5, anchorY: .5,
}
const BEHAVIOUR_BEFORE = `
let script = $FIELD("before", "javascript");
if (script) {
await RUN_JS(script);
}
`;
const BEHAVIOUR_AFTER = `
let script = $FIELD("after", "javascript");
if (script) {
await RUN_JS(script);
}
`;
const BEHAVIOUR_PAGE_COLOR = `
let color = FIELD(EVENT, "page-color", "text");
if (color) {
SET_CSS("--page-color", color);
}
`;
const BEHAVIOUR_IMAGES = `
let backgrounds = FIELDS_OR_LIBRARY("background");
if (backgrounds.length > 0) {
SHOW_IMAGE("BACKGROUND", backgrounds, 1, 0, 0);
} else if (IS_TAGGED(EVENT, "clear-background")) {
HIDE_IMAGE("BACKGROUND");
}
let foregrounds = FIELDS_OR_LIBRARY("foreground");
if (foregrounds.length > 0) {
SHOW_IMAGE("FOREGROUND", foregrounds, 2, 0, 0);
} else if (IS_TAGGED(EVENT, "clear-foreground")) {
HIDE_IMAGE("FOREGROUND");
}
let overlays = FIELDS_OR_LIBRARY("overlay");
if (overlays.length > 0) {
SHOW_IMAGE("OVERLAY", overlays, 3, 0, 0);
} else if (IS_TAGGED(EVENT, "clear-overlay")) {
HIDE_IMAGE("OVERLAY");
}
`;
const BEHAVIOUR_MUSIC = `
let music = FIELD_OR_LIBRARY("music");
if (music) {
PLAY_MUSIC(music);
} else if (IS_TAGGED(EVENT, "stop-music")) {
STOP_MUSIC();
}
`;
const BEHAVIOUR_TITLE = `
let title = FIELD(EVENT, "title", "dialogue");
if (title) {
await TITLE(title, FIELD(EVENT, "say-style", "json"));
}
`;
const BEHAVIOUR_DIALOGUE = `
let id = FIELD(EVENT, "say-shared-id", "text") ?? "SAY-ITERATORS/" + EVENT_ID(EVENT);
let mode = FIELD(EVENT, "say-mode", "text") ?? "cycle";
let say = SAMPLE(id, mode, FIELDS(EVENT, "say", "dialogue"));
if (say) {
await SAY(say, FIELD(EVENT, "say-style", "json"));
} else if (say === undefined) {
let nosays = FIELD(EVENT, "no-says", "javascript");
if (nosays) {
await RUN_JS(nosays);
}
}
`;
const BEHAVIOUR_EXIT = `
let destination = FIELD(EVENT, "exit", "location");
if (destination) {
MOVE(AVATAR, destination);
}
`;
const BEHAVIOUR_REMOVE = `
if (IS_TAGGED(EVENT, "one-time")) {
REMOVE(EVENT);
}
`;
const BEHAVIOUR_ENDING = `
let ending = FIELD(EVENT, "ending", "dialogue");
if (ending !== undefined) {
if (ending.length > 0) {
await TITLE(ending, FIELD(EVENT, "say-style", "json"));
}
RESTART();
}
`;
const BEHAVIOUR_SET_AVATAR = `
let graphic = FIELD(EVENT, "set-avatar", "tile");
if (graphic) {
SET_GRAPHIC(AVATAR, graphic);
}
`;
const BEHAVIOUR_TOUCH_LOCATION = `
let location = FIELD(EVENT, "touch-location", "location");
let event = location ? EVENT_AT(location) : undefined;
if (event) {
await TOUCH(event);
}
`;
const BEHAVIOUR_ADD_BEHAVIOUR = `
ADD_BEHAVIOURS(...FIELDS(EVENT, "add-behaviour", "javascript"));
ADD_BEHAVIOURS(...FIELDS(EVENT, "add-behavior", "javascript"));
`;
const START_SCRIPTS = [
BEHAVIOUR_IMAGES,
BEHAVIOUR_MUSIC,
]
const STANDARD_SCRIPTS = [
BEHAVIOUR_PAGE_COLOR,
...START_SCRIPTS,
BEHAVIOUR_TITLE,
BEHAVIOUR_DIALOGUE,
BEHAVIOUR_EXIT,
BEHAVIOUR_REMOVE,
BEHAVIOUR_ENDING,
BEHAVIOUR_SET_AVATAR,
BEHAVIOUR_TOUCH_LOCATION,
BEHAVIOUR_ADD_BEHAVIOUR,
];
const BACKG_PAGE = createRendering2D(ROOM_PX, ROOM_PX);
const COLOR_PAGE = createRendering2D(ROOM_PX, ROOM_PX);
const TILES_PAGE = createRendering2D(ROOM_PX, ROOM_PX);
function drawRecolorLayer(destination, render) {
fillRendering2D(BACKG_PAGE);
fillRendering2D(COLOR_PAGE);
fillRendering2D(TILES_PAGE);
render(BACKG_PAGE, COLOR_PAGE, TILES_PAGE);
BACKG_PAGE.globalCompositeOperation = "destination-out";
BACKG_PAGE.drawImage(TILES_PAGE.canvas, 0, 0);
BACKG_PAGE.globalCompositeOperation = "source-over";
COLOR_PAGE.globalCompositeOperation = "destination-in";
COLOR_PAGE.drawImage(TILES_PAGE.canvas, 0, 0);
COLOR_PAGE.globalCompositeOperation = "source-over";
destination.drawImage(BACKG_PAGE.canvas, 0, 0);
destination.drawImage(COLOR_PAGE.canvas, 0, 0);
}
const BACKG_PAGE_D = createRendering2D(555, 555);
const COLOR_PAGE_D = createRendering2D(555, 555);
const TILES_PAGE_D = createRendering2D(555, 555);
function drawRecolorLayerDynamic(destination, render) {
const { width, height } = destination.canvas;
resizeRendering2D(BACKG_PAGE_D, width, height);
resizeRendering2D(COLOR_PAGE_D, width, height);
resizeRendering2D(TILES_PAGE_D, width, height);
fillRendering2D(BACKG_PAGE_D);
fillRendering2D(COLOR_PAGE_D);
fillRendering2D(TILES_PAGE_D);
render(BACKG_PAGE_D, COLOR_PAGE_D, TILES_PAGE_D);
BACKG_PAGE_D.globalCompositeOperation = "destination-out";
BACKG_PAGE_D.drawImage(TILES_PAGE_D.canvas, 0, 0);
BACKG_PAGE_D.globalCompositeOperation = "source-over";
COLOR_PAGE_D.globalCompositeOperation = "destination-in";
COLOR_PAGE_D.drawImage(TILES_PAGE_D.canvas, 0, 0);
COLOR_PAGE_D.globalCompositeOperation = "source-over";
destination.drawImage(BACKG_PAGE_D.canvas, 0, 0);
destination.drawImage(COLOR_PAGE_D.canvas, 0, 0);
}
class BipsiPlayback extends EventTarget {
constructor(font) {
super();
// home for data of the project we're playing
this.stateManager = new maker.StateManager(getManifest);
this.stateBackup = new maker.StateManager(getManifest);
// final composite of any graphics
this.rendering = createRendering2D(256, 256);
this.font = font;
this.dialoguePlayback = new DialoguePlayback(256, 256);
this.dialoguePlayback.options.font = font;
this.time = 0;
this.frameCount = 0;
this.ready = false;
this.busy = false;
this.error = false;
this.inputWait = undefined;
this.inputWaitResolve = undefined;
this.objectURLs = new Map();
this.imageElements = new Map();
this.music = document.createElement("audio");
this.music.loop = true;
this.autoplay = false;
this.variables = new Map();
this.images = new Map();
this.extra_behaviours = [];
this.choiceExpected = false;
this.story = undefined
}
async init() {
await this.dialoguePlayback.load();
}
async initWithStory(story){
await this.init()
this.story = story;
}
/** @type {BipsiDataProject} */
get data() {
return this.stateManager.present;
}
async backup() {
await this.stateBackup.copyFrom(this.stateManager);
}
/**
* @param {maker.StateManager<BipsiDataProject>} stateManager
*/
async copyFrom(stateManager) {
this.clear();
await this.stateManager.copyFrom(stateManager);
await this.backup();
}
/**
* @param {maker.ProjectBundle<BipsiDataProject>} bundle
*/
async loadBundle(bundle) {
this.clear();
await this.stateManager.loadBundle(bundle);
await this.backup();
}
clear() {
this.ready = false;
this.error = false;
this.ended = false;
this.dialoguePlayback.clear();
this.variables.clear();
this.inputWaitResolve?.apply();
this.inputWaitResolve = undefined;
this.inputWait = undefined;
this.music.removeAttribute("src");
this.music.pause();
this.images.clear();
this.extra_behaviours.length = 0;
this.imageElements.clear();
this.objectURLs.forEach((url) => URL.revokeObjectURL(url));
this.objectURLs.clear();
}
getFileObjectURL(id) {
const url = this.objectURLs.get(id)
?? URL.createObjectURL(this.stateManager.resources.get(id));
this.objectURLs.set(id, url);
return url;
}
getFileImageElement(id) {
const image = this.imageElements.get(id) ?? loadImageLazy(this.getFileObjectURL(id));
this.imageElements.set(id, image);
return image;
}
async restart() {
this.clear();
this.story.ResetState();
await this.stateManager.copyFrom(this.stateBackup);
this.start();
}
async start() {
// player avatar is event tagged "is-player" at the beginning of the game
const avatar = findEventByTag(this.data, "is-player");
if (avatar === undefined) {
this.showError("NO EVENT WITH is-player TAG FOUND");
return;
}
// move avatar to last event (render on top)
const room = roomFromEvent(this.data, avatar);
moveEvent(this.data, avatar, { room: room.id, position: [...avatar.position] });
this.avatarId = avatar.id;
this.libraryId = findEventByTag(this.data, "is-library")?.id;
this.ready = true;
const setup = findEventByTag(this.data, "is-setup");
if (setup) await this.touch(setup);
// game starts by running the touch behaviour of the player avatar
//await this.touch(avatar);
for (let script of START_SCRIPTS) {
await this.runJS(avatar, script);
}
await this.continueStory(avatar);
}
async spawnAt(target, event){
let targetEvent = findEventByTag(this.data, target);
if(targetEvent){
let targetLocation = getLocationOfEvent(this.data, targetEvent);
let spawnedEvent = findEventByTag(this.data, event);
if(targetLocation && spawnedEvent){
await moveEvent(this.data, spawnedEvent, targetLocation);
}
}
}
async sayWithPortrait(text, character, sentiment, options){
const characterEvent = findEventByTag(this.data, character);
let portraitShown = false;
if(characterEvent){
const sentimentImageId = oneField(characterEvent, sentiment, "file")?.data
|| oneField(characterEvent, "neutral", "file")?.data
if(sentimentImageId){
await this.showImage("portrait", sentimentImageId, 3, 104, 102);
portraitShown = true;
}
}
await this.say(text, options);
if(portraitShown){
await this.hideImage("portrait");
}
}
async continueStory(EVENT){
const story = this.story;
const AVATAR = findEventByTag(this.data, "is-player");
const sayStyle = oneField(EVENT, "say-style", "json")?.data
|| oneField(AVATAR, "say-style", "json")?.data
|| {};
while(story.canContinue) {
// Get ink to generate the next paragraph
var paragraphText = this.story.Continue().trim();
var tags = story.currentTags;
if(paragraphText.length > 0){
const matchSpawn = paragraphText.trim().match(/SPAWN_AT\(([^),\s]*)([\s]*,[\s]*([^)]*)*)*\)/)
const matchCutscene = paragraphText.trim().match(/CUTSCENE\(([^),\s]*)([\s]*,[\s]*([^)]*)*)*\)/)
if( matchSpawn ){
const target = matchSpawn[1];
const event = matchSpawn[3] || "is-player";
await this.spawnAt(target.trim(), event.trim());
}else if( matchCutscene ){
const target = matchCutscene[1];
const field = matchCutscene[3] || "touch";
let targetEvent = findEventByTag(this.data, target);
if(targetEvent){
const js_field = oneField(targetEvent, field, "javascript")?.data;
if (js_field !== undefined) {
await this.runJS(targetEvent, js_field);
}
}
}else if(tags.includes("TITLE")){
await this.title(paragraphText);
}else{
const portrait = tags.find(t => t.match(/[a-zA-Z0-9]*-[a-zA-Z0-9]*/))
if(portrait){
const matchPortrait = portrait.match(/([a-zA-Z0-9]*)-([a-zA-Z0-9]*)/);
const character = matchPortrait[1];
const sentiment = matchPortrait[2];
await this.sayWithPortrait(paragraphText, character, sentiment, sayStyle)
}else{
await this.say(paragraphText, sayStyle);
}
}
}
}
const choices = this.story.currentChoices;
const autoChoice = choices.find( (choice) => choice.text.startsWith("auto:"))
if(autoChoice !== undefined){
story.ChooseChoiceIndex(autoChoice.index)
return await this.continueStory(EVENT);
}
const dialogChoices = choices.filter( (choice) => {
if(choice.text.startsWith("auto:")) return false;
if(choice.text.startsWith("tag:")) return false;
return true;
})
const continueStory = this.continueStory.bind(this)
if(dialogChoices.length > 0){
const availableArrows = [
["ArrowUp", "↑"],
["ArrowDown", "↓"],
["ArrowLeft", "←"],
["ArrowRight", "→"]
];
this.choiceExpected = true;
const dialogChoicesTexts = [];
const playback = this;
const choiceEvents = new Map();
dialogChoices.forEach(function(choice) {
const [arrowEvent, glyph] = availableArrows.shift() || [];
if(arrowEvent){
dialogChoicesTexts.push(`${glyph} ${choice.text}`);
choiceEvents.set(arrowEvent, () => {
story.ChooseChoiceIndex(choice.index);
});
}
});
//always display choices at the bottom
this.say(dialogChoicesTexts.join("\n"), {
...sayStyle,
...{"noMargin": true,
"anchorX": 0, "anchorY": 1, lineWidth: 40*6,
"lines": dialogChoicesTexts.length,
}
})
const listenToChoice = (event) =>{
const choiceAction = choiceEvents.get(event.detail)
if(choiceAction){
choiceAction();
playback.proceed();
playback.removeEventListener('choice', listenToChoice);
playback.choiceExpected = false;
continueStory(EVENT);
}
}
this.addEventListener("choice", listenToChoice);
}else{
this.choiceExpected = false
}
}
update(dt) {
if (!this.ready) return;
// tile animation
this.time += dt;
while (this.time >= .400) {
this.frameCount += 1;
this.time -= .4;
}
// dialogue animation
this.dialoguePlayback.update(dt);
// rerender
this.render();
}
render(frame=undefined) {
// find avatar, current room, current palette
const avatar = getEventById(this.data, this.avatarId);
const room = roomFromEvent(this.data, avatar);
const palette = this.getActivePalette();
const tileset = this.stateManager.resources.get(this.data.tileset);
// find current animation frame for each tile
frame = frame ?? this.frameCount;
const tileToFrame = makeTileToFrameMap(this.data.tiles, frame);
// sort images
const images = Array.from(this.images.values());
images.sort((a, b) => a.layer - b.layer);
const images_below_all = images.filter((image) => image.layer < 1);
const images_below_events = images.filter((image) => image.layer >= 1 && image.layer < 2);
const images_above_events = images.filter((image) => image.layer >= 2 && image.layer < 3);
const images_above_all = images.filter((image) => image.layer >= 3);
fillRendering2D(this.rendering);
// fillRendering2D(TEMP_ROOM, background);
images_below_all.forEach(({ image, x, y }) => TEMP_ROOM.drawImage(image[frame % image.length], x, y));
drawTilemapLayer(TEMP_ROOM, tileset, tileToFrame, palette, room);
images_below_events.forEach(({ image, x, y }) => TEMP_ROOM.drawImage(image[frame % image.length], x, y));
drawEventLayer(TEMP_ROOM, tileset, tileToFrame, palette, room.events);
images_above_events.forEach(({ image, x, y }) => TEMP_ROOM.drawImage(image[frame % image.length], x, y));
// upscale tilemaps to display area
this.rendering.drawImage(TEMP_ROOM.canvas, 0, 0, 256, 256);
// render dialogue box if necessary
if (!this.dialoguePlayback.empty) {
// change default dialogue position based on avatar position
const top = avatar.position[1] >= 8;
this.dialoguePlayback.options.anchorY = top ? 0 : 1;
// redraw dialogue and copy to display area
this.dialoguePlayback.render();
this.rendering.drawImage(this.dialoguePlayback.dialogueRendering.canvas, 0, 0);
}
fillRendering2D(TEMP_ROOM);
images_above_all.forEach(({ image, x, y }) => TEMP_ROOM.drawImage(image[frame % image.length], x, y));
this.rendering.drawImage(TEMP_ROOM.canvas, 0, 0, 256, 256);
if (this.ended) {
fillRendering2D(this.rendering);
}
// signal, to anyone listening, that rendering happened
this.dispatchEvent(new CustomEvent("render"));
}
end() {
this.ended = true;
}
log(...data) {
this.dispatchEvent(new CustomEvent("log", { detail: data }));
window.parent.postMessage({ type: "log", data });
}
setVariable(key, value) {
this.variables.set(key, value);
this.sendVariables();
}
sendVariables() {
const variables = new Map();
this.variables.forEach((value, key) => {
try {
variables.set(key, JSON.parse(JSON.stringify(value)));
} catch (e) {
variables.set(key, "[COMPLEX VALUE]");
}
});
window.parent.postMessage({ type: "variables", data: variables });
}
get canMove() {
return this.ready
&& this.dialoguePlayback.empty
&& !this.busy
&& !this.ended
&& !this.inputWait;
}
async waitInput() {
this.inputWait = this.inputWait ?? new Promise((resolve) => {
this.inputWaitResolve = resolve;
});
return this.inputWait;
}
async proceed() {
if (!this.ready) return;
if (this.ended) {
this.restart();
}
this.inputWaitResolve?.apply();
this.inputWaitResolve = undefined;
this.inputWait = undefined;
this.dialoguePlayback.skip();
if (this.autoplay) {
this.music.play();
this.autoplay = false;
}
}
async title(script, options={}) {
const [, background] = this.getActivePalette().colors;
options = { anchorY: .5, backgroundColor: background, ...options };
return this.say(script, options);
}
async say(script, options={}) {
this.log(`> SAYING "${script}"`);
script = replaceVariables(script, this.variables);
await this.dialoguePlayback.queue(script, options);
}
async move(dx, dy) {
if (this.ended) this.proceed();
if (!this.canMove) return;
this.busy = true;
const avatar = getEventById(this.data, this.avatarId);
const room = roomFromEvent(this.data, avatar);
// determine move destination
const [px, py] = avatar.position;
const [tx, ty] = [px+dx, py+dy];
// is the movement stopped by the room edge or solid cells?
const bounded = tx < 0 || tx >= ROOM_SIZE || ty < 0 || ty >= ROOM_SIZE;
const blocked = bounded ? false : cellIsSolid(room, tx, ty);
// if not, then update avatar position
if (!blocked && !bounded) avatar.position = [tx, ty];
// find if there's an event that should be touched. prefer an event at
// the cell the avatar tried to move into but settle for the cell
// they're already standing on otherwise
const [fx, fy] = avatar.position;
const events_at_destination = getEventsAt(room.events, tx, ty, avatar);
const events_at_position = getEventsAt(room.events, fx, fy, avatar);
const events = events_at_destination.length > 0
? events_at_destination
: events_at_position
// if there are such events, touch them all
await events.forEach(async event => {
await this.touch(event);
});
this.busy = false;
}
eventDebugInfo(event) {
const tags = allEventTags(event).join(", ");
const info = tags.length > 0 ? `(tags: ${tags}) ` : "";
return `${info}@ ${event.position}`;
}
/**
* @param {BipsiDataEvent} event
*/
async touch(event) {
this.log(`> TOUCHING EVENT ${this.eventDebugInfo(event)}`);
const touch = oneField(event, "touch", "javascript")?.data;
const tags = allTags(event);
// do we have a choice that can be triggered by this event ?
const choices = this.story.currentChoices
const taggedChoice = choices.find(choice => {
if(choice.text.substr(0,4) == "tag:"){
const tagvalue = choice.text.substr(4).trim();
if(tags.includes(tagvalue)) return true
return false;
}
return false;
})
if (touch !== undefined) {
await this.runJS(event, touch);
}else if(taggedChoice !== undefined){
await this.runJS(event, BEHAVIOUR_BEFORE);
this.story.ChooseChoiceIndex(taggedChoice.index)
await this.continueStory(event);
await standardEventTouch(this, event);
await this.runJS(event, BEHAVIOUR_AFTER);
this.proceed();
} else {
await this.runJS(event, BEHAVIOUR_BEFORE);
await standardEventTouch(this, event);
await this.runJS(event, BEHAVIOUR_AFTER);
}
}
async runJS(event, js, debug=false) {
const defines = this.makeScriptingDefines(event);
const names = Object.keys(defines).join(", ");
const preamble = `const { ${names} } = this;\n`;
try {
const script = new AsyncFunction("", preamble + js);
await script.call(defines);
} catch (e) {
const long = `> SCRIPT ERROR "${e}"\n---\n${js}\n---`;
this.log(long);
const error = `SCRIPT ERROR:\n${e}`;
this.showError(error);
}
}
makeScriptingDefines(event) {
const defines = bindScriptingDefines(SCRIPTING_FUNCTIONS);
addScriptingConstants(defines, this, event);
return defines;
}
playMusic(src) {
const playing = !this.music.paused;
this.music.src = src;
this.autoplay = true;
if (playing) this.music.play();
}
stopMusic() {
this.music.pause();
this.autoplay = false;
}
setBackground(image) {
this.background = image;
}
async showImage(imageID, fileIDs, layer, x, y) {
if (typeof fileIDs === "string") {
fileIDs = [fileIDs];
}
if (fileIDs.length === 0) {
this.hideImage(imageID);
} else {
const images = fileIDs.map((fileID) => this.getFileImageElement(fileID));
this.images.set(imageID, { image: images, layer, x, y });
}
}
hideImage(imageID) {
this.images.delete(imageID);
}
showError(text) {
this.error = true;
this.dialoguePlayback.clear();
this.dialoguePlayback.queue(text, ERROR_STYLE);
this.dialoguePlayback.skip();
this.dialoguePlayback.render();
this.rendering.drawImage(this.dialoguePlayback.dialogueRendering.canvas, 0, 0);
this.dispatchEvent(new CustomEvent("render"));
}
getActivePalette() {
const avatar = getEventById(this.data, this.avatarId);
const room = roomFromEvent(this.data, avatar);
const palette = getPaletteById(this.data, room.palette);
return palette;
}
}
/**
* @param {BipsiPlayback} playback
* @param {BipsiDataEvent} event
* @returns {Promise}
*/
async function standardEventTouch(playback, event) {
for (let script of STANDARD_SCRIPTS) {
await playback.runJS(event, script);
}
for (let script of playback.extra_behaviours) {
await playback.runJS(event, script);
}
}
function sample(playback, id, type, values) {
let iterator = playback.variables.get(id);
if (iterator === undefined) {
iterator = ITERATOR_FUNCS[type](values);
playback.variables.set(id, iterator);
}
return iterator.next()?.value;
}
const ITERATOR_FUNCS = {
"shuffle": makeShuffleIterator,
"cycle": makeCycleIterator,
"sequence": makeSequenceIterator,
"sequence-once": makeSequenceOnceIterator,
}
function* makeShuffleIterator(values) {
values = [...values];
while (values.length > 0) {
shuffleArray(values);
for (let value of values) {
yield value;
}
}
}
function* makeCycleIterator(values) {
values = [...values];
while (values.length > 0) {
for (let value of values) {
yield value;
}
}
}
function* makeSequenceIterator(values) {
values = [...values];
for (let value of values) {
yield value;
}
while (values.length > 0) {
yield values[values.length - 1];
}
}
function* makeSequenceOnceIterator(values) {
values = [...values];
for (let value of values) {
yield value;
}
}
/**
* @param {BipsiPlayback} playback
* @param {BipsiDataEvent} event
* @returns {Promise}
*/
async function runEventRemove(playback, event) {
if (eventIsTagged(event, "one-time")) {
removeEvent(playback.data, event);
}
}
function fakedownToTag(text, fd, tag) {
const pattern = new RegExp(`${fd}([^${fd}]+)${fd}`, 'g');
return text.replace(pattern, `{+${tag}}$1{-${tag}}`);
}
function parseFakedown(text) {
text = fakedownToTag(text, '##', 'shk');
text = fakedownToTag(text, '~~', 'wvy');
text = fakedownToTag(text, '==', 'rbw');
text = fakedownToTag(text, '__', 'r');
return text;
}
/**
* @param {BipsiDataEvent} event
* @param {string} name
* @param {string?} type
*/
function clearFields(event, name, type=undefined) {
const fields = allFields(event, name, type);
fields.forEach((field) => arrayDiscard(event.fields, field));
}
/**
* @param {BipsiDataEvent} event
* @param {string} name
* @param {string} type
* @param {any[]} values
*/
function replaceFields(event, name, type, ...values) {
clearFields(event, name, type);
values.forEach((value) => {
event.fields.push({
key: name,
type,
data: value,
});
});
}
function replace(format) {
const values = Array.prototype.slice.call(arguments, 1);
return format.replace(/\[\s*(\d+)\s*\]/g, (match, index) => values[index] ?? match);
};
function replaceVariables(text, variables) {
return text.replace(/\[\[([^\]]+)\]\]/g, (match, key) => variables.get(key) ?? match);
}
const WALK_DIRECTIONS = {
"L": [-1, 0],
"R": [ 1, 0],
"U": [ 0, -1],
"D": [ 0, 1],
"<": [-1, 0],
">": [ 1, 0],
"^": [ 0, -1],
"v": [ 0, 1],
}
function bindScriptingDefines(defines) {
const bound = {};
for (const [name, func] of Object.entries(defines)) {
bound[name] = func.bind(bound);
}
return bound;
}
const FIELD = (event, name, type=undefined) => oneField(event, name, type)?.data;
const FIELDS = (event, name, type=undefined) => allFields(event, name, type).map((field) => field.data);
const IS_TAGGED = (event, name) => eventIsTagged(event, name);
const SCRIPTING_FUNCTIONS = {
SAY(dialogue, options) {
return this.PLAYBACK.say(dialogue, options);
},
SAY_FIELD(name, options=undefined, event=this.EVENT) {
const text = this.FIELD(event, name, "dialogue") ?? `[FIELD MISSING: ${name}]`;
return this.SAY(text, options);
},
TITLE(dialogue, options) {
return this.PLAYBACK.title(dialogue, options);
},
TOUCH(event) {
return this.PLAYBACK.touch(event);
},
EVENT_AT(location) {
return getEventAtLocation(this.PLAYBACK.data, location);
},
LOCATION_OF(event) {
return getLocationOfEvent(this.PLAYBACK.data, event);
},
FIND_EVENTS(tag) {
return findEventsByTag(this.PLAYBACK.data, tag);
},
FIND_EVENT(tag) {
return findEventByTag(this.PLAYBACK.data, tag);
},
PLAY_MUSIC(file) {
this.PLAYBACK.playMusic(this.PLAYBACK.getFileObjectURL(file));
},
STOP_MUSIC() {
this.PLAYBACK.stopMusic();
},
SHOW_IMAGE(id, files, layer, x, y) {
this.PLAYBACK.showImage(id, files, layer, x, y);
},
HIDE_IMAGE(id) {
this.PLAYBACK.hideImage(id);
},
FILE_TEXT(file) {
return this.PLAYBACK.stateManager.resources.get(file).text();
},
FIELD_OR_LIBRARY(field, event=this.EVENT) {
let file = FIELD(event, field, "file");
let name = FIELD(event, field, "text");
if (!file && name && this.LIBRARY) {
file = FIELD(this.LIBRARY, name, "file");
} else if (!file && this.LIBRARY) {
file = FIELD(this.LIBRARY, field, "file");
}
return file;
},
FIELDS_OR_LIBRARY(field, event=this.EVENT) {
let files = FIELDS(event, field, "file");
let names = FIELDS(event, field, "text");
if(files.length > 0) return files;
if (names && this.LIBRARY) {
files = names.map((name) => FIELD(this.LIBRARY, name, "file"))//.filter(Boolean);
} else if (this.LIBRARY) {
files = FIELDS(this.LIBRARY, field, "file");
}
return files;
},
DO_STANDARD() {
return standardEventTouch(this.PLAYBACK, this.EVENT);
},
MOVE(event, location) {
moveEvent(this.PLAYBACK.data, event, location);
},
FIELD,
FIELDS,
SET_FIELDS(event, name, type, ...values) {
replaceFields(event, name, type, ...values);
},
$FIELD(name, type=undefined, event=this.EVENT) {
return this.FIELD(event, name, type);
},
$FIELDS(name, type=undefined, event=this.EVENT) {
return this.FIELDS(event, name, type);
},
$SET_FIELDS(name, type=undefined, ...values) {
return this.SET_FIELDS(this.EVENT, name, type, ...values);
},
IS_TAGGED,
TAG(event, name) {
replaceFields(event, name, "tag", true);
},
UNTAG(event, name) {
clearFields(event, name, "tag");
},
$IS_TAGGED(name, event=this.EVENT) {
return this.IS_TAGGED(event, name);
},
$TAG(name, event=this.EVENT) {
this.TAG(event, name);
},
$UNTAG(name, event=this.EVENT) {
this.UNTAG(event, name);
},
REMOVE(event=this.EVENT) {
removeEvent(this.PLAYBACK.data, event);
},
$REMOVE(event=this.EVENT) {
this.REMOVE(event);
},
SET_GRAPHIC(event, tile) {
replaceFields(event, "graphic", "tile", tile);
},
$SET_GRAPHIC(tile, event=this.EVENT) {
this.SET_GRAPHIC(event, tile);
},
async WALK(event, sequence, delay=.4, wait=.4) {
const dirs = Array.from(sequence);
for (const dir of dirs) {
if (dir === ".") {
await sleep(wait * 1000);
} else {
let [x, y] = event.position;
const [dx, dy] = WALK_DIRECTIONS[dir];
x = Math.max(0, Math.min(ROOM_SIZE - 1, x + dx));
y = Math.max(0, Math.min(ROOM_SIZE - 1, y + dy));
event.position = [x, y];
await sleep(delay * 1000);
}
}
},
async $WALK(sequence, delay=.4, wait=.4, event=this.EVENT) {
return this.WALK(event, sequence, delay, wait);
},
GET(key, fallback=undefined, target=undefined) {
key = target ? `${this.EVENT_ID(target)}/${key}` : key;
return this.PLAYBACK.variables.get(key) ?? fallback;
},
SET(key, value, target=undefined) {
key = target ? `${this.EVENT_ID(target)}/${key}` : key;
this.PLAYBACK.setVariable(key, value);
},
$GET(key, fallback=undefined, target=this.EVENT) {
return this.GET(key, fallback, target);
},
$SET(key, value, target=this.EVENT) {
this.SET(key, value, target);
},
EVENT_ID(event) {
return event.id;
},
TEXT_REPLACE(text, ...values) {
return replace(text, ...values);
},
LOG(...data) {
this.PLAYBACK.log(...data);
},
DELAY(seconds) {
return sleep(seconds * 1000);
},
RESTART() {
this.PLAYBACK.end();
},
SAMPLE(id, type, ...values) {
return sample(this.PLAYBACK, id, type, ...values);
},
SET_CSS(name, value) {
ONE(":root").style.setProperty(name, value);
},
RUN_JS(script, event=this.EVENT) {
return this.PLAYBACK.runJS(event, script);
},
ADD_BEHAVIOURS(...scripts) {
this.PLAYBACK.extra_behaviours.push(...scripts);
},
POST(message, origin="*") {
postMessageParent(message, origin);
},
async WAIT_INPUT() {
return this.PLAYBACK.waitInput();
},
//binksi
SET_INK_VAR(field, value) {
this.STORY.variablesState.$(field, value);
},
GET_INK_VAR(field) {
this.STORY.variablesState.$(field);
},
DIVERT_TO(knot_name) {
this.STORY.ChoosePathString(knot_name);
return this.PLAYBACK.continueStory();
}
}
/**
* @param {BipsiPlayback} playback
* @param {BipsiDataEvent} event
*/
function addScriptingConstants(defines, playback, event) {
// edit here to add new scripting functions
defines.PLAYBACK = playback;
defines.AVATAR = getEventById(playback.data, playback.avatarId);
defines.LIBRARY = getEventById(playback.data, playback.libraryId);
defines.EVENT = event;
defines.PALETTE = playback.getActivePalette();
defines.DIALOGUE = playback.dialoguePlayback.waiter;
defines.DIALOG = defines.DIALOGUE;
defines.STORY = playback.story;
}
</script>
<script>/**
* @param {CanvasRenderingContext2D} destination
* @param {CanvasRenderingContext2D} tileset
* @param {Map<number, number>} tileToFrame
* @param {BipsiDataPalette} palette
* @param {BipsiDataRoom} room
*/
function drawRoomPreview(destination, tileset, tileToFrame, palette, room) {
const [background] = palette.colors;
fillRendering2D(destination, background);
drawTilemapLayer(destination, tileset, tileToFrame, palette, room);
drawEventLayer(destination, tileset, tileToFrame, palette, room.events);
room.events.forEach((event) => {
const [x, y] = event.position;
destination.fillStyle = "white";
destination.globalAlpha = .5;
destination.fillRect(
x * TILE_PX + 1,
y * TILE_PX + 1,
TILE_PX - 2,
TILE_PX - 2,
);
});
destination.globalAlpha = 1;
}
/**
* @param {CanvasRenderingContext2D} destination
* @param {BipsiPlayback} playback
* @param {number} roomId
*/
function drawRoomPreviewPlayback(destination, playback, roomId) {
const tileset = playback.stateManager.resources.get(playback.data.tileset);
const room = getRoomById(playback.data, roomId);
const palette = getPaletteById(playback.data, room.palette);
const tileToFrame = makeTileToFrameMap(playback.data.tiles, 0);
drawRoomPreview(destination, tileset, tileToFrame, palette, room);
}
/**
* @param {CanvasRenderingContext2D} destination
* @param {BipsiPlayback} playback
* @param {number} roomId
*/
function drawRoomThumbPlayback(destination, playback, roomId) {
const room = getRoomById(playback.data, roomId);
const palette = getPaletteById(playback.data, room.palette);
drawRoomThumbnail(destination, palette, room);
}
async function generateRoomPreviewURL(destination, playback, roomId) {
drawRoomPreviewPlayback(destination, playback, roomId);
URL.createObjectURL(await canvasToBlob(destination.canvas));
}
/**
* @param {BipsiPlayback} playback
* @returns {[string, number][]}
*/
function recordFrames(playback) {
const frames = [];
const temp = createRendering2D(512, 512);
playback.render(0);
temp.drawImage(playback.rendering.canvas, 0, 0, 512, 512);
frames.push([temp.canvas.toDataURL(), 400]);
playback.render(1);
temp.drawImage(playback.rendering.canvas, 0, 0, 512, 512);
frames.push([temp.canvas.toDataURL(), 400]);
return frames;
}
</script>
<script>!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).inkjs={})}(this,(function(t){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function i(t,e,n){return e&&r(t.prototype,e),n&&r(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}function a(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&s(t,e)}function o(t){return(o=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function s(t,e){return(s=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function l(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function u(t,e,n){return(u=l()?Reflect.construct:function(t,e,n){var r=[null];r.push.apply(r,e);var i=new(Function.bind.apply(t,r));return n&&s(i,n.prototype),i}).apply(null,arguments)}function c(t){var e="function"==typeof Map?new Map:void 0;return(c=function(t){if(null===t||(n=t,-1===Function.toString.call(n).indexOf("[native code]")))return t;var n;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,r)}function r(){return u(t,arguments,o(this).constructor)}return r.prototype=Object.create(t.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),s(r,t)})(t)}function h(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function f(t,e){if(e&&("object"==typeof e||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return h(t)}function d(t){var e=l();return function(){var n,r=o(t);if(e){var i=o(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return f(this,n)}}function v(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=o(t)););return t}function p(){return(p="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var r=v(t,e);if(r){var i=Object.getOwnPropertyDescriptor(r,e);return i.get?i.get.call(arguments.length<3?t:n):i.value}}).apply(this,arguments)}function m(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==n)return;var r,i,a=[],o=!0,s=!1;try{for(n=n.call(t);!(o=(r=n.next()).done)&&(a.push(r.value),!e||a.length!==e);o=!0);}catch(t){s=!0,i=t}finally{try{o||null==n.return||n.return()}finally{if(s)throw i}}return a}(t,e)||g(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function y(t){return function(t){if(Array.isArray(t))return C(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||g(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function g(t,e){if(t){if("string"==typeof t)return C(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?C(t,e):void 0}}function C(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function S(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=g(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,i=function(){};return{s:i,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return o=t.done,t},e:function(t){s=!0,a=t},f:function(){try{o||null==n.return||n.return()}finally{if(s)throw a}}}}var b,w=i((function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;n(this,t),this.sourceFilename=e,this.pluginNames=r,this.countAllVisits=i,this.errorHandler=a,this.fileHandler=o})),k=i((function t(e,r,i){n(this,t),this.length=e,this.debugMetadata=r,this.text=i}));!function(t){t[t.Author=0]="Author",t[t.Warning=1]="Warning",t[t.Error=2]="Error"}(b||(b={}));var E=i((function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;n(this,t),this.identifier=e,this.isByReference=r,this.isDivertTarget=i}));function _(t,e){return t instanceof e?N(t):null}function A(t,e){if(t instanceof e)return N(t);throw new Error("".concat(t," is not of type ").concat(e))}function T(t){return t.hasValidName&&t.name?t:null}function P(t){return void 0===t?null:t}function x(t){return"object"===e(t)&&"function"==typeof t.Equals}function N(t,e){return t}function O(t){return null!=t}var I,W=function(){function t(){var e=this;n(this,t),this._alreadyHadError=!1,this._alreadyHadWarning=!1,this._debugMetadata=null,this._runtimeObject=null,this.content=[],this.parent=null,this.GetType=function(){return e.typeName},this.AddContent=function(t){null===e.content&&(e.content=[]);var n,r=S(Array.isArray(t)?t:[t]);try{for(r.s();!(n=r.n()).done;){var i=n.value;i.hasOwnProperty("parent")&&(i.parent=e),e.content.push(i)}}catch(t){r.e(t)}finally{r.f()}return Array.isArray(t)?void 0:t},this.InsertContent=function(t,n){return null===e.content&&(e.content=[]),n.parent=e,e.content.splice(t,0,n),n},this.Find=function(t){return function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,r=_(e,t);if(null!==r&&(null===n||!0===n(r)))return r;if(null===e.content)return null;var i,a=S(e.content);try{for(a.s();!(i=a.n()).done;){var o=i.value,s=o.Find&&o.Find(t)(n);if(s)return s}}catch(t){a.e(t)}finally{a.f()}return null}},this.FindAll=function(t){return function(n,r){var i=Array.isArray(r)?r:[],a=_(e,t);if(null===a||n&&!0!==n(a)||i.push(a),null===e.content)return[];var o,s=S(e.content);try{for(s.s();!(o=s.n()).done;){var l=o.value;l.FindAll&&l.FindAll(t)(n,i)}}catch(t){s.e(t)}finally{s.f()}return i}},this.Warning=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;e.Error(t,n,!0)}}return i(t,[{key:"debugMetadata",get:function(){return null===this._debugMetadata&&this.parent?this.parent.debugMetadata:this._debugMetadata},set:function(t){this._debugMetadata=t}},{key:"hasOwnDebugMetadata",get:function(){return Boolean(this.debugMetadata)}},{key:"typeName",get:function(){return"ParsedObject"}},{key:"story",get:function(){for(var t=this;t.parent;)t=t.parent;return t}},{key:"runtimeObject",get:function(){return this._runtimeObject||(this._runtimeObject=this.GenerateRuntimeObject(),this._runtimeObject&&(this._runtimeObject.debugMetadata=this.debugMetadata)),this._runtimeObject},set:function(t){this._runtimeObject=t}},{key:"runtimePath",get:function(){if(!this.runtimeObject.path)throw new Error;return this.runtimeObject.path}},{key:"containerForCounting",get:function(){return this.runtimeObject}},{key:"ancestry",get:function(){for(var t=[],e=this.parent;e;)t.push(e),e=e.parent;return t=t.reverse()}},{key:"ResolveReferences",value:function(t){if(null!==this.content){var e,n=S(this.content);try{for(n.s();!(e=n.n()).done;){e.value.ResolveReferences(t)}}catch(t){n.e(t)}finally{n.f()}}}},{key:"Error",value:function(t){function e(e){return t.apply(this,arguments)}return e.toString=function(){return t.toString()},e}((function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(null===e&&(e=this),!(e._alreadyHadError&&!n||e._alreadyHadWarning&&n)){if(!this.parent)throw new Error("No parent object to send error to: ".concat(t));this.parent.Error(t,e,n),n?e._alreadyHadWarning=!0:e._alreadyHadError=!0}}))}]),t}(),F=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).warningMessage=t,i.GenerateRuntimeObject=function(){return i.Warning(i.warningMessage),null},i}return i(r,[{key:"typeName",get:function(){return"AuthorWarning"}}]),r}(W),R=function(){function t(){if(n(this,t),this._components=[],this._componentsString=null,this._isRelative=!1,"string"==typeof arguments[0]){var e=arguments[0];this.componentsString=e}else if(arguments[0]instanceof t.Component&&arguments[1]instanceof t){var r=arguments[0],i=arguments[1];this._components.push(r),this._components=this._components.concat(i._components)}else if(arguments[0]instanceof Array){var a=arguments[0],o=!!arguments[1];this._components=this._components.concat(a),this._isRelative=o}}return i(t,[{key:"isRelative",get:function(){return this._isRelative}},{key:"componentCount",get:function(){return this._components.length}},{key:"head",get:function(){return this._components.length>0?this._components[0]:null}},{key:"tail",get:function(){return this._components.length>=2?new t(this._components.slice(1,this._components.length)):t.self}},{key:"length",get:function(){return this._components.length}},{key:"lastComponent",get:function(){var t=this._components.length-1;return t>=0?this._components[t]:null}},{key:"containsNamedComponent",get:function(){for(var t=0,e=this._components.length;t<e;t++)if(!this._components[t].isIndex)return!0;return!1}},{key:"GetComponent",value:function(t){return this._components[t]}},{key:"PathByAppendingPath",value:function(e){for(var n=new t,r=0,i=0;i<e._components.length&&e._components[i].isParent;++i)r++;for(var a=0;a<this._components.length-r;++a)n._components.push(this._components[a]);for(var o=r;o<e._components.length;++o)n._components.push(e._components[o]);return n}},{key:"componentsString",get:function(){return null==this._componentsString&&(this._componentsString=this._components.join("."),this.isRelative&&(this._componentsString="."+this._componentsString)),this._componentsString},set:function(e){if(this._components.length=0,this._componentsString=e,null!=this._componentsString&&""!=this._componentsString){"."==this._componentsString[0]&&(this._isRelative=!0,this._componentsString=this._componentsString.substring(1));var n,r=S(this._componentsString.split("."));try{for(r.s();!(n=r.n()).done;){var i=n.value;/^(\-|\+)?([0-9]+|Infinity)$/.test(i)?this._components.push(new t.Component(parseInt(i))):this._components.push(new t.Component(i))}}catch(t){r.e(t)}finally{r.f()}}}},{key:"toString",value:function(){return this.componentsString}},{key:"Equals",value:function(t){if(null==t)return!1;if(t._components.length!=this._components.length)return!1;if(t.isRelative!=this.isRelative)return!1;for(var e=0,n=t._components.length;e<n;e++)if(!t._components[e].Equals(this._components[e]))return!1;return!0}},{key:"PathByAppendingComponent",value:function(e){var n,r=new t;return(n=r._components).push.apply(n,y(this._components)),r._components.push(e),r}}],[{key:"self",get:function(){var e=new t;return e._isRelative=!0,e}}]),t}();R.parentId="^",function(t){var e=function(){function e(t){n(this,e),this.index=-1,this.name=null,"string"==typeof t?this.name=t:this.index=t}return i(e,[{key:"isIndex",get:function(){return this.index>=0}},{key:"isParent",get:function(){return this.name==t.parentId}},{key:"toString",value:function(){return this.isIndex?this.index.toString():this.name}},{key:"Equals",value:function(t){return null!=t&&t.isIndex==this.isIndex&&(this.isIndex?this.index==t.index:this.name==t.name)}}],[{key:"ToParent",value:function(){return new e(t.parentId)}}]),e}();t.Component=e}(R||(R={})),function(t){function e(t,e){if(!t)throw void 0!==e&&console.warn(e),console.trace&&console.trace(),new Error("")}t.AssertType=function(t,n,r){e(t instanceof n,r)},t.Assert=e}(I||(I={}));var D=function(t){a(r,t);var e=d(r);function r(){return n(this,r),e.apply(this,arguments)}return i(r)}(c(Error));function L(t){throw new D("".concat(t," is null or undefined"))}var V=function(){function t(){n(this,t),this.parent=null,this._debugMetadata=null,this._path=null}return i(t,[{key:"debugMetadata",get:function(){return null===this._debugMetadata&&this.parent?this.parent.debugMetadata:this._debugMetadata},set:function(t){this._debugMetadata=t}},{key:"ownDebugMetadata",get:function(){return this._debugMetadata}},{key:"DebugLineNumberOfPath",value:function(t){if(null===t)return null;var e=this.rootContentContainer;if(e){var n=e.ContentAtPath(t).obj;if(n){var r=n.debugMetadata;if(null!==r)return r.startLineNumber}}return null}},{key:"path",get:function(){if(null==this._path)if(null==this.parent)this._path=new R;else{for(var t=[],e=this,n=_(e.parent,tt);null!==n;){var r=T(e);if(null!=r&&r.hasValidName){if(null===r.name)return L("namedChild.name");t.unshift(new R.Component(r.name))}else t.unshift(new R.Component(n.content.indexOf(e)));e=n,n=_(n.parent,tt)}this._path=new R(t)}return this._path}},{key:"ResolvePath",value:function(t){if(null===t)return L("path");if(t.isRelative){var e=_(this,tt);return null===e&&(I.Assert(null!==this.parent,"Can't resolve relative path because we don't have a parent"),e=_(this.parent,tt),I.Assert(null!==e,"Expected parent to be a container"),I.Assert(t.GetComponent(0).isParent),t=t.tail),null===e?L("nearestContainer"):e.ContentAtPath(t)}var n=this.rootContentContainer;return null===n?L("contentContainer"):n.ContentAtPath(t)}},{key:"ConvertPathToRelative",value:function(t){for(var e=this.path,n=Math.min(t.length,e.length),r=-1,i=0;i<n;++i){var a=e.GetComponent(i),o=t.GetComponent(i);if(!a.Equals(o))break;r=i}if(-1==r)return t;for(var s=e.componentCount-1-r,l=[],u=0;u<s;++u)l.push(R.Component.ToParent());for(var c=r+1;c<t.componentCount;++c)l.push(t.GetComponent(c));return new R(l,!0)}},{key:"CompactPathString",value:function(t){var e=null,n=null;t.isRelative?(n=t.componentsString,e=this.path.PathByAppendingPath(t).componentsString):(n=this.ConvertPathToRelative(t).componentsString,e=t.componentsString);return n.length<e.length?n:e}},{key:"rootContentContainer",get:function(){for(var t=this;t.parent;)t=t.parent;return _(t,tt)}},{key:"Copy",value:function(){throw Error("Not Implemented: Doesn't support copying")}},{key:"SetChild",value:function(t,e,n){t[e]&&(t[e]=null),t[e]=n,t[e]&&(t[e].parent=this)}},{key:"Equals",value:function(t){return t===this}}]),t}(),j=function(){function t(e){n(this,t),e=void 0!==e?e.toString():"",this.string=e}return i(t,[{key:"Length",get:function(){return this.string.length}},{key:"Append",value:function(t){null!==t&&(this.string+=t)}},{key:"AppendLine",value:function(t){void 0!==t&&this.Append(t),this.string+="\n"}},{key:"AppendFormat",value:function(t){for(var e=arguments.length,n=new Array(e>1?e-1:0),r=1;r<e;r++)n[r-1]=arguments[r];this.string+=t.replace(/{(\d+)}/g,(function(t,e){return void 0!==n[e]?n[e]:t}))}},{key:"toString",value:function(){return this.string}}]),t}(),M=function(){function t(){if(n(this,t),this.originName=null,this.itemName=null,void 0!==arguments[1]){var e=arguments[0],r=arguments[1];this.originName=e,this.itemName=r}else if(arguments[0]){var i=arguments[0],a=i.toString().split(".");this.originName=a[0],this.itemName=a[1]}}return i(t,[{key:"isNull",get:function(){return null==this.originName&&null==this.itemName}},{key:"fullName",get:function(){return(null!==this.originName?this.originName:"?")+"."+this.itemName}},{key:"toString",value:function(){return this.fullName}},{key:"Equals",value:function(e){if(e instanceof t){var n=e;return n.itemName==this.itemName&&n.originName==this.originName}return!1}},{key:"copy",value:function(){return new t(this.originName,this.itemName)}},{key:"serialized",value:function(){return JSON.stringify({originName:this.originName,itemName:this.itemName})}}],[{key:"Null",get:function(){return new t(null,null)}},{key:"fromSerializedKey",value:function(e){var n=JSON.parse(e);if(!t.isLikeInkListItem(n))return t.Null;var r=n;return new t(r.originName,r.itemName)}},{key:"isLikeInkListItem",value:function(t){return"object"===e(t)&&(!(!t.hasOwnProperty("originName")||!t.hasOwnProperty("itemName"))&&(("string"==typeof t.originName||null===typeof t.originName)&&("string"==typeof t.itemName||null===typeof t.itemName)))}}]),t}(),B=function(t){a(o,t);var r=d(o);function o(){var t,i=arguments;if(n(this,o),(t=r.call(this,i[0]instanceof o?i[0]:[])).origins=null,t._originNames=[],arguments[0]instanceof o){var a=arguments[0];t._originNames=a.originNames,null!==a.origins&&(t.origins=a.origins.slice())}else if("string"==typeof arguments[0]){var s=arguments[0],l=arguments[1];if(t.SetInitialOriginName(s),null===l.listDefinitions)return f(t,L("originStory.listDefinitions"));var u=l.listDefinitions.TryListGetDefinition(s,null);if(!u.exists)throw new Error("InkList origin could not be found in story when constructing new list: "+s);if(null===u.result)return f(t,L("def.result"));t.origins=[u.result]}else if("object"===e(arguments[0])&&arguments[0].hasOwnProperty("Key")&&arguments[0].hasOwnProperty("Value")){var c=arguments[0];t.Add(c.Key,c.Value)}return t}return i(o,[{key:"AddItem",value:function(t){if(t instanceof M){var e=t;if(null==e.originName)return void this.AddItem(e.itemName);if(null===this.origins)return L("this.origins");var n,r=S(this.origins);try{for(r.s();!(n=r.n()).done;){var i=n.value;if(i.name==e.originName){var a=i.TryGetValueForItem(e,0);if(a.exists)return void this.Add(e,a.result);throw new Error("Could not add the item "+e+" to this list because it doesn't exist in the original list definition in ink.")}}}catch(t){r.e(t)}finally{r.f()}throw new Error("Failed to add item to list because the item was from a new list definition that wasn't previously known to this list. Only items from previously known lists can be used, so that the int value can be found.")}var o=t,s=null;if(null===this.origins)return L("this.origins");var l,u=S(this.origins);try{for(u.s();!(l=u.n()).done;){var c=l.value;if(null===o)return L("itemName");if(c.ContainsItemWithName(o)){if(null!=s)throw new Error("Could not add the item "+o+" to this list because it could come from either "+c.name+" or "+s.name);s=c}}}catch(t){u.e(t)}finally{u.f()}if(null==s)throw new Error("Could not add the item "+o+" to this list because it isn't known to any list definitions previously associated with this list.");var h=new M(s.name,o),f=s.ValueForItem(h);this.Add(h,f)}},{key:"ContainsItemNamed",value:function(t){var e,n=S(this);try{for(n.s();!(e=n.n()).done;){var r=m(e.value,1)[0];if(M.fromSerializedKey(r).itemName==t)return!0}}catch(t){n.e(t)}finally{n.f()}return!1}},{key:"ContainsKey",value:function(t){return this.has(t.serialized())}},{key:"Add",value:function(t,e){var n=t.serialized();if(this.has(n))throw new Error("The Map already contains an entry for ".concat(t));this.set(n,e)}},{key:"Remove",value:function(t){return this.delete(t.serialized())}},{key:"Count",get:function(){return this.size}},{key:"originOfMaxItem",get:function(){if(null==this.origins)return null;var t=this.maxItem.Key.originName,e=null;return this.origins.every((function(n){return n.name!=t||(e=n,!1)})),e}},{key:"originNames",get:function(){if(this.Count>0){null==this._originNames&&this.Count>0?this._originNames=[]:(this._originNames||(this._originNames=[]),this._originNames.length=0);var t,e=S(this);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,1)[0],r=M.fromSerializedKey(n);if(null===r.originName)return L("item.originName");this._originNames.push(r.originName)}}catch(t){e.e(t)}finally{e.f()}}return this._originNames}},{key:"SetInitialOriginName",value:function(t){this._originNames=[t]}},{key:"SetInitialOriginNames",value:function(t){this._originNames=null==t?null:t.slice()}},{key:"maxItem",get:function(){var t,e={Key:M.Null,Value:0},n=S(this);try{for(n.s();!(t=n.n()).done;){var r=m(t.value,2),i=r[0],a=r[1],o=M.fromSerializedKey(i);(e.Key.isNull||a>e.Value)&&(e={Key:o,Value:a})}}catch(t){n.e(t)}finally{n.f()}return e}},{key:"minItem",get:function(){var t,e={Key:M.Null,Value:0},n=S(this);try{for(n.s();!(t=n.n()).done;){var r=m(t.value,2),i=r[0],a=r[1],o=M.fromSerializedKey(i);(e.Key.isNull||a<e.Value)&&(e={Key:o,Value:a})}}catch(t){n.e(t)}finally{n.f()}return e}},{key:"inverse",get:function(){var t=new o;if(null!=this.origins){var e,n=S(this.origins);try{for(n.s();!(e=n.n()).done;){var r,i=S(e.value.items);try{for(i.s();!(r=i.n()).done;){var a=m(r.value,2),s=a[0],l=a[1],u=M.fromSerializedKey(s);this.ContainsKey(u)||t.Add(u,l)}}catch(t){i.e(t)}finally{i.f()}}}catch(t){n.e(t)}finally{n.f()}}return t}},{key:"all",get:function(){var t=new o;if(null!=this.origins){var e,n=S(this.origins);try{for(n.s();!(e=n.n()).done;){var r,i=S(e.value.items);try{for(i.s();!(r=i.n()).done;){var a=m(r.value,2),s=a[0],l=a[1],u=M.fromSerializedKey(s);t.set(u.serialized(),l)}}catch(t){i.e(t)}finally{i.f()}}}catch(t){n.e(t)}finally{n.f()}}return t}},{key:"Union",value:function(t){var e,n=new o(this),r=S(t);try{for(r.s();!(e=r.n()).done;){var i=m(e.value,2),a=i[0],s=i[1];n.set(a,s)}}catch(t){r.e(t)}finally{r.f()}return n}},{key:"Intersect",value:function(t){var e,n=new o,r=S(this);try{for(r.s();!(e=r.n()).done;){var i=m(e.value,2),a=i[0],s=i[1];t.has(a)&&n.set(a,s)}}catch(t){r.e(t)}finally{r.f()}return n}},{key:"Without",value:function(t){var e,n=new o(this),r=S(t);try{for(r.s();!(e=r.n()).done;){var i=m(e.value,1)[0];n.delete(i)}}catch(t){r.e(t)}finally{r.f()}return n}},{key:"Contains",value:function(t){var e,n=S(t);try{for(n.s();!(e=n.n()).done;){var r=m(e.value,1)[0];if(!this.has(r))return!1}}catch(t){n.e(t)}finally{n.f()}return!0}},{key:"GreaterThan",value:function(t){return 0!=this.Count&&(0==t.Count||this.minItem.Value>t.maxItem.Value)}},{key:"GreaterThanOrEquals",value:function(t){return 0!=this.Count&&(0==t.Count||this.minItem.Value>=t.minItem.Value&&this.maxItem.Value>=t.maxItem.Value)}},{key:"LessThan",value:function(t){return 0!=t.Count&&(0==this.Count||this.maxItem.Value<t.minItem.Value)}},{key:"LessThanOrEquals",value:function(t){return 0!=t.Count&&(0==this.Count||this.maxItem.Value<=t.maxItem.Value&&this.minItem.Value<=t.minItem.Value)}},{key:"MaxAsList",value:function(){return this.Count>0?new o(this.maxItem):new o}},{key:"MinAsList",value:function(){return this.Count>0?new o(this.minItem):new o}},{key:"ListWithSubRange",value:function(t,e){if(0==this.Count)return new o;var n=this.orderedItems,r=0,i=Number.MAX_SAFE_INTEGER;Number.isInteger(t)?r=t:t instanceof o&&t.Count>0&&(r=t.minItem.Value),Number.isInteger(e)?i=e:t instanceof o&&t.Count>0&&(i=e.maxItem.Value);var a=new o;a.SetInitialOriginNames(this.originNames);var s,l=S(n);try{for(l.s();!(s=l.n()).done;){var u=s.value;u.Value>=r&&u.Value<=i&&a.Add(u.Key,u.Value)}}catch(t){l.e(t)}finally{l.f()}return a}},{key:"Equals",value:function(t){if(t instanceof o==!1)return!1;if(t.Count!=this.Count)return!1;var e,n=S(this);try{for(n.s();!(e=n.n()).done;){var r=m(e.value,1)[0];if(!t.has(r))return!1}}catch(t){n.e(t)}finally{n.f()}return!0}},{key:"orderedItems",get:function(){var t,e=new Array,n=S(this);try{for(n.s();!(t=n.n()).done;){var r=m(t.value,2),i=r[0],a=r[1],o=M.fromSerializedKey(i);e.push({Key:o,Value:a})}}catch(t){n.e(t)}finally{n.f()}return e.sort((function(t,e){return null===t.Key.originName?L("x.Key.originName"):null===e.Key.originName?L("y.Key.originName"):t.Value==e.Value?t.Key.originName.localeCompare(e.Key.originName):t.Value<e.Value?-1:t.Value>e.Value?1:0})),e}},{key:"toString",value:function(){for(var t=this.orderedItems,e=new j,n=0;n<t.length;n++){n>0&&e.Append(", ");var r=t[n].Key;if(null===r.itemName)return L("item.itemName");e.Append(r.itemName)}return e.toString()}},{key:"valueOf",value:function(){return NaN}}],[{key:"FromString",value:function(t,e){var n,r=null===(n=e.listDefinitions)||void 0===n?void 0:n.FindSingleItemListWithName(t);if(r)return null===r.value?L("listValue.value"):new o(r.value);throw new Error("Could not find the InkListItem from the string '"+t+"' to create an InkList because it doesn't exist in the original list definition in ink.")}}]),o}(c(Map)),G=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this,t)).useEndLineNumber=!1,i.message=t,i.name="StoryException",i}return i(r)}(c(Error));function q(t,e,n){if(null===t)return{result:n,exists:!1};var r=t.get(e);return void 0===r?{result:n,exists:!1}:{result:r,exists:!0}}var U,K=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).value=t,i}return i(r,[{key:"valueObject",get:function(){return this.value}},{key:"toString",value:function(){return null===this.value?L("Value.value"):this.value.toString()}}]),r}(function(t){a(r,t);var e=d(r);function r(){return n(this,r),e.apply(this,arguments)}return i(r,[{key:"Copy",value:function(){return A(r.Create(this.valueObject),V)}},{key:"BadCastException",value:function(t){return new G("Can't cast "+this.valueObject+" from "+this.valueType+" to "+t)}}],[{key:"Create",value:function(t,e){if(e){if(e===U.Int&&Number.isInteger(Number(t)))return new J(Number(t));if(e===U.Float&&!isNaN(t))return new z(Number(t))}return"boolean"==typeof t?new H(Boolean(t)):"string"==typeof t?new $(String(t)):Number.isInteger(Number(t))?new J(Number(t)):isNaN(t)?t instanceof R?new X(A(t,R)):t instanceof B?new Z(A(t,B)):null:new z(Number(t))}}]),r}(V)),H=function(t){a(r,t);var e=d(r);function r(t){return n(this,r),e.call(this,t||!1)}return i(r,[{key:"isTruthy",get:function(){return Boolean(this.value)}},{key:"valueType",get:function(){return U.Bool}},{key:"Cast",value:function(t){if(null===this.value)return L("Value.value");if(t==this.valueType)return this;if(t==U.Int)return new J(this.value?1:0);if(t==U.Float)return new z(this.value?1:0);if(t==U.String)return new $(this.value?"true":"false");throw this.BadCastException(t)}},{key:"toString",value:function(){return this.value?"true":"false"}}]),r}(K),J=function(t){a(r,t);var e=d(r);function r(t){return n(this,r),e.call(this,t||0)}return i(r,[{key:"isTruthy",get:function(){return 0!=this.value}},{key:"valueType",get:function(){return U.Int}},{key:"Cast",value:function(t){if(null===this.value)return L("Value.value");if(t==this.valueType)return this;if(t==U.Bool)return new H(0!==this.value);if(t==U.Float)return new z(this.value);if(t==U.String)return new $(""+this.value);throw this.BadCastException(t)}}]),r}(K),z=function(t){a(r,t);var e=d(r);function r(t){return n(this,r),e.call(this,t||0)}return i(r,[{key:"isTruthy",get:function(){return 0!=this.value}},{key:"valueType",get:function(){return U.Float}},{key:"Cast",value:function(t){if(null===this.value)return L("Value.value");if(t==this.valueType)return this;if(t==U.Bool)return new H(0!==this.value);if(t==U.Int)return new J(this.value);if(t==U.String)return new $(""+this.value);throw this.BadCastException(t)}}]),r}(K),$=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this,t||""))._isNewline="\n"==i.value,i._isInlineWhitespace=!0,null===i.value?f(i,L("Value.value")):(i.value.length>0&&i.value.split("").every((function(t){return" "==t||"\t"==t||(i._isInlineWhitespace=!1,!1)})),i)}return i(r,[{key:"valueType",get:function(){return U.String}},{key:"isTruthy",get:function(){return null===this.value?L("Value.value"):this.value.length>0}},{key:"isNewline",get:function(){return this._isNewline}},{key:"isInlineWhitespace",get:function(){return this._isInlineWhitespace}},{key:"isNonWhitespace",get:function(){return!this.isNewline&&!this.isInlineWhitespace}},{key:"Cast",value:function(t){if(t==this.valueType)return this;if(t==U.Int){var e=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=parseInt(t);return Number.isNaN(n)?{result:e,exists:!1}:{result:n,exists:!0}}(this.value);if(e.exists)return new J(e.result);throw this.BadCastException(t)}if(t==U.Float){var n=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=parseFloat(t);return Number.isNaN(n)?{result:e,exists:!1}:{result:n,exists:!0}}(this.value);if(n.exists)return new z(n.result);throw this.BadCastException(t)}throw this.BadCastException(t)}}]),r}(K),X=function(t){a(r,t);var e=d(r);function r(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return n(this,r),e.call(this,t)}return i(r,[{key:"valueType",get:function(){return U.DivertTarget}},{key:"targetPath",get:function(){return null===this.value?L("Value.value"):this.value},set:function(t){this.value=t}},{key:"isTruthy",get:function(){throw new Error("Shouldn't be checking the truthiness of a divert target")}},{key:"Cast",value:function(t){if(t==this.valueType)return this;throw this.BadCastException(t)}},{key:"toString",value:function(){return"DivertTargetValue("+this.targetPath+")"}}]),r}(K),Y=function(t){a(r,t);var e=d(r);function r(t){var i,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return n(this,r),(i=e.call(this,t))._contextIndex=a,i}return i(r,[{key:"contextIndex",get:function(){return this._contextIndex},set:function(t){this._contextIndex=t}},{key:"variableName",get:function(){return null===this.value?L("Value.value"):this.value},set:function(t){this.value=t}},{key:"valueType",get:function(){return U.VariablePointer}},{key:"isTruthy",get:function(){throw new Error("Shouldn't be checking the truthiness of a variable pointer")}},{key:"Cast",value:function(t){if(t==this.valueType)return this;throw this.BadCastException(t)}},{key:"toString",value:function(){return"VariablePointerValue("+this.variableName+")"}},{key:"Copy",value:function(){return new r(this.variableName,this.contextIndex)}}]),r}(K),Z=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),a=e.call(this,null),t||i?t instanceof B?a.value=new B(t):t instanceof M&&"number"==typeof i&&(a.value=new B({Key:t,Value:i})):a.value=new B,a}return i(r,[{key:"isTruthy",get:function(){return null===this.value?L("this.value"):this.value.Count>0}},{key:"valueType",get:function(){return U.List}},{key:"Cast",value:function(t){if(null===this.value)return L("Value.value");if(t==U.Int){var e=this.value.maxItem;return e.Key.isNull?new J(0):new J(e.Value)}if(t==U.Float){var n=this.value.maxItem;return n.Key.isNull?new z(0):new z(n.Value)}if(t==U.String){var r=this.value.maxItem;return r.Key.isNull?new $(""):new $(r.Key.toString())}if(t==this.valueType)return this;throw this.BadCastException(t)}}],[{key:"RetainListOriginsForAssignment",value:function(t,e){var n=_(t,r),i=_(e,r);return i&&null===i.value?L("newList.value"):n&&null===n.value?L("oldList.value"):void(n&&i&&0==i.value.Count&&i.value.SetInitialOriginNames(n.value.originNames))}}]),r}(K);!function(t){t[t.Bool=-1]="Bool",t[t.Int=0]="Int",t[t.Float=1]="Float",t[t.List=2]="List",t[t.String=3]="String",t[t.DivertTarget=4]="DivertTarget",t[t.VariablePointer=5]="VariablePointer"}(U||(U={}));var Q=function(){function t(){n(this,t),this.obj=null,this.approximate=!1}return i(t,[{key:"correctObj",get:function(){return this.approximate?null:this.obj}},{key:"container",get:function(){return this.obj instanceof tt?this.obj:null}},{key:"copy",value:function(){var e=new t;return e.obj=this.obj,e.approximate=this.approximate,e}}]),t}(),tt=function(t){a(r,t);var e=d(r);function r(){var t;return n(this,r),(t=e.apply(this,arguments)).name=null,t._content=[],t.namedContent=new Map,t.visitsShouldBeCounted=!1,t.turnIndexShouldBeCounted=!1,t.countingAtStartOnly=!1,t._pathToFirstLeafContent=null,t}return i(r,[{key:"hasValidName",get:function(){return null!=this.name&&this.name.length>0}},{key:"content",get:function(){return this._content},set:function(t){this.AddContent(t)}},{key:"namedOnlyContent",get:function(){var t,e=new Map,n=S(this.namedContent);try{for(n.s();!(t=n.n()).done;){var r=m(t.value,2),i=r[0],a=A(r[1],V);e.set(i,a)}}catch(t){n.e(t)}finally{n.f()}var o,s=S(this.content);try{for(s.s();!(o=s.n()).done;){var l=T(o.value);null!=l&&l.hasValidName&&e.delete(l.name)}}catch(t){s.e(t)}finally{s.f()}return 0==e.size&&(e=null),e},set:function(t){var e=this.namedOnlyContent;if(null!=e){var n,r=S(e);try{for(r.s();!(n=r.n()).done;){var i=m(n.value,1)[0];this.namedContent.delete(i)}}catch(t){r.e(t)}finally{r.f()}}if(null!=t){var a,o=S(t);try{for(o.s();!(a=o.n()).done;){var s=T(m(a.value,2)[1]);null!=s&&this.AddToNamedContentOnly(s)}}catch(t){o.e(t)}finally{o.f()}}}},{key:"countFlags",get:function(){var t=0;return this.visitsShouldBeCounted&&(t|=r.CountFlags.Visits),this.turnIndexShouldBeCounted&&(t|=r.CountFlags.Turns),this.countingAtStartOnly&&(t|=r.CountFlags.CountStartOnly),t==r.CountFlags.CountStartOnly&&(t=0),t},set:function(t){var e=t;(e&r.CountFlags.Visits)>0&&(this.visitsShouldBeCounted=!0),(e&r.CountFlags.Turns)>0&&(this.turnIndexShouldBeCounted=!0),(e&r.CountFlags.CountStartOnly)>0&&(this.countingAtStartOnly=!0)}},{key:"pathToFirstLeafContent",get:function(){return null==this._pathToFirstLeafContent&&(this._pathToFirstLeafContent=this.path.PathByAppendingPath(this.internalPathToFirstLeafContent)),this._pathToFirstLeafContent}},{key:"internalPathToFirstLeafContent",get:function(){for(var t=[],e=this;e instanceof r;)e.content.length>0&&(t.push(new R.Component(0)),e=e.content[0]);return new R(t)}},{key:"AddContent",value:function(t){if(t instanceof Array){var e,n=S(t);try{for(n.s();!(e=n.n()).done;){var r=e.value;this.AddContent(r)}}catch(t){n.e(t)}finally{n.f()}}else{var i=t;if(this._content.push(i),i.parent)throw new Error("content is already in "+i.parent);i.parent=this,this.TryAddNamedContent(i)}}},{key:"TryAddNamedContent",value:function(t){var e=T(t);null!=e&&e.hasValidName&&this.AddToNamedContentOnly(e)}},{key:"AddToNamedContentOnly",value:function(t){if(I.AssertType(t,V,"Can only add Runtime.Objects to a Runtime.Container"),A(t,V).parent=this,null===t.name)return L("namedContentObj.name");this.namedContent.set(t.name,t)}},{key:"ContentAtPath",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1;-1==n&&(n=t.length);var i=new Q;i.approximate=!1;for(var a=this,o=this,s=e;s<n;++s){var l=t.GetComponent(s);if(null==a){i.approximate=!0;break}var u=a.ContentWithPathComponent(l);if(null==u){i.approximate=!0;break}o=u,a=_(u,r)}return i.obj=o,i}},{key:"InsertContent",value:function(t,e){if(this.content.splice(e,0,t),t.parent)throw new Error("content is already in "+t.parent);t.parent=this,this.TryAddNamedContent(t)}},{key:"AddContentsOfContainer",value:function(t){var e;(e=this.content).push.apply(e,y(t.content));var n,r=S(t.content);try{for(r.s();!(n=r.n()).done;){var i=n.value;i.parent=this,this.TryAddNamedContent(i)}}catch(t){r.e(t)}finally{r.f()}}},{key:"ContentWithPathComponent",value:function(t){if(t.isIndex)return t.index>=0&&t.index<this.content.length?this.content[t.index]:null;if(t.isParent)return this.parent;if(null===t.name)return L("component.name");var e=q(this.namedContent,t.name,null);return e.exists?A(e.result,V):null}},{key:"BuildStringOfHierarchy",value:function(){var t;if(0==arguments.length)return t=new j,this.BuildStringOfHierarchy(t,0,null),t.toString();t=arguments[0];var e=arguments[1],n=arguments[2];function i(){for(var n=0;n<4*e;++n)t.Append(" ")}i(),t.Append("["),this.hasValidName&&t.AppendFormat(" ({0})",this.name),this==n&&t.Append(" <---"),t.AppendLine(),e++;for(var a=0;a<this.content.length;++a){var o=this.content[a];if(o instanceof r){var s=o;s.BuildStringOfHierarchy(t,e,n)}else i(),o instanceof $?(t.Append('"'),t.Append(o.toString().replace("\n","\\n")),t.Append('"')):t.Append(o.toString());a!=this.content.length-1&&t.Append(","),o instanceof r||o!=n||t.Append(" <---"),t.AppendLine()}var l,u=new Map,c=S(this.namedContent);try{for(c.s();!(l=c.n()).done;){var h=m(l.value,2),f=h[0],d=h[1];this.content.indexOf(A(d,V))>=0||u.set(f,d)}}catch(t){c.e(t)}finally{c.f()}if(u.size>0){i(),t.AppendLine("-- named: --");var v,p=S(u);try{for(p.s();!(v=p.n()).done;){var y=m(v.value,2),g=y[1];I.AssertType(g,r,"Can only print out named Containers");var C=g;C.BuildStringOfHierarchy(t,e,n),t.AppendLine()}}catch(t){p.e(t)}finally{p.f()}}e--,i(),t.Append("]")}}]),r}(V);!function(t){var e;(e=t.CountFlags||(t.CountFlags={}))[e.Visits=1]="Visits",e[e.Turns=2]="Turns",e[e.CountStartOnly=4]="CountStartOnly"}(tt||(tt={}));var et=function(t){a(r,t);var e=d(r);function r(){var t,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:r.CommandType.NotSet;return n(this,r),(t=e.call(this))._commandType=i,t}return i(r,[{key:"commandType",get:function(){return this._commandType}},{key:"Copy",value:function(){return new r(this.commandType)}},{key:"toString",value:function(){return this.commandType.toString()}}],[{key:"EvalStart",value:function(){return new r(r.CommandType.EvalStart)}},{key:"EvalOutput",value:function(){return new r(r.CommandType.EvalOutput)}},{key:"EvalEnd",value:function(){return new r(r.CommandType.EvalEnd)}},{key:"Duplicate",value:function(){return new r(r.CommandType.Duplicate)}},{key:"PopEvaluatedValue",value:function(){return new r(r.CommandType.PopEvaluatedValue)}},{key:"PopFunction",value:function(){return new r(r.CommandType.PopFunction)}},{key:"PopTunnel",value:function(){return new r(r.CommandType.PopTunnel)}},{key:"BeginString",value:function(){return new r(r.CommandType.BeginString)}},{key:"EndString",value:function(){return new r(r.CommandType.EndString)}},{key:"NoOp",value:function(){return new r(r.CommandType.NoOp)}},{key:"ChoiceCount",value:function(){return new r(r.CommandType.ChoiceCount)}},{key:"Turns",value:function(){return new r(r.CommandType.Turns)}},{key:"TurnsSince",value:function(){return new r(r.CommandType.TurnsSince)}},{key:"ReadCount",value:function(){return new r(r.CommandType.ReadCount)}},{key:"Random",value:function(){return new r(r.CommandType.Random)}},{key:"SeedRandom",value:function(){return new r(r.CommandType.SeedRandom)}},{key:"VisitIndex",value:function(){return new r(r.CommandType.VisitIndex)}},{key:"SequenceShuffleIndex",value:function(){return new r(r.CommandType.SequenceShuffleIndex)}},{key:"StartThread",value:function(){return new r(r.CommandType.StartThread)}},{key:"Done",value:function(){return new r(r.CommandType.Done)}},{key:"End",value:function(){return new r(r.CommandType.End)}},{key:"ListFromInt",value:function(){return new r(r.CommandType.ListFromInt)}},{key:"ListRange",value:function(){return new r(r.CommandType.ListRange)}},{key:"ListRandom",value:function(){return new r(r.CommandType.ListRandom)}}]),r}(V);!function(t){var e;(e=t.CommandType||(t.CommandType={}))[e.NotSet=-1]="NotSet",e[e.EvalStart=0]="EvalStart",e[e.EvalOutput=1]="EvalOutput",e[e.EvalEnd=2]="EvalEnd",e[e.Duplicate=3]="Duplicate",e[e.PopEvaluatedValue=4]="PopEvaluatedValue",e[e.PopFunction=5]="PopFunction",e[e.PopTunnel=6]="PopTunnel",e[e.BeginString=7]="BeginString",e[e.EndString=8]="EndString",e[e.NoOp=9]="NoOp",e[e.ChoiceCount=10]="ChoiceCount",e[e.Turns=11]="Turns",e[e.TurnsSince=12]="TurnsSince",e[e.Random=13]="Random",e[e.SeedRandom=14]="SeedRandom",e[e.VisitIndex=15]="VisitIndex",e[e.SequenceShuffleIndex=16]="SequenceShuffleIndex",e[e.StartThread=17]="StartThread",e[e.Done=18]="Done",e[e.End=19]="End",e[e.ListFromInt=20]="ListFromInt",e[e.ListRange=21]="ListRange",e[e.ListRandom=22]="ListRandom",e[e.ReadCount=23]="ReadCount",e[e.TOTAL_VALUES=24]="TOTAL_VALUES"}(et||(et={}));var nt=function(t){a(r,t);var e=d(r);function r(){var t;return n(this,r),(t=e.apply(this,arguments))._prototypeRuntimeConstantExpression=null,t.outputWhenComplete=!1,t.GenerateRuntimeObject=function(){var e=new tt;return e.AddContent(et.EvalStart()),t.GenerateIntoContainer(e),t.outputWhenComplete&&e.AddContent(et.EvalOutput()),e.AddContent(et.EvalEnd()),e},t.GenerateConstantIntoContainer=function(e){null===t._prototypeRuntimeConstantExpression&&(t._prototypeRuntimeConstantExpression=new tt,t.GenerateIntoContainer(t._prototypeRuntimeConstantExpression));var n,r=S(t._prototypeRuntimeConstantExpression.content);try{for(r.s();!(n=r.n()).done;){var i=n.value.Copy();i&&e.AddContent(i)}}catch(t){r.e(t)}finally{r.f()}},t.toString=function(){return"No string value in JavaScript."},t}return i(r,[{key:"typeName",get:function(){return"Expression"}},{key:"Equals",value:function(t){return!1}}]),r}(W),rt=function(t){a(r,t);var e=d(r);function r(){return n(this,r),e.apply(this,arguments)}return i(r)}(V),it=function(t){a(r,t);var e=d(r);function r(){var t;if(n(this,r),(t=e.call(this))._name=null,t._numberOfParameters=0,t._prototype=null,t._isPrototype=!1,t._operationFuncs=null,0===arguments.length)r.GenerateNativeFunctionsIfNecessary();else if(1===arguments.length){var i=arguments[0];r.GenerateNativeFunctionsIfNecessary(),t.name=i}else if(2===arguments.length){var a=arguments[0],o=arguments[1];t._isPrototype=!0,t.name=a,t.numberOfParameters=o}return t}return i(r,[{key:"name",get:function(){return null===this._name?L("NativeFunctionCall._name"):this._name},set:function(t){this._name=t,this._isPrototype||(null===r._nativeFunctions?L("NativeFunctionCall._nativeFunctions"):this._prototype=r._nativeFunctions.get(this._name)||null)}},{key:"numberOfParameters",get:function(){return this._prototype?this._prototype.numberOfParameters:this._numberOfParameters},set:function(t){this._numberOfParameters=t}},{key:"Call",value:function(t){if(this._prototype)return this._prototype.Call(t);if(this.numberOfParameters!=t.length)throw new Error("Unexpected number of parameters");var e,n=!1,r=S(t);try{for(r.s();!(e=r.n()).done;){var i=e.value;if(i instanceof rt)throw new G('Attempting to perform operation on a void value. Did you forget to "return" a value from a function you called here?');i instanceof Z&&(n=!0)}}catch(t){r.e(t)}finally{r.f()}if(2==t.length&&n)return this.CallBinaryListOperation(t);var a=this.CoerceValuesToSingleType(t),o=a[0].valueType;return o==U.Int||o==U.Float||o==U.String||o==U.DivertTarget||o==U.List?this.CallType(a):null}},{key:"CallType",value:function(t){var e=A(t[0],K),n=e.valueType,i=e,a=t.length;if(2==a||1==a){if(null===this._operationFuncs)return L("NativeFunctionCall._operationFuncs");var o=this._operationFuncs.get(n);if(!o){var s=U[n];throw new G("Cannot perform operation "+this.name+" on "+s)}if(2==a){var l=A(t[1],K),u=o;if(null===i.value||null===l.value)return L("NativeFunctionCall.Call BinaryOp values");var c=u(i.value,l.value);return K.Create(c)}var h=o;if(null===i.value)return L("NativeFunctionCall.Call UnaryOp value");var f=h(i.value);return this.name===r.Int?K.Create(f,U.Int):this.name===r.Float?K.Create(f,U.Float):K.Create(f,e.valueType)}throw new Error("Unexpected number of parameters to NativeFunctionCall: "+t.length)}},{key:"CallBinaryListOperation",value:function(t){if(("+"==this.name||"-"==this.name)&&t[0]instanceof Z&&t[1]instanceof J)return this.CallListIncrementOperation(t);var e=A(t[0],K),n=A(t[1],K);if(!("&&"!=this.name&&"||"!=this.name||e.valueType==U.List&&n.valueType==U.List)){if(null===this._operationFuncs)return L("NativeFunctionCall._operationFuncs");var r=this._operationFuncs.get(U.Int);if(null===r)return L("NativeFunctionCall.CallBinaryListOperation op");var i=function(t){if("boolean"==typeof t)return t;throw new Error("".concat(t," is not a boolean"))}(r(e.isTruthy?1:0,n.isTruthy?1:0));return new H(i)}if(e.valueType==U.List&&n.valueType==U.List)return this.CallType([e,n]);throw new G("Can not call use "+this.name+" operation on "+U[e.valueType]+" and "+U[n.valueType])}},{key:"CallListIncrementOperation",value:function(t){var e=A(t[0],Z),n=A(t[1],J),r=new B;if(null===e.value)return L("NativeFunctionCall.CallListIncrementOperation listVal.value");var i,a=S(e.value);try{for(a.s();!(i=a.n()).done;){var o=m(i.value,2),s=o[0],l=o[1],u=M.fromSerializedKey(s);if(null===this._operationFuncs)return L("NativeFunctionCall._operationFuncs");var c=this._operationFuncs.get(U.Int);if(null===n.value)return L("NativeFunctionCall.CallListIncrementOperation intVal.value");var h=c(l,n.value),f=null;if(null===e.value.origins)return L("NativeFunctionCall.CallListIncrementOperation listVal.value.origins");var d,v=S(e.value.origins);try{for(v.s();!(d=v.n()).done;){var p=d.value;if(p.name==u.originName){f=p;break}}}catch(t){v.e(t)}finally{v.f()}if(null!=f){var y=f.TryGetItemWithValue(h,M.Null);y.exists&&r.Add(y.result,h)}}}catch(t){a.e(t)}finally{a.f()}return new Z(r)}},{key:"CoerceValuesToSingleType",value:function(t){var e,n=U.Int,r=null,i=S(t);try{for(i.s();!(e=i.n()).done;){var a=A(e.value,K);a.valueType>n&&(n=a.valueType),a.valueType==U.List&&(r=_(a,Z))}}catch(t){i.e(t)}finally{i.f()}var o=[];if(U[n]==U[U.List]){var s,l=S(t);try{for(l.s();!(s=l.n()).done;){var u=A(s.value,K);if(u.valueType==U.List)o.push(u);else{if(u.valueType!=U.Int){var c=U[u.valueType];throw new G("Cannot mix Lists and "+c+" values in this operation")}var h=parseInt(u.valueObject);if(null===(r=A(r,Z)).value)return L("NativeFunctionCall.CoerceValuesToSingleType specialCaseList.value");var f=r.value.originOfMaxItem;if(null===f)return L("NativeFunctionCall.CoerceValuesToSingleType list");var d=f.TryGetItemWithValue(h,M.Null);if(!d.exists)throw new G("Could not find List item with the value "+h+" in "+f.name);var v=new Z(d.result,h);o.push(v)}}}catch(t){l.e(t)}finally{l.f()}}else{var p,m=S(t);try{for(m.s();!(p=m.n()).done;){var y=A(p.value,K).Cast(n);o.push(y)}}catch(t){m.e(t)}finally{m.f()}}return o}},{key:"AddOpFuncForType",value:function(t,e){null==this._operationFuncs&&(this._operationFuncs=new Map),this._operationFuncs.set(t,e)}},{key:"toString",value:function(){return'Native "'+this.name+'"'}}],[{key:"CallWithName",value:function(t){return new r(t)}},{key:"CallExistsWithName",value:function(t){return this.GenerateNativeFunctionsIfNecessary(),this._nativeFunctions.get(t)}},{key:"Identity",value:function(t){return t}},{key:"GenerateNativeFunctionsIfNecessary",value:function(){if(null==this._nativeFunctions){this._nativeFunctions=new Map,this.AddIntBinaryOp(this.Add,(function(t,e){return t+e})),this.AddIntBinaryOp(this.Subtract,(function(t,e){return t-e})),this.AddIntBinaryOp(this.Multiply,(function(t,e){return t*e})),this.AddIntBinaryOp(this.Divide,(function(t,e){return Math.floor(t/e)})),this.AddIntBinaryOp(this.Mod,(function(t,e){return t%e})),this.AddIntUnaryOp(this.Negate,(function(t){return-t})),this.AddIntBinaryOp(this.Equal,(function(t,e){return t==e})),this.AddIntBinaryOp(this.Greater,(function(t,e){return t>e})),this.AddIntBinaryOp(this.Less,(function(t,e){return t<e})),this.AddIntBinaryOp(this.GreaterThanOrEquals,(function(t,e){return t>=e})),this.AddIntBinaryOp(this.LessThanOrEquals,(function(t,e){return t<=e})),this.AddIntBinaryOp(this.NotEquals,(function(t,e){return t!=e})),this.AddIntUnaryOp(this.Not,(function(t){return 0==t})),this.AddIntBinaryOp(this.And,(function(t,e){return 0!=t&&0!=e})),this.AddIntBinaryOp(this.Or,(function(t,e){return 0!=t||0!=e})),this.AddIntBinaryOp(this.Max,(function(t,e){return Math.max(t,e)})),this.AddIntBinaryOp(this.Min,(function(t,e){return Math.min(t,e)})),this.AddIntBinaryOp(this.Pow,(function(t,e){return Math.pow(t,e)})),this.AddIntUnaryOp(this.Floor,r.Identity),this.AddIntUnaryOp(this.Ceiling,r.Identity),this.AddIntUnaryOp(this.Int,r.Identity),this.AddIntUnaryOp(this.Float,(function(t){return t})),this.AddFloatBinaryOp(this.Add,(function(t,e){return t+e})),this.AddFloatBinaryOp(this.Subtract,(function(t,e){return t-e})),this.AddFloatBinaryOp(this.Multiply,(function(t,e){return t*e})),this.AddFloatBinaryOp(this.Divide,(function(t,e){return t/e})),this.AddFloatBinaryOp(this.Mod,(function(t,e){return t%e})),this.AddFloatUnaryOp(this.Negate,(function(t){return-t})),this.AddFloatBinaryOp(this.Equal,(function(t,e){return t==e})),this.AddFloatBinaryOp(this.Greater,(function(t,e){return t>e})),this.AddFloatBinaryOp(this.Less,(function(t,e){return t<e})),this.AddFloatBinaryOp(this.GreaterThanOrEquals,(function(t,e){return t>=e})),this.AddFloatBinaryOp(this.LessThanOrEquals,(function(t,e){return t<=e})),this.AddFloatBinaryOp(this.NotEquals,(function(t,e){return t!=e})),this.AddFloatUnaryOp(this.Not,(function(t){return 0==t})),this.AddFloatBinaryOp(this.And,(function(t,e){return 0!=t&&0!=e})),this.AddFloatBinaryOp(this.Or,(function(t,e){return 0!=t||0!=e})),this.AddFloatBinaryOp(this.Max,(function(t,e){return Math.max(t,e)})),this.AddFloatBinaryOp(this.Min,(function(t,e){return Math.min(t,e)})),this.AddFloatBinaryOp(this.Pow,(function(t,e){return Math.pow(t,e)})),this.AddFloatUnaryOp(this.Floor,(function(t){return Math.floor(t)})),this.AddFloatUnaryOp(this.Ceiling,(function(t){return Math.ceil(t)})),this.AddFloatUnaryOp(this.Int,(function(t){return Math.floor(t)})),this.AddFloatUnaryOp(this.Float,r.Identity),this.AddStringBinaryOp(this.Add,(function(t,e){return t+e})),this.AddStringBinaryOp(this.Equal,(function(t,e){return t===e})),this.AddStringBinaryOp(this.NotEquals,(function(t,e){return!(t===e)})),this.AddStringBinaryOp(this.Has,(function(t,e){return t.includes(e)})),this.AddStringBinaryOp(this.Hasnt,(function(t,e){return!t.includes(e)})),this.AddListBinaryOp(this.Add,(function(t,e){return t.Union(e)})),this.AddListBinaryOp(this.Subtract,(function(t,e){return t.Without(e)})),this.AddListBinaryOp(this.Has,(function(t,e){return t.Contains(e)})),this.AddListBinaryOp(this.Hasnt,(function(t,e){return!t.Contains(e)})),this.AddListBinaryOp(this.Intersect,(function(t,e){return t.Intersect(e)})),this.AddListBinaryOp(this.Equal,(function(t,e){return t.Equals(e)})),this.AddListBinaryOp(this.Greater,(function(t,e){return t.GreaterThan(e)})),this.AddListBinaryOp(this.Less,(function(t,e){return t.LessThan(e)})),this.AddListBinaryOp(this.GreaterThanOrEquals,(function(t,e){return t.GreaterThanOrEquals(e)})),this.AddListBinaryOp(this.LessThanOrEquals,(function(t,e){return t.LessThanOrEquals(e)})),this.AddListBinaryOp(this.NotEquals,(function(t,e){return!t.Equals(e)})),this.AddListBinaryOp(this.And,(function(t,e){return t.Count>0&&e.Count>0})),this.AddListBinaryOp(this.Or,(function(t,e){return t.Count>0||e.Count>0})),this.AddListUnaryOp(this.Not,(function(t){return 0==t.Count?1:0})),this.AddListUnaryOp(this.Invert,(function(t){return t.inverse})),this.AddListUnaryOp(this.All,(function(t){return t.all})),this.AddListUnaryOp(this.ListMin,(function(t){return t.MinAsList()})),this.AddListUnaryOp(this.ListMax,(function(t){return t.MaxAsList()})),this.AddListUnaryOp(this.Count,(function(t){return t.Count})),this.AddListUnaryOp(this.ValueOfList,(function(t){return t.maxItem.Value}));this.AddOpToNativeFunc(this.Equal,2,U.DivertTarget,(function(t,e){return t.Equals(e)})),this.AddOpToNativeFunc(this.NotEquals,2,U.DivertTarget,(function(t,e){return!t.Equals(e)}))}}},{key:"AddOpToNativeFunc",value:function(t,e,n,i){if(null===this._nativeFunctions)return L("NativeFunctionCall._nativeFunctions");var a=this._nativeFunctions.get(t);a||(a=new r(t,e),this._nativeFunctions.set(t,a)),a.AddOpFuncForType(n,i)}},{key:"AddIntBinaryOp",value:function(t,e){this.AddOpToNativeFunc(t,2,U.Int,e)}},{key:"AddIntUnaryOp",value:function(t,e){this.AddOpToNativeFunc(t,1,U.Int,e)}},{key:"AddFloatBinaryOp",value:function(t,e){this.AddOpToNativeFunc(t,2,U.Float,e)}},{key:"AddFloatUnaryOp",value:function(t,e){this.AddOpToNativeFunc(t,1,U.Float,e)}},{key:"AddStringBinaryOp",value:function(t,e){this.AddOpToNativeFunc(t,2,U.String,e)}},{key:"AddListBinaryOp",value:function(t,e){this.AddOpToNativeFunc(t,2,U.List,e)}},{key:"AddListUnaryOp",value:function(t,e){this.AddOpToNativeFunc(t,1,U.List,e)}}]),r}(V);it.Add="+",it.Subtract="-",it.Divide="/",it.Multiply="*",it.Mod="%",it.Negate="_",it.Equal="==",it.Greater=">",it.Less="<",it.GreaterThanOrEquals=">=",it.LessThanOrEquals="<=",it.NotEquals="!=",it.Not="!",it.And="&&",it.Or="||",it.Min="MIN",it.Max="MAX",it.Pow="POW",it.Floor="FLOOR",it.Ceiling="CEILING",it.Int="INT",it.Float="FLOAT",it.Has="?",it.Hasnt="!?",it.Intersect="^",it.ListMin="LIST_MIN",it.ListMax="LIST_MAX",it.All="LIST_ALL",it.Count="LIST_COUNT",it.ValueOfList="LIST_VALUE",it.Invert="LIST_INVERT",it._nativeFunctions=null;var at=function(t){a(r,t);var e=d(r);function r(t,i){var a;if(n(this,r),(a=e.call(this)).isInt=function(){return"int"==a.subtype},a.isFloat=function(){return"float"==a.subtype},a.isBool=function(){return"bool"==a.subtype},a.GenerateIntoContainer=function(t){a.isInt()?t.AddContent(new J(a.value)):a.isFloat()?t.AddContent(new z(a.value)):a.isBool()&&t.AddContent(new H(a.value))},a.toString=function(){return String(a.value)},("number"!=typeof t||Number.isNaN(t))&&"boolean"!=typeof t)throw new Error("Unexpected object type in NumberExpression.");return a.value=t,a.subtype=i,a}return i(r,[{key:"typeName",get:function(){return"Number"}},{key:"Equals",value:function(t){var e=_(t,r);return!!e&&(e.subtype==this.subtype&&e.value==this.value)}}]),r}(nt),ot=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).op=i,a.GenerateIntoContainer=function(t){a.innerExpression.GenerateIntoContainer(t),t.AddContent(it.CallWithName(a.nativeNameForOp))},a.toString=function(){return a.nativeNameForOp+a.innerExpression},a.innerExpression=a.AddContent(t),a}return i(r,[{key:"nativeNameForOp",get:function(){return"-"===this.op?"_":"not"===this.op?"!":this.op}},{key:"typeName",get:function(){return"UnaryExpression"}}]),r}(nt);ot.WithInner=function(t,e){var n=_(t,at);if(n){if("-"===e){if(n.isInt())return new at(-n.value,"int");if(n.isFloat())return new at(-n.value,"float")}else if("!"==e||"not"==e){if(n.isInt())return new at(0==n.value,"bool");if(n.isFloat())return new at(0==n.value,"bool");if(n.isBool())return new at(!n.value,"bool")}throw new Error("Unexpected operation or number type")}return new ot(t,e)};var st=function(t){a(r,t);var e=d(r);function r(t,i,a){var o;return n(this,r),(o=e.call(this)).opName=a,o.GenerateIntoContainer=function(t){o.leftExpression.GenerateIntoContainer(t),o.rightExpression.GenerateIntoContainer(t),o.opName=o.NativeNameForOp(o.opName),t.AddContent(it.CallWithName(o.opName))},o.NativeNameForOp=function(t){return"and"===t?"&&":"or"===t?"||":"mod"===t?"%":"has"===t?"?":"hasnt"===t?"!?":t},o.toString=function(){return"(".concat(o.leftExpression," ").concat(o.opName," ").concat(o.rightExpression,")")},o.leftExpression=o.AddContent(t),o.rightExpression=o.AddContent(i),o.opName=a,o}return i(r,[{key:"typeName",get:function(){return"BinaryExpression"}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),"?"===this.NativeNameForOp(this.opName)){var e=_(this.leftExpression,ot);null===e||"not"!==e.op&&"!"!==e.op||this.Error("Using 'not' or '!' here negates '".concat(e.innerExpression,"' rather than the result of the '?' or 'has' operator. You need to add parentheses around the (A ? B) expression."))}}}]),r}(nt),lt=i((function t(e){var r=this;n(this,t),this.set=new Set,this.Add=function(t){return r.set.add(t)},this.AddRange=function(t,e){for(var n=t.charCodeAt(0);n<=e.charCodeAt(0);++n)r.Add(String.fromCharCode(n));return r},this.AddCharacters=function(t){if("string"==typeof t||Array.isArray(t)){var e,n=S(t);try{for(n.s();!(e=n.n()).done;){var i=e.value;r.Add(i)}}catch(t){n.e(t)}finally{n.f()}}else{var a,o=S(t.set);try{for(o.s();!(a=o.n()).done;){var s=a.value;r.Add(s)}}catch(t){o.e(t)}finally{o.f()}}return r},e&&this.AddCharacters(e)}));lt.FromRange=function(t,e){return(new lt).AddRange(t,e)};var ut=function(){function t(e,r){var i=this,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];if(n(this,t),this._start=e,this._end=r,this._correspondingCharSet=new lt,this._excludes=new Set,this.ToCharacterSet=function(){if(0===i._correspondingCharSet.set.size)for(var t=i.start.charCodeAt(0),e=String.fromCharCode(t);t<=i.end.charCodeAt(0);t+=1)i._excludes.has(e)||i._correspondingCharSet.AddCharacters(e);return i._correspondingCharSet},a instanceof lt)this._excludes=a.set;else{var o,s=S(a);try{for(s.s();!(o=s.n()).done;){var l=o.value;this._excludes.add(l)}}catch(t){s.e(t)}finally{s.f()}}}return i(t,[{key:"start",get:function(){return this._start}},{key:"end",get:function(){return this._end}}]),t}();ut.Define=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return new ut(t,e,n)};var ct,ht=function(t){a(r,t);var e=d(r);function r(){var t,i=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return n(this,r),(t=e.call(this))._pathOnChoice=null,t.hasCondition=!1,t.hasStartContent=!1,t.hasChoiceOnlyContent=!1,t.isInvisibleDefault=!1,t.onceOnly=!0,t.onceOnly=i,t}return i(r,[{key:"pathOnChoice",get:function(){if(null!=this._pathOnChoice&&this._pathOnChoice.isRelative){var t=this.choiceTarget;t&&(this._pathOnChoice=t.path)}return this._pathOnChoice},set:function(t){this._pathOnChoice=t}},{key:"choiceTarget",get:function(){return null===this._pathOnChoice?L("ChoicePoint._pathOnChoice"):this.ResolvePath(this._pathOnChoice).container}},{key:"pathStringOnChoice",get:function(){return null===this.pathOnChoice?L("ChoicePoint.pathOnChoice"):this.CompactPathString(this.pathOnChoice)},set:function(t){this.pathOnChoice=new R(t)}},{key:"flags",get:function(){var t=0;return this.hasCondition&&(t|=1),this.hasStartContent&&(t|=2),this.hasChoiceOnlyContent&&(t|=4),this.isInvisibleDefault&&(t|=8),this.onceOnly&&(t|=16),t},set:function(t){this.hasCondition=(1&t)>0,this.hasStartContent=(2&t)>0,this.hasChoiceOnlyContent=(4&t)>0,this.isInvisibleDefault=(8&t)>0,this.onceOnly=(16&t)>0}},{key:"toString",value:function(){return null===this.pathOnChoice?L("ChoicePoint.pathOnChoice"):"Choice: -> "+this.pathOnChoice.toString()}}]),r}(V);!function(t){t[t.Tunnel=0]="Tunnel",t[t.Function=1]="Function",t[t.FunctionEvaluationFromGame=2]="FunctionEvaluationFromGame"}(ct||(ct={}));var ft,dt=function(){function t(){n(this,t),this.container=null,this.index=-1,2===arguments.length&&(this.container=arguments[0],this.index=arguments[1])}return i(t,[{key:"Resolve",value:function(){return this.index<0?this.container:null==this.container?null:0==this.container.content.length?this.container:this.index>=this.container.content.length?null:this.container.content[this.index]}},{key:"isNull",get:function(){return null==this.container}},{key:"path",get:function(){return this.isNull?null:this.index>=0?this.container.path.PathByAppendingComponent(new R.Component(this.index)):this.container.path}},{key:"toString",value:function(){return this.container?"Ink Pointer -> "+this.container.path.toString()+" -- index "+this.index:"Ink Pointer (null)"}},{key:"copy",value:function(){return new t(this.container,this.index)}}],[{key:"StartOf",value:function(e){return new t(e,0)}},{key:"Null",get:function(){return new t(null,-1)}}]),t}(),vt=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this))._targetPath=null,i._targetPointer=dt.Null,i.variableDivertName=null,i.pushesToStack=!1,i.stackPushType=0,i.isExternal=!1,i.externalArgs=0,i.isConditional=!1,i.pushesToStack=!1,void 0!==t&&(i.pushesToStack=!0,i.stackPushType=t),i}return i(r,[{key:"targetPath",get:function(){if(null!=this._targetPath&&this._targetPath.isRelative){var t=this.targetPointer.Resolve();t&&(this._targetPath=t.path)}return this._targetPath},set:function(t){this._targetPath=t,this._targetPointer=dt.Null}},{key:"targetPointer",get:function(){if(this._targetPointer.isNull){var t=this.ResolvePath(this._targetPath).obj;if(null===this._targetPath)return L("this._targetPath");if(null===this._targetPath.lastComponent)return L("this._targetPath.lastComponent");if(this._targetPath.lastComponent.isIndex){if(null===t)return L("targetObj");this._targetPointer.container=t.parent instanceof tt?t.parent:null,this._targetPointer.index=this._targetPath.lastComponent.index}else this._targetPointer=dt.StartOf(t instanceof tt?t:null)}return this._targetPointer.copy()}},{key:"targetPathString",get:function(){return null==this.targetPath?null:this.CompactPathString(this.targetPath)},set:function(t){this.targetPath=null==t?null:new R(t)}},{key:"hasVariableTarget",get:function(){return null!=this.variableDivertName}},{key:"Equals",value:function(t){var e=t;return e instanceof r&&this.hasVariableTarget==e.hasVariableTarget&&(this.hasVariableTarget?this.variableDivertName==e.variableDivertName:null===this.targetPath?L("this.targetPath"):this.targetPath.Equals(e.targetPath))}},{key:"toString",value:function(){if(this.hasVariableTarget)return"Divert(variable: "+this.variableDivertName+")";if(null==this.targetPath)return"Divert(null)";var t=new j,e=this.targetPath.toString();return t.Append("Divert"),this.isConditional&&t.Append("?"),this.pushesToStack&&(this.stackPushType==ct.Function?t.Append(" function"):t.Append(" tunnel")),t.Append(" -> "),t.Append(this.targetPathString),t.Append(" ("),t.Append(e),t.Append(")"),t.toString()}}]),r}(V);!function(t){t[t.Knot=0]="Knot",t[t.List=1]="List",t[t.ListItem=2]="ListItem",t[t.Var=3]="Var",t[t.SubFlowAndWeave=4]="SubFlowAndWeave",t[t.Arg=5]="Arg",t[t.Temp=6]="Temp"}(ft||(ft={}));var pt=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).variableName=t||null,a.isNewDeclaration=!!i,a.isGlobal=!1,a}return i(r,[{key:"toString",value:function(){return"VarAssign to "+this.variableName}}]),r}(V),mt=function(t){a(r,t);var e=d(r);function r(t,i,a){var o;return n(this,r),(o=e.call(this))._condition=null,o._innerContentContainer=null,o._outerContainer=null,o._runtimeChoice=null,o._returnToR1=null,o._returnToR2=null,o._r1Label=null,o._r2Label=null,o._divertToStartContentOuter=null,o._divertToStartContentInner=null,o._startContentRuntimeContainer=null,o.isInvisibleDefault=!1,o.hasWeaveStyleInlineBrackets=!1,o.GenerateRuntimeObject=function(){if(o._outerContainer=new tt,o._runtimeChoice=new ht(o.onceOnly),o._runtimeChoice.isInvisibleDefault=o.isInvisibleDefault,(o.startContent||o.choiceOnlyContent||o.condition)&&o._outerContainer.AddContent(et.EvalStart()),o.startContent){o._returnToR1=new X,o._outerContainer.AddContent(o._returnToR1);var t=new pt("$r",!0);o._outerContainer.AddContent(t),o._outerContainer.AddContent(et.BeginString()),o._divertToStartContentOuter=new vt,o._outerContainer.AddContent(o._divertToStartContentOuter),o._startContentRuntimeContainer=o.startContent.GenerateRuntimeObject(),o._startContentRuntimeContainer.name="s";var e=new vt;e.variableDivertName="$r",o._startContentRuntimeContainer.AddContent(e),o._outerContainer.AddToNamedContentOnly(o._startContentRuntimeContainer),o._r1Label=new tt,o._r1Label.name="$r1",o._outerContainer.AddContent(o._r1Label),o._outerContainer.AddContent(et.EndString()),o._runtimeChoice.hasStartContent=!0}if(o.choiceOnlyContent){o._outerContainer.AddContent(et.BeginString());var n=o.choiceOnlyContent.GenerateRuntimeObject();o._outerContainer.AddContentsOfContainer(n),o._outerContainer.AddContent(et.EndString()),o._runtimeChoice.hasChoiceOnlyContent=!0}if(o.condition&&(o.condition.GenerateIntoContainer(o._outerContainer),o._runtimeChoice.hasCondition=!0),(o.startContent||o.choiceOnlyContent||o.condition)&&o._outerContainer.AddContent(et.EvalEnd()),o._outerContainer.AddContent(o._runtimeChoice),o._innerContentContainer=new tt,o.startContent){o._returnToR2=new X,o._innerContentContainer.AddContent(et.EvalStart()),o._innerContentContainer.AddContent(o._returnToR2),o._innerContentContainer.AddContent(et.EvalEnd());var r=new pt("$r",!0);o._innerContentContainer.AddContent(r),o._divertToStartContentInner=new vt,o._innerContentContainer.AddContent(o._divertToStartContentInner),o._r2Label=new tt,o._r2Label.name="$r2",o._innerContentContainer.AddContent(o._r2Label)}if(o.innerContent){var i=o.innerContent.GenerateRuntimeObject();o._innerContentContainer.AddContentsOfContainer(i)}return o.story.countAllVisits&&(o._innerContentContainer.visitsShouldBeCounted=!0),o._innerContentContainer.countingAtStartOnly=!0,o._outerContainer},o.toString=function(){return null!==o.choiceOnlyContent?"* ".concat(o.startContent,"[").concat(o.choiceOnlyContent,"]..."):"* ".concat(o.startContent,"...")},o.startContent=t,o.choiceOnlyContent=i,o.innerContent=a,o.indentationDepth=1,t&&o.AddContent(o.startContent),i&&o.AddContent(o.choiceOnlyContent),a&&o.AddContent(o.innerContent),o.onceOnly=!0,o}return i(r,[{key:"runtimeChoice",get:function(){if(!this._runtimeChoice)throw new Error;return this._runtimeChoice}},{key:"name",get:function(){var t;return(null===(t=this.identifier)||void 0===t?void 0:t.name)||null}},{key:"condition",get:function(){return this._condition},set:function(t){this._condition=t,t&&this.AddContent(t)}},{key:"runtimeContainer",get:function(){return this._innerContentContainer}},{key:"innerContentContainer",get:function(){return this._innerContentContainer}},{key:"containerForCounting",get:function(){return this._innerContentContainer}},{key:"runtimePath",get:function(){if(!this.innerContentContainer||!this.innerContentContainer.path)throw new Error;return this.innerContentContainer.path}},{key:"typeName",get:function(){return"Choice"}},{key:"ResolveReferences",value:function(t){var e;if(this._innerContentContainer&&(this.runtimeChoice.pathOnChoice=this._innerContentContainer.path,this.onceOnly&&(this._innerContentContainer.visitsShouldBeCounted=!0)),this._returnToR1){if(!this._r1Label)throw new Error;this._returnToR1.targetPath=this._r1Label.path}if(this._returnToR2){if(!this._r2Label)throw new Error;this._returnToR2.targetPath=this._r2Label.path}if(this._divertToStartContentOuter){if(!this._startContentRuntimeContainer)throw new Error;this._divertToStartContentOuter.targetPath=this._startContentRuntimeContainer.path}if(this._divertToStartContentInner){if(!this._startContentRuntimeContainer)throw new Error;this._divertToStartContentInner.targetPath=this._startContentRuntimeContainer.path}p(o(r.prototype),"ResolveReferences",this).call(this,t),this.identifier&&((null===(e=this.identifier)||void 0===e?void 0:e.name)||"").length>0&&t.CheckForNamingCollisions(this,this.identifier,ft.SubFlowAndWeave)}}]),r}(W),yt=i((function t(){var e=this;n(this,t),this.characterIndex=0,this.characterInLineIndex=0,this.lineIndex=0,this.reportedErrorInScope=!1,this.uniqueId=0,this.customFlags=0,this.CopyFrom=function(n){t._uniqueIdCounter++,e.uniqueId=t._uniqueIdCounter,e.characterIndex=n.characterIndex,e.characterInLineIndex=n.characterInLineIndex,e.lineIndex=n.lineIndex,e.customFlags=n.customFlags,e.reportedErrorInScope=!1},this.SquashFrom=function(t){e.characterIndex=t.characterIndex,e.characterInLineIndex=t.characterInLineIndex,e.lineIndex=t.lineIndex,e.reportedErrorInScope=t.reportedErrorInScope}}));yt._uniqueIdCounter=1e3;var gt=function(){function t(){var e=this;n(this,t),this._stack=[],this._numElements=0,this.StringParserState=function(){e._stack=new Array(200);for(var t=0;t<200;++t)e._stack[t]=new yt;e._numElements=1},this.Push=function(){if(e._numElements>=e._stack.length&&e._numElements>0)throw new Error("Stack overflow in parser state.");var t=e._stack[e._numElements-1],n=e._stack[e._numElements];return e._numElements++,n.CopyFrom(t),n.uniqueId},this.Pop=function(t){if(1==e._numElements)throw new Error("Attempting to remove final stack element is illegal! Mismatched Begin/Succceed/Fail?");if(e.currentElement.uniqueId!=t)throw new Error("Mismatched rule IDs while Poping - do you have mismatched Begin/Succeed/Fail?");e._numElements-=1},this.Peek=function(t){if(e.currentElement.uniqueId!=t)throw new Error("Mismatched rule IDs while Peeking - do you have mismatched Begin/Succeed/Fail?");return e._stack[e._numElements-1]},this.PeekPenultimate=function(){return e._numElements>=2?e._stack[e._numElements-2]:null},this.Squash=function(){if(e._numElements<2)throw new Error("Attempting to remove final stack element is illegal! Mismatched Begin/Succceed/Fail?");var t=e._stack[e._numElements-2],n=e._stack[e._numElements-1];t.SquashFrom(n),e._numElements-=1},this.NoteErrorReported=function(){var t,n=S(e._stack);try{for(n.s();!(t=n.n()).done;){t.value.reportedErrorInScope=!0}}catch(t){n.e(t)}finally{n.f()}};for(var r=0;r<200;r++)this._stack[r]=new yt;this._numElements=1}return i(t,[{key:"currentElement",get:function(){return this._stack[this._numElements-1]}},{key:"lineIndex",get:function(){return this.currentElement.lineIndex},set:function(t){this.currentElement.lineIndex=t}},{key:"characterIndex",get:function(){return this.currentElement.characterIndex},set:function(t){this.currentElement.characterIndex=t}},{key:"characterInLineIndex",get:function(){return this.currentElement.characterInLineIndex},set:function(t){this.currentElement.characterInLineIndex=t}},{key:"customFlags",get:function(){return this.currentElement.customFlags},set:function(t){this.currentElement.customFlags=t}},{key:"errorReportedAlreadyInScope",get:function(){return this.currentElement.reportedErrorInScope}},{key:"stackHeight",get:function(){return this._numElements}}]),t}(),Ct=Symbol("ParseSuccessStruct"),St=function(){function t(e){var r=this;n(this,t),this.ParseRule=null,this.errorHandler=null,this.hadError=!1,this.BeginRule=function(){return r.state.Push()},this.FailRule=function(t){return r.state.Pop(t),null},this.CancelRule=function(t){r.state.Pop(t)},this.SucceedRule=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,i=r.state.Peek(e),a=r.state.PeekPenultimate();r.RuleDidSucceed&&r.RuleDidSucceed(n,a,i),r.state.Squash();var o=n;return null===o&&(o=t.ParseSuccess),o},this.Expect=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=r.ParseObject(t);if(null===i){var a;null===e&&(e=t.name);var o=r.LineRemainder();a=null===o||0===o.length?"end of line":"'".concat(o,"'"),r.Error("Expected ".concat(e," but saw ").concat(a)),null!==n&&(i=n())}return i},this.Error=function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];r.ErrorOnLine(t,r.lineIndex+1,e)},this.ErrorWithParsedObject=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];r.ErrorOnLine(t,e.debugMetadata?e.debugMetadata.startLineNumber:-1,n)},this.ErrorOnLine=function(t,e,n){if(!r.state.errorReportedAlreadyInScope){var i=n?"Warning":"Error";if(!r.errorHandler)throw new Error("".concat(i," on line ").concat(e,": ").concat(t));r.errorHandler(t,r.index,e-1,n),r.state.NoteErrorReported()}n||(r.hadError=!0)},this.Warning=function(t){return r.Error(t,!0)},this.LineRemainder=function(){return r.Peek((function(){return r.ParseUntilCharactersFromString("\n\r")}))},this.SetFlag=function(t,e){e?r.state.customFlags|=t:r.state.customFlags&=~t},this.GetFlag=function(t){return Boolean(r.state.customFlags&t)},this.ParseObject=function(t){var e=r.BeginRule(),n=r.state.stackHeight,i=t();if(n!==r.state.stackHeight)throw new Error("Mismatched Begin/Fail/Succeed rules");return null===i?r.FailRule(e):(r.SucceedRule(e,i),i)},this.Parse=function(t){var e=r.BeginRule(),n=t();return null===n?(r.FailRule(e),null):(r.SucceedRule(e,n),n)},this.OneOf=function(t){var e,n=S(t);try{for(n.s();!(e=n.n()).done;){var i=e.value,a=r.ParseObject(i);if(null!==a)return a}}catch(t){n.e(t)}finally{n.f()}return null},this.OneOrMore=function(t){var e=[],n=null;do{null!==(n=r.ParseObject(t))&&e.push(n)}while(null!==n);return e.length>0?e:null},this.Optional=function(e){return function(){var n=r.ParseObject(e);return null===n?t.ParseSuccess:n}},this.Exclude=function(e){return function(){return r.ParseObject(e)&&t.ParseSuccess}},this.OptionalExclude=function(e){return function(){return r.ParseObject(e),t.ParseSuccess}},this.String=function(t){return function(){return r.ParseString(t)}},this.TryAddResultToList=function(e,n){var r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(e!==t.ParseSuccess){if(r&&Array.isArray(e)){var i=e;if(null!==i){var a,o=S(i);try{for(o.s();!(a=o.n()).done;){var s=a.value;n.push(s)}}catch(t){o.e(t)}finally{o.f()}return}}n.push(e)}},this.Interleave=function(e,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,a=!(arguments.length>3&&void 0!==arguments[3])||arguments[3],o=r.BeginRule(),s=[],l=r.ParseObject(e);if(null===l)return r.FailRule(o);r.TryAddResultToList(l,s,a);var u=null,c=null;do{if(null!==i&&null!==r.Peek(i))break;if(null===(u=r.ParseObject(n)))break;if(r.TryAddResultToList(u,s,a),c=null,null!==u){if(null===(c=r.ParseObject(e)))break;r.TryAddResultToList(c,s,a)}}while((null!==u||null!==c)&&(u!==t.ParseSuccess||c!=t.ParseSuccess)&&r.remainingLength>0);return 0===s.length?r.FailRule(o):r.SucceedRule(o,s)},this.ParseString=function(t){if(t.length>r.remainingLength)return null;for(var e=r.BeginRule(),n=r.index,i=r.characterInLineIndex,a=r.lineIndex,o=!0,s=0;s<t.length;s+=1){var l=t[s];if(r._chars[n]!==l){o=!1;break}"\n"===l&&(a++,i=-1),n++,i++}return r.index=n,r.characterInLineIndex=i,r.lineIndex=a,o?r.SucceedRule(e,t):r.FailRule(e)},this.ParseSingleCharacter=function(){if(r.remainingLength>0){var t=r._chars[r.index];return"\n"===t&&(r.lineIndex+=1,r.characterInLineIndex=-1),r.index+=1,r.characterInLineIndex+=1,t}return"0"},this.ParseUntilCharactersFromString=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return r.ParseCharactersFromString(t,!1,e)},this.ParseUntilCharactersFromCharSet=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return r.ParseCharactersFromCharSet(t,!1,e)},this.ParseCharactersFromString=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1,i=new lt(t);return"number"==typeof e?r.ParseCharactersFromCharSet(i,!0,e):r.ParseCharactersFromCharSet(i,e,n)},this.ParseCharactersFromCharSet=function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:-1;-1===n&&(n=Number.MAX_SAFE_INTEGER);for(var i=r.index,a=r.index,o=r.characterInLineIndex,s=r.lineIndex,l=0;a<r._chars.length&&t.set.has(r._chars[a])===e&&l<n;)"\n"===r._chars[a]&&(s+=1,o=-1),a+=1,o+=1,l+=1;r.index=a,r.characterInLineIndex=o,r.lineIndex=s;var u=r.index;return u>i?r._chars.slice(i,r.index).join(""):null},this.Peek=function(t){var e=r.BeginRule(),n=t();return r.CancelRule(e),n},this.ParseInt=function(){var e=r.index,n=r.characterInLineIndex,i=null!==r.ParseString("-");r.ParseCharactersFromString(" \t");var a,o=r.ParseCharactersFromCharSet(t.numbersCharacterSet);return null===o?(r.index=e,r.characterInLineIndex=n,null):Number.isNaN(Number(o))?(r.Error("Failed to read integer value: "+o+". Perhaps it's out of the range of acceptable numbers ink supports? ("+Number.MIN_SAFE_INTEGER+" to "+Number.MAX_SAFE_INTEGER+")"),null):(a=Number(o),i?-a:a)},this.ParseFloat=function(){var e=r.index,n=r.characterInLineIndex,i=r.ParseInt();if(null!==i&&null!==r.ParseString(".")){var a=r.ParseCharactersFromCharSet(t.numbersCharacterSet);return Number("".concat(i,".").concat(a))}return r.index=e,r.characterInLineIndex=n,null},this.ParseNewline=function(){var t=r.BeginRule();return r.ParseString("\r"),null===r.ParseString("\n")?r.FailRule(t):r.SucceedRule(t,"\n")};var i=this.PreProcessInputString(e);this.state=new gt,this._chars=e?i.split(""):[],this.inputString=i}return i(t,[{key:"currentCharacter",get:function(){return this.index>=0&&this.remainingLength>0?this._chars[this.index]:"0"}},{key:"PreProcessInputString",value:function(t){return t}},{key:"endOfInput",get:function(){return this.index>=this._chars.length}},{key:"remainingString",get:function(){return this._chars.slice(this.index,this.index+this.remainingLength).join("")}},{key:"remainingLength",get:function(){return this._chars.length-this.index}},{key:"lineIndex",get:function(){return this.state.lineIndex},set:function(t){this.state.lineIndex=t}},{key:"characterInLineIndex",get:function(){return this.state.characterInLineIndex},set:function(t){this.state.characterInLineIndex=t}},{key:"index",get:function(){return this.state.characterIndex},set:function(t){this.state.characterIndex=t}},{key:"ParseUntil",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=this.BeginRule(),i=new lt;null!==e&&(i.set=new Set([].concat(y(i.set.values()),y(e.set.values())))),null!==n&&(i.set=new Set([].concat(y(i.set.values()),y(n.set.values()))));for(var a="";;){var o=this.ParseUntilCharactersFromCharSet(i);if(o&&(a+=o),null!==this.Peek(t))break;if(this.endOfInput)break;var s=this.currentCharacter;if(null===e||!e.set.has(s))break;a+=s,"\n"===s&&(this.lineIndex+=1,this.characterInLineIndex=-1),this.index+=1,this.characterInLineIndex+=1}return a.length>0?this.SucceedRule(r,String(a)):this.FailRule(r)}}]),t}();St.ParseSuccess=Ct,St.numbersCharacterSet=new lt("0123456789");var bt,wt=function(t){a(r,t);var e=d(r);function r(){var t;return n(this,r),(t=e.apply(this,arguments))._commentOrNewlineStartCharacter=new lt("/\r\n"),t._commentBlockEndCharacter=new lt("*"),t._newlineCharacters=new lt("\n\r"),t.Process=function(){var e=t.Interleave(t.Optional(t.CommentsAndNewlines),t.Optional(t.MainInk));return null!==e?e.join(""):""},t.MainInk=function(){return t.ParseUntil(t.CommentsAndNewlines,t._commentOrNewlineStartCharacter,null)},t.CommentsAndNewlines=function(){var e=t.Interleave(t.Optional(t.ParseNewline),t.Optional(t.ParseSingleComment));return null!==e?e.join(""):null},t.ParseSingleComment=function(){return t.OneOf([t.EndOfLineComment,t.BlockComment])},t.EndOfLineComment=function(){return null===t.ParseString("//")?null:(t.ParseUntilCharactersFromCharSet(t._newlineCharacters),"")},t.BlockComment=function(){if(null===t.ParseString("/*"))return null;var e=t.lineIndex,n=t.ParseUntil(t.String("*/"),t._commentBlockEndCharacter,null);return t.endOfInput||t.ParseString("*/"),null!=n?"\n".repeat(t.lineIndex-e):null},t}return i(r,[{key:"PreProcessInputString",value:function(t){return t}}]),r}(St),kt=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).initialCondition=t,a.branches=i,a._reJoinTarget=null,a.GenerateRuntimeObject=function(){var t=new tt;a.initialCondition&&t.AddContent(a.initialCondition.runtimeObject);var e,n=S(a.branches);try{for(n.s();!(e=n.n()).done;){var r=e.value.runtimeObject;t.AddContent(r)}}catch(t){n.e(t)}finally{n.f()}return null===a.initialCondition||null===a.branches[0].ownExpression||a.branches[a.branches.length-1].isElse||t.AddContent(et.PopEvaluatedValue()),a._reJoinTarget=et.NoOp(),t.AddContent(a._reJoinTarget),t},a.initialCondition&&a.AddContent(a.initialCondition),null!==a.branches&&a.AddContent(a.branches),a}return i(r,[{key:"typeName",get:function(){return"Conditional"}},{key:"ResolveReferences",value:function(t){var e,n=this._reJoinTarget.path,i=S(this.branches);try{for(i.s();!(e=i.n()).done;){var a=e.value;if(!a.returnDivert)throw new Error;a.returnDivert.targetPath=n}}catch(t){i.e(t)}finally{i.f()}p(o(r.prototype),"ResolveReferences",this).call(this,t)}}]),r}(W),Et=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).text=t,i.GenerateRuntimeObject=function(){return new $(i.text)},i.toString=function(){return i.text},i}return i(r,[{key:"typeName",get:function(){return"Text"}}]),r}(W),_t=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this))._expression=null,a.GenerateRuntimeObject=function(){return null},a.constantIdentifier=t,i&&(a._expression=a.AddContent(i)),a}return i(r,[{key:"constantName",get:function(){var t;return null===(t=this.constantIdentifier)||void 0===t?void 0:t.name}},{key:"expression",get:function(){if(!this._expression)throw new Error;return this._expression}},{key:"typeName",get:function(){return"CONST"}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t),t.CheckForNamingCollisions(this,this.constantIdentifier,ft.Var)}}]),r}(W);!function(t){t[t.Story=0]="Story",t[t.Knot=1]="Knot",t[t.Stitch=2]="Stitch",t[t.WeavePoint=3]="WeavePoint"}(bt||(bt={}));var At=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).indentationDepth=i,a.GenerateRuntimeObject=function(){var t=new tt;if(t.name=a.name,a.story.countAllVisits&&(t.visitsShouldBeCounted=!0),t.countingAtStartOnly=!0,a.content){var e,n=S(a.content);try{for(n.s();!(e=n.n()).done;){var r=e.value;t.AddContent(r.runtimeObject)}}catch(t){n.e(t)}finally{n.f()}}return t},a.toString=function(){var t,e;return"- ".concat((null===(t=a.identifier)||void 0===t?void 0:t.name)?"("+(null===(e=a.identifier)||void 0===e?void 0:e.name)+")":"gather")},t&&(a.identifier=t),a}return i(r,[{key:"name",get:function(){var t;return(null===(t=this.identifier)||void 0===t?void 0:t.name)||null}},{key:"runtimeContainer",get:function(){return this.runtimeObject}},{key:"typeName",get:function(){return"Gather"}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t),this.identifier&&(this.identifier.name||"").length>0&&t.CheckForNamingCollisions(this,this.identifier,ft.SubFlowAndWeave)}}]),r}(W),Tt=function(){function t(e,r){var i=this;n(this,t),this._dotSeparatedComponents=null,this.toString=function(){return null===i.components||0===i.components.length?i.baseTargetLevel===bt.WeavePoint?"-> <next gather point>":"<invalid Path>":"-> ".concat(i.dotSeparatedComponents)},this.ResolveFromContext=function(t){if(null==i.components||0==i.components.length)return null;var e=i.ResolveBaseTarget(t);return null===e?null:i.components.length>1?i.ResolveTailComponents(e):e},this.ResolveBaseTarget=function(t){for(var e=i.firstComponent,n=t;n;){var r=n===t,a=i.GetChildFromContext(n,e,null,r);if(a)return a;n=n.parent}return null},this.ResolveTailComponents=function(t){var e=t;if(!i.components)return null;for(var n=1;n<i.components.length;++n){var r=i.components[n].name,a=void 0,o=_(e,Ot);if(a=null!==o?o.flowLevel+1:bt.WeavePoint,null===(e=i.GetChildFromContext(e,r,a)))break}return e},this.GetChildFromContext=function(t,e,n){var r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],i=null===n,a=_(t,zt);if(e&&null!==a&&(i||n===bt.WeavePoint))return a.WeavePointNamed(e);var o=_(t,Ot);if(e&&null!==o){var s=r||o.flowLevel===bt.Knot;return o.ContentWithNameAtLevel(e,n,s)}return null},Object.values(bt).includes(e)?(this._baseTargetLevel=e,this.components=r||[]):Array.isArray(e)?(this._baseTargetLevel=null,this.components=e||[]):(this._baseTargetLevel=null,this.components=[e])}return i(t,[{key:"baseTargetLevel",get:function(){return this.baseLevelIsAmbiguous?bt.Story:this._baseTargetLevel}},{key:"baseLevelIsAmbiguous",get:function(){return!this._baseTargetLevel}},{key:"firstComponent",get:function(){return null!=this.components&&this.components.length?this.components[0].name:null}},{key:"numberOfComponents",get:function(){return this.components?this.components.length:0}},{key:"dotSeparatedComponents",get:function(){return null==this._dotSeparatedComponents&&(this._dotSeparatedComponents=(this.components?this.components:[]).map((function(t){return t.name})).filter(O).join(".")),this._dotSeparatedComponents}},{key:"typeName",get:function(){return"Path"}}]),t}(),Pt=function(t){a(r,t);var e=d(r);function r(){var t,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return n(this,r),(t=e.call(this)).returnedExpression=null,t.GenerateRuntimeObject=function(){var e=new tt;return t.returnedExpression?e.AddContent(t.returnedExpression.runtimeObject):(e.AddContent(et.EvalStart()),e.AddContent(new rt),e.AddContent(et.EvalEnd())),e.AddContent(et.PopFunction()),e},i&&(t.returnedExpression=t.AddContent(i)),t}return i(r,[{key:"typeName",get:function(){return"ReturnType"}}]),r}(W);function xt(t){for(var e=t.parent;e;){if(e.hasOwnProperty("iamFlowbase")&&e.iamFlowbase())return e;e=e.parent}return null}var Nt=function(){function t(e){var r=this;n(this,t),this.debugMetadata=null,this.toString=function(){return r.name||"undefined identifer"},this.name=e}return i(t,[{key:"typeName",get:function(){return"Identifier"}}],[{key:"Done",value:function(){return new t("DONE")}}]),t}(),Ot=function(t){a(r,t);var e=d(r);function r(t){var i,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,s=arguments.length>3&&void 0!==arguments[3]&&arguments[3],l=arguments.length>4&&void 0!==arguments[4]&&arguments[4];return n(this,r),(i=e.call(this)).isFunction=s,i._rootWeave=null,i._subFlowsByName=new Map,i._startingSubFlowDivert=null,i._startingSubFlowRuntime=null,i._firstChildFlow=null,i.variableDeclarations=new Map,i.identifier=null,i.args=null,i.iamFlowbase=function(){return!0},i.SplitWeaveAndSubFlowContent=function(t,e){var n,a,o=[],s=[];i._subFlowsByName=new Map;var l,u=S(t);try{for(u.s();!(l=u.n()).done;){var c=l.value,h=_(c,r);h?(null===i._firstChildFlow&&(i._firstChildFlow=h),s.push(c),(null===(n=h.identifier)||void 0===n?void 0:n.name)&&i._subFlowsByName.set(null===(a=h.identifier)||void 0===a?void 0:a.name,h)):o.push(c)}}catch(t){u.e(t)}finally{u.f()}e&&o.push(new At(null,1),new jt(new Tt(Nt.Done())));var f=[];return o.length>0&&(i._rootWeave=new zt(o,0),f.push(i._rootWeave)),s.length>0&&f.push.apply(f,s),f},i.ResolveVariableWithName=function(t,e){var n,r={},a=null===e?h(i):xt(e);if(a){if(null!==a.args){var o,s=S(a.args);try{for(s.s();!(o=s.n()).done;){if((null===(n=o.value.identifier)||void 0===n?void 0:n.name)===t)return r.found=!0,r.isArgument=!0,r.ownerFlow=a,r}}catch(t){s.e(t)}finally{s.f()}}if(a!==i.story&&a.variableDeclarations.has(t))return r.found=!0,r.ownerFlow=a,r.isTemporary=!0,r}return i.story.variableDeclarations.has(t)?(r.found=!0,r.ownerFlow=i.story,r.isGlobal=!0,r):(r.found=!1,r)},i.AddNewVariableDeclaration=function(t){var e=t.variableName;if(i.variableDeclarations.has(e)){var n=i.variableDeclarations.get(e),r="";return n.debugMetadata&&(r=" (".concat(n.debugMetadata,")")),void i.Error("found declaration variable '".concat(e,"' that was already declared").concat(r),t,!1)}i.variableDeclarations.set(t.variableName,t)},i.ResolveWeavePointNaming=function(){i._rootWeave&&i._rootWeave.ResolveWeavePointNaming();var t,e=S(i._subFlowsByName);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,2)[1];n.hasOwnProperty("ResolveWeavePointNaming")&&n.ResolveWeavePointNaming()}}catch(t){e.e(t)}finally{e.f()}},i.GenerateRuntimeObject=function(){var t,e=null;i.isFunction?i.CheckForDisallowedFunctionFlowControl():i.flowLevel!==bt.Knot&&i.flowLevel!==bt.Stitch||null!==(e=i.Find(Pt)())&&i.Error("Return statements can only be used in knots that are declared as functions: == function ".concat(i.identifier," =="),e);var n=new tt;n.name=null===(t=i.identifier)||void 0===t?void 0:t.name,i.story.countAllVisits&&(n.visitsShouldBeCounted=!0),i.GenerateArgumentVariableAssignments(n);for(var a=0;null!==i.content&&a<i.content.length;){var o=i.content[a];if(o instanceof r){var s=o,l=s.runtimeObject;0!==a||s.hasParameters||i.flowLevel!==bt.Knot||(i._startingSubFlowDivert=new vt,n.AddContent(i._startingSubFlowDivert),i._startingSubFlowRuntime=l);var u=l,c=n.namedContent.get(u.name)||null;if(c){var h="".concat(i.GetType()," already contains flow named '").concat(u.name,"' (at ").concat(c.debugMetadata,")");i.Error(h,s)}n.AddToNamedContentOnly(u)}else o&&n.AddContent(o.runtimeObject);a+=1}return i.flowLevel===bt.Story||i.isFunction||null===i._rootWeave||null!==e||i._rootWeave.ValidateTermination(i.WarningInTermination),n},i.GenerateArgumentVariableAssignments=function(t){var e;if(null!==i.args&&0!==i.args.length)for(var n=i.args.length-1;n>=0;--n){var r=(null===(e=i.args[n].identifier)||void 0===e?void 0:e.name)||null,a=new pt(r,!0);t.AddContent(a)}},i.ContentWithNameAtLevel=function(t){var e,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if((n===i.flowLevel||null===n)&&t===(null===(e=i.identifier)||void 0===e?void 0:e.name))return h(i);if(n===bt.WeavePoint||null===n){var a=null;if(i._rootWeave&&(a=i._rootWeave.WeavePointNamed(t)))return a;if(n===bt.WeavePoint)return r?i.DeepSearchForAnyLevelContent(t):null}if(null!==n&&n<i.flowLevel)return null;var o=i._subFlowsByName.get(t)||null;return!o||null!==n&&n!==o.flowLevel?r?i.DeepSearchForAnyLevelContent(t):null:o},i.DeepSearchForAnyLevelContent=function(t){var e=i.ContentWithNameAtLevel(t,bt.WeavePoint,!1);if(e)return e;var n,r=S(i._subFlowsByName);try{for(r.s();!(n=r.n()).done;){var a=m(n.value,2)[1].ContentWithNameAtLevel(t,null,!0);if(a)return a}}catch(t){r.e(t)}finally{r.f()}return null},i.CheckForDisallowedFunctionFlowControl=function(){i.flowLevel!==bt.Knot&&i.Error("Functions cannot be stitches - i.e. they should be defined as '== function myFunc ==' rather than internal to another knot.");var t,e=S(i._subFlowsByName);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,2),r=n[0],a=n[1];i.Error("Functions may not contain stitches, but saw '".concat(r,"' within the function '").concat(i.identifier,"'"),a)}}catch(t){e.e(t)}finally{e.f()}if(!i._rootWeave)throw new Error;var o,s=S(i._rootWeave.FindAll(jt)());try{for(s.s();!(o=s.n()).done;){var l=o.value;l.isFunctionCall||l.parent instanceof Vt||i.Error("Functions may not contain diverts, but saw '".concat(l,"'"),l)}}catch(t){s.e(t)}finally{s.f()}var u,c=S(i._rootWeave.FindAll(mt)());try{for(c.s();!(u=c.n()).done;){var h=u.value;i.Error("Functions may not contain choices, but saw '".concat(h,"'"),h)}}catch(t){c.e(t)}finally{c.f()}},i.WarningInTermination=function(t){var e="Apparent loose end exists where the flow runs out. Do you need a '-> DONE' statement, choice or divert?";t.parent===i._rootWeave&&i._firstChildFlow&&(e="".concat(e," Note that if you intend to enter '").concat(i._firstChildFlow.identifier,"' next, you need to divert to it explicitly."));var n=_(t,jt);n&&n.isTunnel&&(e+=" When final tunnel to '".concat(n.target," ->' returns it won't have anywhere to go.")),i.Warning(e,t)},i.toString=function(){return"".concat(i.typeName," '").concat(i.identifier,"'")},i.identifier=t,i.args=o,null===a&&(a=[]),i.PreProcessTopLevelObjects(a),a=i.SplitWeaveAndSubFlowContent(a,"Story"==i.GetType()&&!l),i.AddContent(a),i}return i(r,[{key:"hasParameters",get:function(){return null!==this.args&&this.args.length>0}},{key:"subFlowsByName",get:function(){return this._subFlowsByName}},{key:"typeName",get:function(){return this.isFunction?"Function":String(this.flowLevel)}},{key:"name",get:function(){var t;return(null===(t=this.identifier)||void 0===t?void 0:t.name)||null}},{key:"PreProcessTopLevelObjects",value:function(t){}},{key:"ResolveReferences",value:function(t){var e,n;if(this._startingSubFlowDivert){if(!this._startingSubFlowRuntime)throw new Error;this._startingSubFlowDivert.targetPath=this._startingSubFlowRuntime.path}if(p(o(r.prototype),"ResolveReferences",this).call(this,t),null!==this.args){var i,a=S(this.args);try{for(a.s();!(i=a.n()).done;){var s=i.value;t.CheckForNamingCollisions(this,s.identifier,ft.Arg,"argument")}}catch(t){a.e(t)}finally{a.f()}for(var l=0;l<this.args.length;l+=1)for(var u=l+1;u<this.args.length;u+=1)(null===(e=this.args[l].identifier)||void 0===e?void 0:e.name)==(null===(n=this.args[u].identifier)||void 0===n?void 0:n.name)&&this.Error("Multiple arguments with the same name: '".concat(this.args[l].identifier,"'"))}if(this.flowLevel!==bt.Story){var c=this.flowLevel===bt.Knot?ft.Knot:ft.SubFlowAndWeave;t.CheckForNamingCollisions(this,this.identifier,c)}}}]),r}(W),It=function(t){a(r,t);var e=d(r);function r(t){var i;n(this,r),(i=e.call(this)).dontFlatten=!1,i.TrimTrailingWhitespace=function(){for(var t=i.content.length-1;t>=0;--t){var e=_(i.content[t],Et);if(null===e)break;if(e.text=e.text.replace(new RegExp(/[ \t]/g),""),0!==e.text.length)break;i.content.splice(t,1)}},i.GenerateRuntimeObject=function(){var t=new tt;if(null!==i.content){var e,n=S(i.content);try{for(n.s();!(e=n.n()).done;){var r=e.value.runtimeObject;r&&t.AddContent(r)}}catch(t){n.e(t)}finally{n.f()}}return i.dontFlatten&&i.story.DontFlattenContainer(t),t},i.toString=function(){return"ContentList(".concat(i.content.join(", "),")")},t&&i.AddContent(t);for(var a=arguments.length,o=new Array(a>1?a-1:0),s=1;s<a;s++)o[s-1]=arguments[s];return o&&i.AddContent(o),i}return i(r,[{key:"runtimeContainer",get:function(){return this.runtimeObject}},{key:"typeName",get:function(){return"ContentList"}}]),r}(W),Wt=function(t){a(r,t);var e=d(r);function r(){var t,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return n(this,r),(t=e.call(this)).pathForCount=null,t.name=i,t}return i(r,[{key:"containerForCount",get:function(){return null===this.pathForCount?null:this.ResolvePath(this.pathForCount).container}},{key:"pathStringForCount",get:function(){return null===this.pathForCount?null:this.CompactPathString(this.pathForCount)},set:function(t){this.pathForCount=null===t?null:new R(t)}},{key:"toString",value:function(){return null!=this.name?"var("+this.name+")":"read_count("+this.pathStringForCount+")"}}]),r}(V),Ft=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).pathIdentifiers=t,i._runtimeVarRef=null,i.isConstantReference=!1,i.isListItemReference=!1,i.GenerateIntoContainer=function(t){var e=i.story.constants.get(i.name);if(e)return e.GenerateConstantIntoContainer(t),void(i.isConstantReference=!0);if(i._runtimeVarRef=new Wt(i.name),1===i.path.length||2===i.path.length){var n="",r="";1===i.path.length?n=i.path[0]:(r=i.path[0],n=i.path[1]),i.story.ResolveListItem(r,n,h(i))&&(i.isListItemReference=!0)}t.AddContent(i._runtimeVarRef)},i.toString=function(){return"{".concat(i.path.join("."),"}")},i}return i(r,[{key:"name",get:function(){return this.path.join(".")}},{key:"path",get:function(){return this.pathIdentifiers.map((function(t){return t.name})).filter(O)}},{key:"identifier",get:function(){if(!this.pathIdentifiers||0==this.pathIdentifiers.length)return null;var t=this.path.join(".");return new Nt(t)}},{key:"runtimeVarRef",get:function(){return this._runtimeVarRef}},{key:"typeName",get:function(){return"ref"}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),!this.isConstantReference&&!this.isListItemReference){var e=new Tt(this.pathIdentifiers),n=e.ResolveFromContext(this);if(n){if(!n.containerForCounting)throw new Error;if(n.containerForCounting.visitsShouldBeCounted=!0,null===this._runtimeVarRef)return;this._runtimeVarRef.pathForCount=n.runtimePath,this._runtimeVarRef.name=null;var i=_(n,Ot);i&&i.isFunction&&(this.parent instanceof zt||this.parent instanceof It||this.parent instanceof Ot)&&this.Warning("'".concat(i.identifier,"' being used as read count rather than being called as function. Perhaps you intended to write ").concat(i.identifier,"()"))}else{if(this.path.length>1){var a="Could not find target for read count: ".concat(e);return this.path.length<=2&&(a+=", or couldn't find list item with the name ".concat(this.path.join(","))),void this.Error(a)}t.ResolveVariableWithName(this.name,this).found||this.Error("Unresolved variable: ".concat(this.name),this)}}}}]),r}(nt),Rt=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this))._divertTargetToCount=null,a._variableReferenceToCount=null,a.shouldPopReturnedValue=!1,a.GenerateIntoContainer=function(t){var e=a.story.ResolveList(a.name),n=!1;if(a.isChoiceCount)a.args.length>0&&a.Error("The CHOICE_COUNT() function shouldn't take any arguments"),t.AddContent(et.ChoiceCount());else if(a.isTurns)a.args.length>0&&a.Error("The TURNS() function shouldn't take any arguments"),t.AddContent(et.Turns());else if(a.isTurnsSince||a.isReadCount){var r=_(a.args[0],Vt),i=_(a.args[0],Ft);if(1!==a.args.length||null===r&&null===i)return void a.Error("The ".concat(a.name,"() function should take one argument: a divert target to the target knot, stitch, gather or choice you want to check. e.g. TURNS_SINCE(-> myKnot)"));r?(a._divertTargetToCount=r,a.AddContent(a._divertTargetToCount),a._divertTargetToCount.GenerateIntoContainer(t)):i&&(a._variableReferenceToCount=i,a.AddContent(a._variableReferenceToCount),a._variableReferenceToCount.GenerateIntoContainer(t)),a.isTurnsSince?t.AddContent(et.TurnsSince()):t.AddContent(et.ReadCount())}else if(a.isRandom){2!==a.args.length&&a.Error("RANDOM should take 2 parameters: a minimum and a maximum integer");for(var o=0;o<a.args.length;o+=1){var s=_(a.args[o],at);if(s&&!s.isInt()){var l=0===o?"minimum":"maximum";a.Error("RANDOM's ".concat(l," parameter should be an integer"))}a.args[o].GenerateIntoContainer(t)}t.AddContent(et.Random())}else if(a.isSeedRandom){1!==a.args.length&&a.Error("SEED_RANDOM should take 1 parameter - an integer seed");var u=_(a.args[0],at);u&&!u.isInt()&&a.Error("SEED_RANDOM's parameter should be an integer seed"),a.args[0].GenerateIntoContainer(t),t.AddContent(et.SeedRandom())}else if(a.isListRange){3!==a.args.length&&a.Error("LIST_RANGE should take 3 parameters - a list, a min and a max");for(var c=0;c<a.args.length;c+=1)a.args[c].GenerateIntoContainer(t);t.AddContent(et.ListRange())}else if(a.isListRandom)1!==a.args.length&&a.Error("LIST_RANDOM should take 1 parameter - a list"),a.args[0].GenerateIntoContainer(t),t.AddContent(et.ListRandom());else if(it.CallExistsWithName(a.name)){var h=it.CallWithName(a.name);if(h.numberOfParameters!==a.args.length){var f="".concat(name," should take ").concat(h.numberOfParameters," parameter");h.numberOfParameters>1&&(f+="s"),a.Error(f)}for(var d=0;d<a.args.length;d+=1)a.args[d].GenerateIntoContainer(t);t.AddContent(it.CallWithName(a.name))}else if(null!==e)if(a.args.length>1&&a.Error("Can currently only construct a list from one integer (or an empty list from a given list definition)"),1===a.args.length)t.AddContent(new $(a.name)),a.args[0].GenerateIntoContainer(t),t.AddContent(et.ListFromInt());else{var v=new B;v.SetInitialOriginName(a.name),t.AddContent(new Z(v))}else t.AddContent(a._proxyDivert.runtimeObject),n=!0;n||a.content.splice(a.content.indexOf(a._proxyDivert),1),a.shouldPopReturnedValue&&t.AddContent(et.PopEvaluatedValue())},a.toString=function(){var t=a.args.join(", ");return"".concat(a.name,"(").concat(t,")")},a._proxyDivert=new jt(new Tt(t),i),a._proxyDivert.isFunctionCall=!0,a.AddContent(a._proxyDivert),a}return i(r,[{key:"proxyDivert",get:function(){return this._proxyDivert}},{key:"name",get:function(){return this._proxyDivert.target.firstComponent||""}},{key:"args",get:function(){return this._proxyDivert.args}},{key:"runtimeDivert",get:function(){return this._proxyDivert.runtimeDivert}},{key:"isChoiceCount",get:function(){return"CHOICE_COUNT"===this.name}},{key:"isTurns",get:function(){return"TURNS"===this.name}},{key:"isTurnsSince",get:function(){return"TURNS_SINCE"===this.name}},{key:"isRandom",get:function(){return"RANDOM"===this.name}},{key:"isSeedRandom",get:function(){return"SEED_RANDOM"===this.name}},{key:"isListRange",get:function(){return"LIST_RANGE"===this.name}},{key:"isListRandom",get:function(){return"LIST_RANDOM"===this.name}},{key:"isReadCount",get:function(){return"READ_COUNT"===this.name}},{key:"typeName",get:function(){return"FunctionCall"}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),!this.content.includes(this._proxyDivert)&&null!==this.args){var e,n=S(this.args);try{for(n.s();!(e=n.n()).done;){e.value.ResolveReferences(t)}}catch(t){n.e(t)}finally{n.f()}}if(this._divertTargetToCount){var i=this._divertTargetToCount.divert,a=null!=i.runtimeDivert.variableDivertName;if(a)return void this.Error("When getting the TURNS_SINCE() of a variable target, remove the '->' - i.e. it should just be TURNS_SINCE(".concat(i.runtimeDivert.variableDivertName,")"));var s=i.targetContent;if(null===s)a||this.Error("Failed to find target for TURNS_SINCE: '".concat(i.target,"'"));else{if(!s.containerForCounting)throw new Error;s.containerForCounting.turnIndexShouldBeCounted=!0}}else if(this._variableReferenceToCount){var l=this._variableReferenceToCount.runtimeVarRef;if(!l)throw new Error;null!==l.pathForCount&&this.Error("Should be '".concat(name,"'(-> '").concat(this._variableReferenceToCount.name,"). Usage without the '->' only makes sense for variable targets."))}}}]),r}(nt);Rt.IsBuiltIn=function(t){return!!it.CallExistsWithName(t)||("CHOICE_COUNT"===t||"TURNS_SINCE"===t||"TURNS"===t||"RANDOM"===t||"SEED_RANDOM"===t||"LIST_VALUE"===t||"LIST_RANDOM"===t||"READ_COUNT"===t)};var Dt,Lt=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).GenerateIntoContainer=function(t){var e,n=!0,r=S(i.subExpressions);try{for(r.s();!(e=r.n()).done;){e.value.GenerateIntoContainer(t),n||t.AddContent(it.CallWithName("&&")),n=!1}}catch(t){r.e(t)}finally{r.f()}},i.AddContent(t),i}return i(r,[{key:"subExpressions",get:function(){return this.content}},{key:"typeName",get:function(){return"MultipleConditionExpression"}}]),r}(nt),Vt=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this))._runtimeDivert=null,i._runtimeDivertTargetValue=null,i.GenerateIntoContainer=function(t){i.divert.GenerateRuntimeObject(),i._runtimeDivert=i.divert.runtimeDivert,i._runtimeDivertTargetValue=new X,t.AddContent(i.runtimeDivertTargetValue)},i.Equals=function(t){var e=_(t,r);return!!(e&&i.divert.target&&e.divert.target)&&i.divert.target.dotSeparatedComponents===e.divert.target.dotSeparatedComponents},i.divert=i.AddContent(t),i}return i(r,[{key:"runtimeDivert",get:function(){if(!this._runtimeDivert)throw new Error;return this._runtimeDivert}},{key:"runtimeDivertTargetValue",get:function(){if(!this._runtimeDivertTargetValue)throw new Error;return this._runtimeDivertTargetValue}},{key:"typeName",get:function(){return"DivertTarget"}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),this.divert.isDone||this.divert.isEnd)this.Error("Can't use -> DONE or -> END as variable divert targets",this);else{for(var e=this;e&&e instanceof nt;){var n=!1,i=!1,a=e.parent;if(a instanceof st){var s=a;"=="!==s.opName&&"!="!==s.opName?n=!0:(s.leftExpression instanceof r||s.leftExpression instanceof Ft)&&(s.rightExpression instanceof r||s.rightExpression instanceof Ft)||(n=!0),i=!0}else if(a instanceof Rt){var l=a;l.isTurnsSince||l.isReadCount||(n=!0),i=!0}else(a instanceof nt||a instanceof Lt||a instanceof mt&&a.condition===e||a instanceof kt||a instanceof $t)&&(n=!0,i=!0);if(n&&this.Error("Can't use a divert target like that. Did you intend to call '".concat(this.divert.target,"' as a function: likeThis(), or check the read count: likeThis, with no arrows?"),this),i)break;e=a}if(this.runtimeDivert.hasVariableTarget){if(!this.divert.target)throw new Error;this.Error("Since '".concat(this.divert.target.dotSeparatedComponents,"' is a variable, it shouldn't be preceded by '->' here."))}this.runtimeDivert.targetPath&&(this.runtimeDivertTargetValue.targetPath=this.runtimeDivert.targetPath);var u=this.divert.targetContent;if(null!==u){var c=u.containerForCounting;if(null!==c){var h=_(this.parent,Rt);h&&h.isTurnsSince||(c.visitsShouldBeCounted=!0),c.turnIndexShouldBeCounted=!0}var f=_(u,Ot);if(null!=f&&null!==f.args){var d,v=S(f.args);try{for(v.s();!(d=v.n()).done;){var m=d.value;m.isByReference&&this.Error("Can't store a divert target to a knot or function that has by-reference arguments ('".concat(f.identifier,"' has 'ref ").concat(m.identifier,"')."))}}catch(t){v.e(t)}finally{v.f()}}}}}}]),r}(nt),jt=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).args=[],a.target=null,a.targetContent=null,a._runtimeDivert=null,a.isFunctionCall=!1,a.isEmpty=!1,a.isTunnel=!1,a.isThread=!1,a.GenerateRuntimeObject=function(){if(a.isEnd)return et.End();if(a.isDone)return et.Done();a.runtimeDivert=new vt,a.ResolveTargetContent(),a.CheckArgumentValidity();var t=null!==a.args&&a.args.length>0;if(t||a.isFunctionCall||a.isTunnel||a.isThread){var e=new tt;if(t){a.isFunctionCall||e.AddContent(et.EvalStart());var n=null;a.targetContent&&(n=a.targetContent.args);for(var r=0;r<a.args.length;++r){var i=a.args[r],o=null;if(n&&r<n.length&&(o=n[r]),o&&o.isByReference){var s=_(i,Ft);if(!s){a.Error("Expected variable name to pass by reference to 'ref ".concat(o.identifier,"' but saw ").concat(i));break}var l=new Tt(s.pathIdentifiers);if(l.ResolveFromContext(h(a))){a.Error("can't pass a read count by reference. '".concat(l.dotSeparatedComponents,"' is a knot/stitch/label, but '").concat(a.target.dotSeparatedComponents,"' requires the name of a VAR to be passed."));break}var u=new Y(s.name);e.AddContent(u)}else i.GenerateIntoContainer(e)}a.isFunctionCall||e.AddContent(et.EvalEnd())}return a.isThread?e.AddContent(et.StartThread()):(a.isFunctionCall||a.isTunnel)&&(a.runtimeDivert.pushesToStack=!0,a.runtimeDivert.stackPushType=a.isFunctionCall?ct.Function:ct.Tunnel),e.AddContent(a.runtimeDivert),e}return a.runtimeDivert},a.PathAsVariableName=function(){return a.target?a.target.firstComponent:null},a.ResolveTargetContent=function(){if(!a.isEmpty&&!a.isEnd&&null===a.targetContent){var t=a.PathAsVariableName();if(null!==t){var e=_(xt(h(a)),Ot);if(e){var n=e.ResolveVariableWithName(t,h(a));if(n.found){if(n.isArgument&&n.ownerFlow&&n.ownerFlow.args){var r=n.ownerFlow.args.find((function(e){var n;return(null===(n=e.identifier)||void 0===n?void 0:n.name)==t}));r&&!r.isDivertTarget&&a.Error("Since '".concat(r.identifier,"' is used as a variable divert target (on ").concat(a.debugMetadata,"), it should be marked as: -> ").concat(r.identifier),n.ownerFlow)}return void(a.runtimeDivert.variableDivertName=t)}}}if(!a.target)throw new Error;a.targetContent=a.target.ResolveFromContext(h(a))}},a.CheckArgumentValidity=function(){if(!a.isEmpty){var t=0;if(null!==a.args&&a.args.length>0&&(t=a.args.length),null!==a.targetContent){var e=_(a.targetContent,Ot);if(0!==t||null!==e&&e.hasParameters)if(null===e&&t>0)a.Error("target needs to be a knot or stitch in order to pass arguments");else if(null!==e&&(null===e.args||!e.args&&t>0))a.Error("target (".concat(e.name,") doesn't take parameters"));else if(a.parent instanceof Vt)t>0&&a.Error("can't store arguments in a divert target variable");else{var n,r=e.args.length;if(r!==t)return n=0===t?"but there weren't any passed to it":t<r?"but only got ".concat(t):"but got ".concat(t),void a.Error("to '".concat(e.identifier,"' requires ").concat(r," arguments, ").concat(n));for(var i=0;i<r;++i){var o=e.args[i],s=a.args[i];if(o.isDivertTarget){var l=_(s,Ft);if(s instanceof Vt||null!==l){if(l){var u=new Tt(l.pathIdentifiers);u.ResolveFromContext(l)&&a.Error("Passing read count of '".concat(u.dotSeparatedComponents,"' instead of a divert target. You probably meant '").concat(u,"'"))}}else a.Error("Target '".concat(e.identifier,"' expects a divert target for the parameter named -> ").concat(o.identifier," but saw ").concat(s),s)}}null!==e||a.Error("Can't call as a function or with arguments unless it's a knot or stitch")}}}},a.CheckExternalArgumentValidity=function(t){var e=a.target?a.target.firstComponent:null,n=t.externals.get(e);if(!n)throw new Error("external not found");var r=n.argumentNames.length,i=0;a.args&&(i=a.args.length),i!==r&&a.Error("incorrect number of arguments sent to external function '".concat(e,"'. Expected ").concat(r," but got ").concat(i))},a.toString=function(){var t="";return null===a.target?"-> <empty divert>":(t+=a.target.toString(),a.isTunnel&&(t+=" ->"),a.isFunctionCall&&(t+=" ()"),t)},t&&(a.target=t),i&&(a.args=i,a.AddContent(i)),a}return i(r,[{key:"runtimeDivert",get:function(){if(!this._runtimeDivert)throw new Error;return this._runtimeDivert},set:function(t){this._runtimeDivert=t}},{key:"isEnd",get:function(){return Boolean(this.target&&"END"===this.target.dotSeparatedComponents)}},{key:"isDone",get:function(){return Boolean(this.target&&"DONE"===this.target.dotSeparatedComponents)}},{key:"typeName",get:function(){return"Divert"}},{key:"ResolveReferences",value:function(t){if(!(this.isEmpty||this.isEnd||this.isDone)){if(!this.runtimeDivert)throw new Error;this.targetContent&&(this.runtimeDivert.targetPath=this.targetContent.runtimePath),p(o(r.prototype),"ResolveReferences",this).call(this,t);var e=_(this.targetContent,Ot);e&&(!e.isFunction&&this.isFunctionCall?p(o(r.prototype),"Error",this).call(this,"".concat(e.identifier," hasn't been marked as a function, but it's being called as one. Do you need to delcare the knot as '== function ").concat(e.identifier," =='?")):!e.isFunction||this.isFunctionCall||this.parent instanceof Vt||p(o(r.prototype),"Error",this).call(this,e.identifier+" can't be diverted to. It can only be called as a function since it's been marked as such: '"+e.identifier+"(...)'"));var n=null!==this.targetContent,i=!1,a=!1;if(!this.target)throw new Error;if(1===this.target.numberOfComponents){if(!this.target.firstComponent)throw new Error;if(i=Rt.IsBuiltIn(this.target.firstComponent),a=t.IsExternal(this.target.firstComponent),i||a)return this.isFunctionCall||p(o(r.prototype),"Error",this).call(this,"".concat(this.target.firstComponent," must be called as a function: ~ ").concat(this.target.firstComponent,"()")),void(a&&(this.runtimeDivert.isExternal=!0,null!==this.args&&(this.runtimeDivert.externalArgs=this.args.length),this.runtimeDivert.pushesToStack=!1,this.runtimeDivert.targetPath=new R(this.target.firstComponent),this.CheckExternalArgumentValidity(t)))}null==this.runtimeDivert.variableDivertName&&(n||i||a||this.Error("target not found: '".concat(this.target,"'")))}}},{key:"Error",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];e!==this&&e?p(o(r.prototype),"Error",this).call(this,t,e):this.isFunctionCall?p(o(r.prototype),"Error",this).call(this,"Function call ".concat(t),e,n):p(o(r.prototype),"Error",this).call(this,"Divert ".concat(t),e,n)}}]),r}(W),Mt=i((function t(e,r){n(this,t),this.divert=e,this.targetRuntimeObj=r})),Bt=i((function t(e,r){n(this,t),this.divert=e,this.targetContent=r}));!function(t){t[t.Stopping=1]="Stopping",t[t.Cycle=2]="Cycle",t[t.Shuffle=4]="Shuffle",t[t.Once=8]="Once"}(Dt||(Dt={}));var Gt,qt=function(t){a(r,t);var e=d(r);function r(t,i){var a;n(this,r),(a=e.call(this)).sequenceType=i,a._sequenceDivertsToResolve=[],a.GenerateRuntimeObject=function(){var t=new tt;t.visitsShouldBeCounted=!0,t.countingAtStartOnly=!0,a._sequenceDivertsToResolve=[],t.AddContent(et.EvalStart()),t.AddContent(et.VisitIndex());var e=(a.sequenceType&Dt.Once)>0,n=(a.sequenceType&Dt.Cycle)>0,r=(a.sequenceType&Dt.Stopping)>0,i=(a.sequenceType&Dt.Shuffle)>0,o=a.sequenceElements.length;if(e&&(o+=1),r||e?(t.AddContent(new J(o-1)),t.AddContent(it.CallWithName("MIN"))):n&&(t.AddContent(new J(a.sequenceElements.length)),t.AddContent(it.CallWithName("%"))),i){var s=et.NoOp();if(e||r){var l=r?a.sequenceElements.length-1:a.sequenceElements.length;t.AddContent(et.Duplicate()),t.AddContent(new J(l)),t.AddContent(it.CallWithName("=="));var u=new vt;u.isConditional=!0,t.AddContent(u),a.AddDivertToResolve(u,s)}var c=a.sequenceElements.length;r&&(c-=1),t.AddContent(new J(c)),t.AddContent(et.SequenceShuffleIndex()),(e||r)&&t.AddContent(s)}t.AddContent(et.EvalEnd());for(var h=et.NoOp(),f=0;f<o;f+=1){t.AddContent(et.EvalStart()),t.AddContent(et.Duplicate()),t.AddContent(new J(f)),t.AddContent(it.CallWithName("==")),t.AddContent(et.EvalEnd());var d=new vt;d.isConditional=!0,t.AddContent(d);var v=void 0;if(f<a.sequenceElements.length)v=a.sequenceElements[f].runtimeObject;else v=new tt;v.name="s".concat(f),v.InsertContent(et.PopEvaluatedValue(),0);var p=new vt;v.AddContent(p),t.AddToNamedContentOnly(v),a.AddDivertToResolve(d,v),a.AddDivertToResolve(p,h)}return t.AddContent(h),t},a.AddDivertToResolve=function(t,e){a._sequenceDivertsToResolve.push(new Bt(t,e))},a.sequenceType=i,a.sequenceElements=[];var o,s=S(t);try{for(s.s();!(o=s.n()).done;){var l=o.value,u=l.content,c=null;c=null===u||0===u.length?l:new zt(u),a.sequenceElements.push(c),a.AddContent(c)}}catch(t){s.e(t)}finally{s.f()}return a}return i(r,[{key:"typeName",get:function(){return"Sequence"}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t);var e,n=S(this._sequenceDivertsToResolve);try{for(n.s();!(e=n.n()).done;){var i=e.value;i.divert.targetPath=i.targetContent.path}}catch(t){n.e(t)}finally{n.f()}}}]),r}(W),Ut=function(t){a(r,t);var e=d(r);function r(){var t;return n(this,r),(t=e.apply(this,arguments))._overrideDivertTarget=null,t._divertAfter=null,t.GenerateRuntimeObject=function(){var e=new tt;if(e.AddContent(et.EvalStart()),t.divertAfter){var n=t.divertAfter.GenerateRuntimeObject();if(n){var r=t.divertAfter.args;if(null!==r&&r.length>0){for(var i=-1,a=-1,o=0;o<n.content.length;o+=1){var s=n.content[o];s&&(-1==i&&s.commandType===et.CommandType.EvalStart?i=o:s.commandType===et.CommandType.EvalEnd&&(a=o))}for(var l=i+1;l<a;l+=1){n.content[l].parent=null,e.AddContent(n.content[l])}}}t._overrideDivertTarget=new X,e.AddContent(t._overrideDivertTarget)}else e.AddContent(new rt);return e.AddContent(et.EvalEnd()),e.AddContent(et.PopTunnel()),e},t.toString=function(){return" -> ".concat(t._divertAfter)},t}return i(r,[{key:"divertAfter",get:function(){return this._divertAfter},set:function(t){this._divertAfter=t,this._divertAfter&&this.AddContent(this._divertAfter)}},{key:"typeName",get:function(){return"TunnelOnwards"}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t),this.divertAfter&&this.divertAfter.targetContent&&(this._overrideDivertTarget.targetPath=this.divertAfter.targetContent.runtimePath)}}]),r}(W),Kt=function(){function t(e,r){n(this,t),this._name=e||"",this._items=null,this._itemNameToValues=r||new Map}return i(t,[{key:"name",get:function(){return this._name}},{key:"items",get:function(){if(null==this._items){this._items=new Map;var t,e=S(this._itemNameToValues);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,2),r=n[0],i=n[1],a=new M(this.name,r);this._items.set(a.serialized(),i)}}catch(t){e.e(t)}finally{e.f()}}return this._items}},{key:"ValueForItem",value:function(t){if(!t.itemName)return 0;var e=this._itemNameToValues.get(t.itemName);return void 0!==e?e:0}},{key:"ContainsItem",value:function(t){return!!t.itemName&&(t.originName==this.name&&this._itemNameToValues.has(t.itemName))}},{key:"ContainsItemWithName",value:function(t){return this._itemNameToValues.has(t)}},{key:"TryGetItemWithValue",value:function(t,e){var n,r=S(this._itemNameToValues);try{for(r.s();!(n=r.n()).done;){var i=m(n.value,2),a=i[0];if(i[1]==t)return{result:new M(this.name,a),exists:!0}}}catch(t){r.e(t)}finally{r.f()}return{result:M.Null,exists:!1}}},{key:"TryGetValueForItem",value:function(t,e){if(!t.itemName)return{result:0,exists:!1};var n=this._itemNameToValues.get(t.itemName);return n?{result:n,exists:!0}:{result:0,exists:!1}}}]),t}(),Ht=function(t){a(r,t);var e=d(r);function r(t){var i;n(this,r),(i=e.call(this)).itemDefinitions=t,i.identifier=null,i.variableAssignment=null,i._elementsByName=null,i.ItemNamed=function(t){if(null===i._elementsByName){i._elementsByName=new Map;var e,n=S(i.itemDefinitions);try{for(n.s();!(e=n.n()).done;){var r=e.value;i._elementsByName.set(r.name,r)}}catch(t){n.e(t)}finally{n.f()}}return i._elementsByName.get(t)||null},i.GenerateRuntimeObject=function(){var t,e,n,r=new B,a=S(i.itemDefinitions);try{for(a.s();!(n=a.n()).done;){var o=n.value;if(o.inInitialList){var s=new M((null===(t=i.identifier)||void 0===t?void 0:t.name)||null,o.name||null);r.Add(s,o.seriesValue)}}}catch(t){a.e(t)}finally{a.f()}return r.SetInitialOriginName((null===(e=i.identifier)||void 0===e?void 0:e.name)||""),new Z(r)};var a,o=1,s=S(i.itemDefinitions);try{for(s.s();!(a=s.n()).done;){var l=a.value;null!==l.explicitValue&&(o=l.explicitValue),l.seriesValue=o,o+=1}}catch(t){s.e(t)}finally{s.f()}return i.AddContent(t),i}return i(r,[{key:"typeName",get:function(){return"ListDefinition"}},{key:"runtimeListDefinition",get:function(){var t,e,n=new Map,r=S(this.itemDefinitions);try{for(r.s();!(e=r.n()).done;){var i=e.value;n.has(i.name)?this.Error("List '".concat(this.identifier,"' contains duplicate items called '").concat(i.name,"'")):n.set(i.name,i.seriesValue)}}catch(t){r.e(t)}finally{r.f()}return new Kt((null===(t=this.identifier)||void 0===t?void 0:t.name)||"",n)}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t),t.CheckForNamingCollisions(this,this.identifier,ft.List)}}]),r}(W),Jt=function(t){a(r,t);var e=d(r);function r(t){var i,a=t.assignedExpression,o=t.isGlobalDeclaration,s=t.isTemporaryNewDeclaration,l=t.listDef,u=t.variableIdentifier;return n(this,r),(i=e.call(this))._runtimeAssignment=null,i.expression=null,i.listDefinition=null,i.GenerateRuntimeObject=function(){var t=null;if(i.isGlobalDeclaration?t=i.story:i.isNewTemporaryDeclaration&&(t=xt(h(i))),t&&t.AddNewVariableDeclaration(h(i)),i.isGlobalDeclaration)return null;var e=new tt;return i.expression?e.AddContent(i.expression.runtimeObject):i.listDefinition&&e.AddContent(i.listDefinition.runtimeObject),i._runtimeAssignment=new pt(i.variableName,i.isNewTemporaryDeclaration),e.AddContent(i._runtimeAssignment),e},i.toString=function(){return"".concat(i.isGlobalDeclaration?"VAR":i.isNewTemporaryDeclaration?"~ temp":""," ").concat(i.variableName)},i.variableIdentifier=u,i.isGlobalDeclaration=Boolean(o),i.isNewTemporaryDeclaration=Boolean(s),l instanceof Ht?(i.listDefinition=i.AddContent(l),i.listDefinition.variableAssignment=h(i),i.isGlobalDeclaration=!0):a&&(i.expression=i.AddContent(a)),i}return i(r,[{key:"variableName",get:function(){return this.variableIdentifier.name}},{key:"typeName",get:function(){return this.isNewTemporaryDeclaration?"temp":this.isGlobalDeclaration?null!==this.listDefinition?"LIST":"VAR":"variable assignment"}},{key:"isDeclaration",get:function(){return this.isGlobalDeclaration||this.isNewTemporaryDeclaration}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),this.isDeclaration&&null===this.listDefinition&&t.CheckForNamingCollisions(this,this.variableIdentifier,this.isGlobalDeclaration?ft.Var:ft.Temp),this.isGlobalDeclaration){var e=_(this.expression,Ft);!e||e.isConstantReference||e.isListItemReference||this.Error("global variable assignments cannot refer to other variables, only literal values, constants and list items")}if(!this.isNewTemporaryDeclaration){var n=t.ResolveVariableWithName(this.variableName,this);n.found||(this.variableName in this.story.constants?this.Error("Can't re-assign to a constant (do you need to use VAR when declaring '".concat(this.variableName,"'?)"),this):this.Error("Variable could not be found to assign to: '".concat(this.variableName,"'"),this)),this._runtimeAssignment&&(this._runtimeAssignment.isGlobal=n.isGlobal)}}}]),r}(W),zt=function(t){a(r,t);var e=d(r);function r(t){var i,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;return n(this,r),(i=e.call(this)).previousWeavePoint=null,i.addContentToPreviousWeavePoint=!1,i.hasSeenChoiceInSection=!1,i.currentContainer=null,i._unnamedGatherCount=0,i._choiceCount=0,i._rootContainer=null,i._namedWeavePoints=new Map,i.looseEnds=[],i.gatherPointsToResolve=[],i.ResolveWeavePointNaming=function(){var t,e,n,r=[].concat(y(i.FindAll(At)((function(t){return!(null===t.name||void 0===t.name)}))),y(i.FindAll(mt)((function(t){return!(null===t.name||void 0===t.name)}))));i._namedWeavePoints=new Map;var a,o=S(r);try{for(o.s();!(a=o.n()).done;){var s=a.value,l=i.namedWeavePoints.get((null===(t=s.identifier)||void 0===t?void 0:t.name)||"");if(l){var u=l instanceof At?"gather":"choice",c=l;i.Error("A ".concat(u," with the same label name '").concat(s.name,"' already exists in this context on line ").concat(c.debugMetadata?c.debugMetadata.startLineNumber:"NO DEBUG METADATA AVAILABLE"),s)}(null===(e=s.identifier)||void 0===e?void 0:e.name)&&i.namedWeavePoints.set(null===(n=s.identifier)||void 0===n?void 0:n.name,s)}}catch(t){o.e(t)}finally{o.f()}},i.ConstructWeaveHierarchyFromIndentation=function(){for(var t=0;t<i.content.length;){var e=i.content[t];if(e instanceof mt||e instanceof At){var n=e.indentationDepth-1;if(n>i.baseIndentIndex){for(var a=t;t<i.content.length;){var o=_(i.content[t],mt)||_(i.content[t],At);if(null!==o)if(o.indentationDepth-1<=i.baseIndentIndex)break;t+=1}var s=t-a,l=i.content.slice(a,a+s);i.content.splice(a,s);var u=new r(l,n);i.InsertContent(a,u),t=a}}t+=1}},i.DetermineBaseIndentationFromContent=function(t){var e,n=S(t);try{for(n.s();!(e=n.n()).done;){var r=e.value;if(r instanceof mt||r instanceof At)return r.indentationDepth-1}}catch(t){n.e(t)}finally{n.f()}return 0},i.GenerateRuntimeObject=function(){i._rootContainer=new tt,i.currentContainer=i._rootContainer,i.looseEnds=[],i.gatherPointsToResolve=[];var t,e=S(i.content);try{for(e.s();!(t=e.n()).done;){var n=t.value;if(n instanceof mt||n instanceof At)i.AddRuntimeForWeavePoint(n);else if(n instanceof r){var a,o=n;i.AddRuntimeForNestedWeave(o),(a=i.gatherPointsToResolve).splice.apply(a,[0,0].concat(y(o.gatherPointsToResolve)))}else i.AddGeneralRuntimeContent(n.runtimeObject)}}catch(t){e.e(t)}finally{e.f()}return i.PassLooseEndsToAncestors(),i._rootContainer},i.AddRuntimeForGather=function(t){var e=!i.hasSeenChoiceInSection;i.hasSeenChoiceInSection=!1;var n=t.runtimeContainer;if(t.name||(n.name="g-".concat(i._unnamedGatherCount),i._unnamedGatherCount+=1),e){if(!i.currentContainer)throw new Error;i.currentContainer.AddContent(n)}else i.rootContainer.AddToNamedContentOnly(n);var r,a=S(i.looseEnds);try{for(a.s();!(r=a.n()).done;){var o=r.value;if(o instanceof At)if(o.indentationDepth==t.indentationDepth)continue;var s=null;if(o instanceof jt)s=o.runtimeObject;else{s=new vt;var l=o;if(!l.runtimeContainer)throw new Error;l.runtimeContainer.AddContent(s)}i.gatherPointsToResolve.push(new Mt(s,n))}}catch(t){a.e(t)}finally{a.f()}i.looseEnds=[],i.currentContainer=n},i.AddRuntimeForWeavePoint=function(t){if(t instanceof At)i.AddRuntimeForGather(t);else if(t instanceof mt){if(!i.currentContainer)throw new Error;i.previousWeavePoint instanceof At&&i.looseEnds.splice(i.looseEnds.indexOf(i.previousWeavePoint),1);var e=t;if(i.currentContainer.AddContent(e.runtimeObject),!e.innerContentContainer)throw new Error;e.innerContentContainer.name="c-".concat(i._choiceCount),i.currentContainer.AddToNamedContentOnly(e.innerContentContainer),i._choiceCount+=1,i.hasSeenChoiceInSection=!0}(i.addContentToPreviousWeavePoint=!1,i.WeavePointHasLooseEnd(t))&&(i.looseEnds.push(t),_(t,mt)&&(i.addContentToPreviousWeavePoint=!0));i.previousWeavePoint=t},i.AddRuntimeForNestedWeave=function(t){i.AddGeneralRuntimeContent(t.rootContainer),null!==i.previousWeavePoint&&(i.looseEnds.splice(i.looseEnds.indexOf(i.previousWeavePoint),1),i.addContentToPreviousWeavePoint=!1)},i.AddGeneralRuntimeContent=function(t){if(null!==t)if(i.addContentToPreviousWeavePoint){if(!i.previousWeavePoint||!i.previousWeavePoint.runtimeContainer)throw new Error;i.previousWeavePoint.runtimeContainer.AddContent(t)}else{if(!i.currentContainer)throw new Error;i.currentContainer.AddContent(t)}},i.PassLooseEndsToAncestors=function(){if(0!==i.looseEnds.length){for(var t=null,e=null,n=!1,a=i.parent;null!==a;a=a.parent){var o=_(a,r);o&&(n||null!==t||(t=o),n&&null===e&&(e=o)),(a instanceof qt||a instanceof kt)&&(n=!0)}if(null!==t||null!==e)for(var s=i.looseEnds.length-1;s>=0;s-=1){var l=i.looseEnds[s],u=!1;if(n){if(l instanceof mt&&null!==t)t.ReceiveLooseEnd(l),u=!0;else if(!(l instanceof mt)){var c=t||e;null!==c&&(c.ReceiveLooseEnd(l),u=!0)}}else(null==t?void 0:t.hasOwnProperty("ReceiveLooseEnd"))&&t.ReceiveLooseEnd(l),u=!0;u&&i.looseEnds.splice(s,1)}}},i.ReceiveLooseEnd=function(t){i.looseEnds.push(t)},i.WeavePointNamed=function(t){if(!i.namedWeavePoints)return null;var e=i.namedWeavePoints.get(t);return e||null},i.IsGlobalDeclaration=function(t){var e=_(t,Jt);return!!(e&&e.isGlobalDeclaration&&e.isDeclaration)||!!_(t,_t)},i.ContentThatFollowsWeavePoint=function(t){var e=[],n=t;if(null!==n.content){var a,o=S(n.content);try{for(o.s();!(a=o.n()).done;){var s=a.value;i.IsGlobalDeclaration(s)||e.push(s)}}catch(t){o.e(t)}finally{o.f()}}var l=_(n.parent,r);if(null===l)throw new Error("Expected weave point parent to be weave?");for(var u=l.content.indexOf(n)+1;u<l.content.length;u+=1){var c=l.content[u];if(!i.IsGlobalDeclaration(c)){if(c instanceof mt||c instanceof At)break;if(c instanceof r)break;e.push(c)}}return e},i.ValidateTermination=function(t){if(!(i.lastParsedSignificantObject instanceof F))if(null!==i.looseEnds&&i.looseEnds.length>0){var e,n=S(i.looseEnds);try{for(n.s();!(e=n.n()).done;){var r=e.value,a=i.ContentThatFollowsWeavePoint(r);i.ValidateFlowOfObjectsTerminates(a,r,t)}}catch(t){n.e(t)}finally{n.f()}}else{var o,s=S(i.content);try{for(s.s();!(o=s.n()).done;){var l=o.value;if(l instanceof mt||l instanceof jt)return}}catch(t){s.e(t)}finally{s.f()}i.ValidateFlowOfObjectsTerminates(i.content,h(i),t)}},i.BadNestedTerminationHandler=function(t){for(var e=null,n=t.parent;null!==n;n=n.parent)if(n instanceof qt||n instanceof kt){e=_(n,kt);break}var r="Choices nested in conditionals or sequences need to explicitly divert afterwards.";null!==e&&(1===e.FindAll(mt)().length&&(r="Choices with conditions should be written: '* {condition} choice'. Otherwise, ".concat(r.toLowerCase())));i.Error(r,t)},i.ValidateFlowOfObjectsTerminates=function(t,e,n){var r,i=!1,a=e,o=S(t);try{for(o.s();!(r=o.n()).done;){var s=r.value;if(null!==s.Find(jt)((function(t){return!(t.isThread||t.isTunnel||t.isFunctionCall||t.parent instanceof Vt)}))&&(i=!0),null!=s.Find(Ut)()){i=!0;break}a=s}}catch(t){o.e(t)}finally{o.f()}if(!i){if(a instanceof F)return;n(a)}},i.WeavePointHasLooseEnd=function(t){if(null===t.content)return!0;for(var e=t.content.length-1;e>=0;--e){var n=_(t.content[e],jt);if(n)if(!(n.isThread||n.isTunnel||n.isFunctionCall))return!1}return!0},i.CheckForWeavePointNamingCollisions=function(){if(i.namedWeavePoints){var t,e=[],n=S(i.ancestry);try{for(n.s();!(t=n.n()).done;){var r=_(t.value,Ot);if(!r)break;e.push(r)}}catch(t){n.e(t)}finally{n.f()}var a,o=S(i.namedWeavePoints);try{for(o.s();!(a=o.n()).done;){var s,l=m(a.value,2),u=l[0],c=l[1],h=S(e);try{for(h.s();!(s=h.n()).done;){var f=s.value.ContentWithNameAtLevel(u);if(f&&f!==c){var d="".concat(c.GetType()," '").concat(u,"' has the same label name as a ").concat(f.GetType()," (on ").concat(f.debugMetadata,")");i.Error(d,c)}}}catch(t){h.e(t)}finally{h.f()}}}catch(t){o.e(t)}finally{o.f()}}},i.baseIndentIndex=-1==a?i.DetermineBaseIndentationFromContent(t):a,i.AddContent(t),i.ConstructWeaveHierarchyFromIndentation(),i}return i(r,[{key:"rootContainer",get:function(){return this._rootContainer||(this._rootContainer=this.GenerateRuntimeObject()),this._rootContainer}},{key:"namedWeavePoints",get:function(){return this._namedWeavePoints}},{key:"lastParsedSignificantObject",get:function(){if(0===this.content.length)return null;for(var t=null,e=this.content.length-1;e>=0;--e){var n=_(t=this.content[e],Et);if((!n||"\n"!==n.text)&&!this.IsGlobalDeclaration(t))break}var i=_(t,r);return i&&(t=i.lastParsedSignificantObject),t}},{key:"typeName",get:function(){return"Weave"}},{key:"ResolveReferences",value:function(t){if(p(o(r.prototype),"ResolveReferences",this).call(this,t),null!==this.looseEnds&&this.looseEnds.length>0){for(var e=!1,n=this.parent;null!==n;n=n.parent)if(n instanceof qt||n instanceof kt){e=!0;break}e&&this.ValidateTermination(this.BadNestedTerminationHandler)}var i,a=S(this.gatherPointsToResolve);try{for(a.s();!(i=a.n()).done;){var s=i.value;s.divert.targetPath=s.targetRuntimeObj.path}}catch(t){a.e(t)}finally{a.f()}this.CheckForWeavePointNamingCollisions()}}]),r}(W),$t=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this))._contentContainer=null,i._conditionalDivert=null,i._ownExpression=null,i._innerWeave=null,i.isTrueBranch=!1,i.matchingEquality=!1,i.isElse=!1,i.isInline=!1,i.returnDivert=null,i.GenerateRuntimeObject=function(){if(i._innerWeave){var t,e=S(i._innerWeave.content);try{for(e.s();!(t=e.n()).done;){var n=_(t.value,Et);n&&n.text.startsWith("else:")&&i.Warning("Saw the text 'else:' which is being treated as content. Did you mean '- else:'?",n)}}catch(t){e.e(t)}finally{e.f()}}var r=new tt,a=i.matchingEquality&&!i.isElse;if(a&&r.AddContent(et.Duplicate()),i._conditionalDivert=new vt,i._conditionalDivert.isConditional=!i.isElse,!i.isTrueBranch&&!i.isElse){var o=null!==i.ownExpression;o&&r.AddContent(et.EvalStart()),i.ownExpression&&i.ownExpression.GenerateIntoContainer(r),i.matchingEquality&&r.AddContent(it.CallWithName("==")),o&&r.AddContent(et.EvalEnd())}return r.AddContent(i._conditionalDivert),i._contentContainer=i.GenerateRuntimeForContent(),i._contentContainer.name="b",i.isInline||i._contentContainer.InsertContent(new $("\n"),0),(a||i.isElse&&i.matchingEquality)&&i._contentContainer.InsertContent(et.PopEvaluatedValue(),0),r.AddToNamedContentOnly(i._contentContainer),i.returnDivert=new vt,i._contentContainer.AddContent(i.returnDivert),r},i.GenerateRuntimeForContent=function(){return null===i._innerWeave?new tt:i._innerWeave.rootContainer},t&&(i._innerWeave=new zt(t),i.AddContent(i._innerWeave)),i}return i(r,[{key:"ownExpression",get:function(){return this._ownExpression},set:function(t){this._ownExpression=t,this._ownExpression&&this.AddContent(this._ownExpression)}},{key:"typeName",get:function(){return"ConditionalSingleBranch"}},{key:"ResolveReferences",value:function(t){if(!this._conditionalDivert||!this._contentContainer)throw new Error;this._conditionalDivert.targetPath=this._contentContainer.path,p(o(r.prototype),"ResolveReferences",this).call(this,t)}}]),r}(W);!function(t){t[t.ParsingString=1]="ParsingString"}(Gt||(Gt={}));var Xt,Yt=function(){function t(){n(this,t),this.startLineNumber=0,this.endLineNumber=0,this.startCharacterNumber=0,this.endCharacterNumber=0,this.fileName=null,this.sourceName=null}return i(t,[{key:"Merge",value:function(e){var n=new t;return n.fileName=this.fileName,n.sourceName=this.sourceName,this.startLineNumber<e.startLineNumber?(n.startLineNumber=this.startLineNumber,n.startCharacterNumber=this.startCharacterNumber):this.startLineNumber>e.startLineNumber?(n.startLineNumber=e.startLineNumber,n.startCharacterNumber=e.startCharacterNumber):(n.startLineNumber=this.startLineNumber,n.startCharacterNumber=Math.min(this.startCharacterNumber,e.startCharacterNumber)),this.endLineNumber>e.endLineNumber?(n.endLineNumber=this.endLineNumber,n.endCharacterNumber=this.endCharacterNumber):this.endLineNumber<e.endLineNumber?(n.endLineNumber=e.endLineNumber,n.endCharacterNumber=e.endCharacterNumber):(n.endLineNumber=this.endLineNumber,n.endCharacterNumber=Math.max(this.endCharacterNumber,e.endCharacterNumber)),n}},{key:"toString",value:function(){return null!==this.fileName?"line ".concat(this.startLineNumber," of ").concat(this.fileName,'"'):"line "+this.startLineNumber}}]),t}(),Zt=function(t){a(r,t);var e=d(r);function r(t,i){var a;return n(this,r),(a=e.call(this)).identifier=t,a.argumentNames=i,a.GenerateRuntimeObject=function(){return a.story.AddExternal(h(a)),null},a}return i(r,[{key:"name",get:function(){var t;return(null===(t=this.identifier)||void 0===t?void 0:t.name)||null}},{key:"typeName",get:function(){return"EXTERNAL"}},{key:"toString",value:function(){var t;return"EXTERNAL ".concat(null===(t=this.identifier)||void 0===t?void 0:t.name)}}]),r}(W),Qt=i((function t(e,r,i){n(this,t),this.name=e,this.args=r,this.isFunction=i})),te=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this))._objToWrap=t,i.GenerateRuntimeObject=function(){return i._objToWrap},i}return i(r)}(W),ee=function(t){a(r,t);var e=d(r);function r(t){return n(this,r),e.call(this,t)}return i(r,[{key:"typeName",get:function(){return"Glue"}}]),r}(te),ne=function(t){a(r,t);var e=d(r);function r(){return n(this,r),e.apply(this,arguments)}return i(r,[{key:"toString",value:function(){return"Glue"}}]),r}(V),re=function(t){a(r,t);var e=d(r);function r(t,i,a){var o;return n(this,r),(o=e.call(this)).varIdentifier=t,o._runtimeAssignment=null,o.expression=null,o.GenerateIntoContainer=function(t){var e,n;t.AddContent(new Wt((null===(e=o.varIdentifier)||void 0===e?void 0:e.name)||null)),o.expression?o.expression.GenerateIntoContainer(t):t.AddContent(new J(1)),t.AddContent(it.CallWithName(o.isInc?"+":"-")),o._runtimeAssignment=new pt((null===(n=o.varIdentifier)||void 0===n?void 0:n.name)||null,!1),t.AddContent(o._runtimeAssignment)},o.toString=function(){var t,e;return o.expression?"".concat(null===(t=o.varIdentifier)||void 0===t?void 0:t.name).concat(o.isInc?" += ":" -= ").concat(o.expression):"".concat(null===(e=o.varIdentifier)||void 0===e?void 0:e.name)+(o.isInc?"++":"--")},i instanceof nt?(o.expression=i,o.AddContent(o.expression),o.isInc=Boolean(a)):o.isInc=i,o}return i(r,[{key:"typeName",get:function(){return"IncDecExpression"}},{key:"ResolveReferences",value:function(t){var e;p(o(r.prototype),"ResolveReferences",this).call(this,t);var n=t.ResolveVariableWithName((null===(e=this.varIdentifier)||void 0===e?void 0:e.name)||"",this);if(n.found||this.Error("variable for ".concat(this.incrementDecrementWord," could not be found: '").concat(this.varIdentifier,"' after searching: {this.descriptionOfScope}")),!this._runtimeAssignment)throw new Error;this._runtimeAssignment.isGlobal=n.isGlobal,this.parent instanceof zt||this.parent instanceof Ot||this.parent instanceof It||this.Error("Can't use ".concat(this.incrementDecrementWord," as sub-expression"))}},{key:"incrementDecrementWord",get:function(){return this.isInc?"increment":"decrement"}}]),r}(nt),ie=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).includedStory=t,i.GenerateRuntimeObject=function(){return null},i}return i(r)}(W),ae=i((function t(e,r,i){var a=this;n(this,t),this.type=e,this.precedence=r,this.requireWhitespace=i,this.toString=function(){return a.type}})),oe=function(t){a(r,t);var e=d(r);function r(t,i,a,o){return n(this,r),e.call(this,t,i,a,o)}return i(r,[{key:"flowLevel",get:function(){return bt.Knot}},{key:"typeName",get:function(){return this.isFunction?"Function":"Knot"}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t);var e=this.story;for(var n in this.subFlowsByName){var i=e.ContentWithNameAtLevel(n,bt.Knot,!1);if(i){var a=this.subFlowsByName.get(n),s="Stitch '".concat(a?a.name:"NO STITCH FOUND","' has the same name as a knot (on ").concat(i.debugMetadata,")");this.Error(s,a)}}}}]),r}(Ot),se=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).itemIdentifierList=t,i.GenerateIntoContainer=function(t){var e,n,r=new B;if(null!=i.itemIdentifierList){var a,o=S(i.itemIdentifierList);try{for(o.s();!(a=o.n()).done;){var s=a.value,l=(null===(e=null==s?void 0:s.name)||void 0===e?void 0:e.split("."))||[],u=null,c="";l.length>1?(u=l[0],c=l[1]):c=l[0];var f=i.story.ResolveListItem(u,c,h(i));if(null===f)null===u?i.Error("Could not find list definition that contains item '".concat(s,"'")):i.Error("Could not find list item ".concat(s));else{if(null==f.parent)return void i.Error("Could not find list definition for item ".concat(s));u||(u=(null===(n=f.parent.identifier)||void 0===n?void 0:n.name)||null);var d=new M(u,f.name||null);r.has(d.serialized())?i.Warning("Duplicate of item '".concat(s,"' in list.")):r.Add(d,f.seriesValue)}}}catch(t){o.e(t)}finally{o.f()}}t.AddContent(new Z(r))},i}return i(r,[{key:"typeName",get:function(){return"List"}}]),r}(nt),le=function(t){a(r,t);var e=d(r);function r(t,i){var a,s,l=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;return n(this,r),(s=e.call(this)).indentifier=t,s.inInitialList=i,s.explicitValue=l,s.seriesValue=0,s.parent=null,s.GenerateRuntimeObject=function(){throw new Error("Not implemented.")},s.toString=function(){return s.fullName},s.parent=p((a=h(s),o(r.prototype)),"parent",a),s}return i(r,[{key:"fullName",get:function(){var t,e=this.parent;if(null===e)throw new Error("Can't get full name without a parent list.");return"".concat(null===(t=e.identifier)||void 0===t?void 0:t.name,".").concat(this.name)}},{key:"typeName",get:function(){return"ListElement"}},{key:"name",get:function(){var t;return(null===(t=this.indentifier)||void 0===t?void 0:t.name)||null}},{key:"ResolveReferences",value:function(t){p(o(r.prototype),"ResolveReferences",this).call(this,t),t.CheckForNamingCollisions(this,this.indentifier,ft.ListItem)}}]),r}(W);!function(t){t[t.InnerBlock=0]="InnerBlock",t[t.Stitch=1]="Stitch",t[t.Knot=2]="Knot",t[t.Top=3]="Top"}(Xt||(Xt={}));var ue=function(t){a(r,t);var e=d(r);function r(t,i,a,s){var l,u;return n(this,r),(u=e.call(this,t,i,a,s)).toString=function(){return"".concat(null!==u.parent?u.parent+" > ":"").concat(p((l=h(u),o(r.prototype)),"toString",l).call(l))},u}return i(r,[{key:"flowLevel",get:function(){return bt.Stitch}},{key:"typeName",get:function(){return"Stitch"}}]),r}(Ot),ce=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).text=t.toString()||"",i}return i(r,[{key:"toString",value:function(){return"# "+this.text}}]),r}(V),he=function(t){a(r,t);var e=d(r);function r(){var t;return n(this,r),(t=e.apply(this,arguments)).text="",t.index=0,t.threadAtGeneration=null,t.sourcePath="",t.targetPath=null,t.isInvisibleDefault=!1,t.originalThreadIndex=0,t}return i(r,[{key:"pathStringOnChoice",get:function(){return null===this.targetPath?L("Choice.targetPath"):this.targetPath.toString()},set:function(t){this.targetPath=new R(t)}}]),r}(V),fe=function(){function t(e){n(this,t),this._lists=new Map,this._allUnambiguousListValueCache=new Map;var r,i=S(e);try{for(i.s();!(r=i.n()).done;){var a=r.value;this._lists.set(a.name,a);var o,s=S(a.items);try{for(s.s();!(o=s.n()).done;){var l=m(o.value,2),u=l[0],c=l[1],h=M.fromSerializedKey(u),f=new Z(h,c);if(!h.itemName)throw new Error("item.itemName is null or undefined.");this._allUnambiguousListValueCache.set(h.itemName,f),this._allUnambiguousListValueCache.set(h.fullName,f)}}catch(t){s.e(t)}finally{s.f()}}}catch(t){i.e(t)}finally{i.f()}}return i(t,[{key:"lists",get:function(){var t,e=[],n=S(this._lists);try{for(n.s();!(t=n.n()).done;){var r=m(t.value,2)[1];e.push(r)}}catch(t){n.e(t)}finally{n.f()}return e}},{key:"TryListGetDefinition",value:function(t,e){if(null===t)return{result:e,exists:!1};var n=this._lists.get(t);return n?{result:n,exists:!0}:{result:e,exists:!1}}},{key:"FindSingleItemListWithName",value:function(t){if(null===t)return L("name");var e=this._allUnambiguousListValueCache.get(t);return void 0!==e?e:null}}]),t}(),de=function(){function t(){n(this,t)}return i(t,null,[{key:"JArrayToRuntimeObjList",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=t.length;e&&n--;for(var r=[],i=0;i<n;i++){var a=t[i],o=this.JTokenToRuntimeObject(a);if(null===o)return L("runtimeObj");r.push(o)}return r}},{key:"WriteDictionaryRuntimeObjs",value:function(t,e){t.WriteObjectStart();var n,r=S(e);try{for(r.s();!(n=r.n()).done;){var i=m(n.value,2),a=i[0],o=i[1];t.WritePropertyStart(a),this.WriteRuntimeObject(t,o),t.WritePropertyEnd()}}catch(t){r.e(t)}finally{r.f()}t.WriteObjectEnd()}},{key:"WriteListRuntimeObjs",value:function(t,e){t.WriteArrayStart();var n,r=S(e);try{for(r.s();!(n=r.n()).done;){var i=n.value;this.WriteRuntimeObject(t,i)}}catch(t){r.e(t)}finally{r.f()}t.WriteArrayEnd()}},{key:"WriteIntDictionary",value:function(t,e){t.WriteObjectStart();var n,r=S(e);try{for(r.s();!(n=r.n()).done;){var i=m(n.value,2),a=i[0],o=i[1];t.WriteIntProperty(a,o)}}catch(t){r.e(t)}finally{r.f()}t.WriteObjectEnd()}},{key:"WriteRuntimeObject",value:function(e,n){var r=_(n,tt);if(r)this.WriteRuntimeContainer(e,r);else{var i=_(n,vt);if(i){var a,o="->";return i.isExternal?o="x()":i.pushesToStack&&(i.stackPushType==ct.Function?o="f()":i.stackPushType==ct.Tunnel&&(o="->t->")),a=i.hasVariableTarget?i.variableDivertName:i.targetPathString,e.WriteObjectStart(),e.WriteProperty(o,a),i.hasVariableTarget&&e.WriteProperty("var",!0),i.isConditional&&e.WriteProperty("c",!0),i.externalArgs>0&&e.WriteIntProperty("exArgs",i.externalArgs),void e.WriteObjectEnd()}var s=_(n,ht);if(s)return e.WriteObjectStart(),e.WriteProperty("*",s.pathStringOnChoice),e.WriteIntProperty("flg",s.flags),void e.WriteObjectEnd();var l=_(n,H);if(l)e.WriteBool(l.value);else{var u=_(n,J);if(u)e.WriteInt(u.value);else{var c=_(n,z);if(c)e.WriteFloat(c.value);else{var h=_(n,$);if(h)h.isNewline?e.Write("\n",!1):(e.WriteStringStart(),e.WriteStringInner("^"),e.WriteStringInner(h.value),e.WriteStringEnd());else{var f=_(n,Z);if(f)this.WriteInkList(e,f);else{var d=_(n,X);if(d)return e.WriteObjectStart(),null===d.value?L("divTargetVal.value"):(e.WriteProperty("^->",d.value.componentsString),void e.WriteObjectEnd());var v=_(n,Y);if(v)return e.WriteObjectStart(),e.WriteProperty("^var",v.value),e.WriteIntProperty("ci",v.contextIndex),void e.WriteObjectEnd();if(_(n,ne))e.Write("<>");else{var p=_(n,et);if(p)e.Write(t._controlCommandNames[p.commandType]);else{var m=_(n,it);if(m){var y=m.name;return"^"==y&&(y="L^"),void e.Write(y)}var g=_(n,Wt);if(g){e.WriteObjectStart();var C=g.pathStringForCount;return null!=C?e.WriteProperty("CNT?",C):e.WriteProperty("VAR?",g.name),void e.WriteObjectEnd()}var S=_(n,pt);if(S){e.WriteObjectStart();var b=S.isGlobal?"VAR=":"temp=";return e.WriteProperty(b,S.variableName),S.isNewDeclaration||e.WriteProperty("re",!0),void e.WriteObjectEnd()}if(_(n,rt))e.Write("void");else{var w=_(n,ce);if(w)return e.WriteObjectStart(),e.WriteProperty("#",w.text),void e.WriteObjectEnd();var k=_(n,he);if(!k)throw new Error("Failed to convert runtime object to Json token: "+n);this.WriteChoice(e,k)}}}}}}}}}}},{key:"JObjectToDictionaryRuntimeObjs",value:function(t){var e=new Map;for(var n in t)if(t.hasOwnProperty(n)){var r=this.JTokenToRuntimeObject(t[n]);if(null===r)return L("inkObject");e.set(n,r)}return e}},{key:"JObjectToIntDictionary",value:function(t){var e=new Map;for(var n in t)t.hasOwnProperty(n)&&e.set(n,parseInt(t[n]));return e}},{key:"JTokenToRuntimeObject",value:function(n){if("number"==typeof n&&!isNaN(n)||"boolean"==typeof n)return K.Create(n);if("string"==typeof n){var r=n.toString(),i=r[0];if("^"==i)return new $(r.substring(1));if("\n"==i&&1==r.length)return new $("\n");if("<>"==r)return new ne;for(var a=0;a<t._controlCommandNames.length;++a){if(r==t._controlCommandNames[a])return new et(a)}if("L^"==r&&(r="^"),it.CallExistsWithName(r))return it.CallWithName(r);if("->->"==r)return et.PopTunnel();if("~ret"==r)return et.PopFunction();if("void"==r)return new rt}if("object"===e(n)&&!Array.isArray(n)){var o,s=n;if(s["^->"])return o=s["^->"],new X(new R(o.toString()));if(s["^var"]){o=s["^var"];var l=new Y(o.toString());return"ci"in s&&(o=s.ci,l.contextIndex=parseInt(o)),l}var u=!1,c=!1,h=ct.Function,f=!1;if((o=s["->"])?u=!0:(o=s["f()"])?(u=!0,c=!0,h=ct.Function):(o=s["->t->"])?(u=!0,c=!0,h=ct.Tunnel):(o=s["x()"])&&(u=!0,f=!0,c=!1,h=ct.Function),u){var d=new vt;d.pushesToStack=c,d.stackPushType=h,d.isExternal=f;var v=o.toString();return(o=s.var)?d.variableDivertName=v:d.targetPathString=v,d.isConditional=!!s.c,f&&(o=s.exArgs)&&(d.externalArgs=parseInt(o)),d}if(o=s["*"]){var p=new ht;return p.pathStringOnChoice=o.toString(),(o=s.flg)&&(p.flags=parseInt(o)),p}if(o=s["VAR?"])return new Wt(o.toString());if(o=s["CNT?"]){var m=new Wt;return m.pathStringForCount=o.toString(),m}var y=!1,g=!1;if((o=s["VAR="])?(y=!0,g=!0):(o=s["temp="])&&(y=!0,g=!1),y){var C=o.toString(),S=!s.re,b=new pt(C,S);return b.isGlobal=g,b}if(void 0!==s["#"])return o=s["#"],new ce(o.toString());if(o=s.list){var w=o,k=new B;if(o=s.origins){var E=o;k.SetInitialOriginNames(E)}for(var _ in w)if(w.hasOwnProperty(_)){var A=w[_],T=new M(_),P=parseInt(A);k.Add(T,P)}return new Z(k)}if(null!=s.originalChoicePath)return this.JObjectToChoice(s)}if(Array.isArray(n))return this.JArrayToContainer(n);if(null==n)return null;throw new Error("Failed to convert token to runtime object: "+this.toJson(n,["parent"]))}},{key:"toJson",value:function(t,e,n){return JSON.stringify(t,(function(t,n){return(null==e?void 0:e.some((function(e){return e===t})))?void 0:n}),n)}},{key:"WriteRuntimeContainer",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(t.WriteArrayStart(),null===e)return L("container");var r,i=S(e.content);try{for(i.s();!(r=i.n()).done;){var a=r.value;this.WriteRuntimeObject(t,a)}}catch(t){i.e(t)}finally{i.f()}var o=e.namedOnlyContent,s=e.countFlags,l=null!=e.name&&!n,u=null!=o||s>0||l;if(u&&t.WriteObjectStart(),null!=o){var c,h=S(o);try{for(h.s();!(c=h.n()).done;){var f=m(c.value,2),d=f[0],v=f[1],p=d,y=_(v,tt);t.WritePropertyStart(p),this.WriteRuntimeContainer(t,y,!0),t.WritePropertyEnd()}}catch(t){h.e(t)}finally{h.f()}}s>0&&t.WriteIntProperty("#f",s),l&&t.WriteProperty("#n",e.name),u?t.WriteObjectEnd():t.WriteNull(),t.WriteArrayEnd()}},{key:"JArrayToContainer",value:function(t){var e=new tt;e.content=this.JArrayToRuntimeObjList(t,!0);var n=t[t.length-1];if(null!=n){var r=new Map;for(var i in n)if("#f"==i)e.countFlags=parseInt(n[i]);else if("#n"==i)e.name=n[i].toString();else{var a=this.JTokenToRuntimeObject(n[i]),o=_(a,tt);o&&(o.name=i),r.set(i,a)}e.namedOnlyContent=r}return e}},{key:"JObjectToChoice",value:function(t){var e=new he;return e.text=t.text.toString(),e.index=parseInt(t.index),e.sourcePath=t.originalChoicePath.toString(),e.originalThreadIndex=parseInt(t.originalThreadIndex),e.pathStringOnChoice=t.targetPath.toString(),e}},{key:"WriteChoice",value:function(t,e){t.WriteObjectStart(),t.WriteProperty("text",e.text),t.WriteIntProperty("index",e.index),t.WriteProperty("originalChoicePath",e.sourcePath),t.WriteIntProperty("originalThreadIndex",e.originalThreadIndex),t.WriteProperty("targetPath",e.pathStringOnChoice),t.WriteObjectEnd()}},{key:"WriteInkList",value:function(t,e){var n=e.value;if(null===n)return L("rawList");t.WriteObjectStart(),t.WritePropertyStart("list"),t.WriteObjectStart();var r,i=S(n);try{for(i.s();!(r=i.n()).done;){var a=m(r.value,2),o=a[0],s=a[1],l=M.fromSerializedKey(o),u=s;if(null===l.itemName)return L("item.itemName");t.WritePropertyNameStart(),t.WritePropertyNameInner(l.originName?l.originName:"?"),t.WritePropertyNameInner("."),t.WritePropertyNameInner(l.itemName),t.WritePropertyNameEnd(),t.Write(u),t.WritePropertyEnd()}}catch(t){i.e(t)}finally{i.f()}if(t.WriteObjectEnd(),t.WritePropertyEnd(),0==n.Count&&null!=n.originNames&&n.originNames.length>0){t.WritePropertyStart("origins"),t.WriteArrayStart();var c,h=S(n.originNames);try{for(h.s();!(c=h.n()).done;){var f=c.value;t.Write(f)}}catch(t){h.e(t)}finally{h.f()}t.WriteArrayEnd(),t.WritePropertyEnd()}t.WriteObjectEnd()}},{key:"ListDefinitionsToJToken",value:function(t){var e,n={},r=S(t.lists);try{for(r.s();!(e=r.n()).done;){var i,a=e.value,o={},s=S(a.items);try{for(s.s();!(i=s.n()).done;){var l=m(i.value,2),u=l[0],c=l[1],h=M.fromSerializedKey(u);if(null===h.itemName)return L("item.itemName");o[h.itemName]=c}}catch(t){s.e(t)}finally{s.f()}n[a.name]=o}}catch(t){r.e(t)}finally{r.f()}return n}},{key:"JTokenToListDefinitions",value:function(t){var e=t,n=[];for(var r in e)if(e.hasOwnProperty(r)){var i=r.toString(),a=e[r],o=new Map;for(var s in a)if(e.hasOwnProperty(r)){var l=a[s];o.set(s,parseInt(l))}var u=new Kt(i,o);n.push(u)}return new fe(n)}}]),t}();de._controlCommandNames=function(){var t=[];t[et.CommandType.EvalStart]="ev",t[et.CommandType.EvalOutput]="out",t[et.CommandType.EvalEnd]="/ev",t[et.CommandType.Duplicate]="du",t[et.CommandType.PopEvaluatedValue]="pop",t[et.CommandType.PopFunction]="~ret",t[et.CommandType.PopTunnel]="->->",t[et.CommandType.BeginString]="str",t[et.CommandType.EndString]="/str",t[et.CommandType.NoOp]="nop",t[et.CommandType.ChoiceCount]="choiceCnt",t[et.CommandType.Turns]="turn",t[et.CommandType.TurnsSince]="turns",t[et.CommandType.ReadCount]="readc",t[et.CommandType.Random]="rnd",t[et.CommandType.SeedRandom]="srnd",t[et.CommandType.VisitIndex]="visit",t[et.CommandType.SequenceShuffleIndex]="seq",t[et.CommandType.StartThread]="thread",t[et.CommandType.Done]="done",t[et.CommandType.End]="end",t[et.CommandType.ListFromInt]="listInt",t[et.CommandType.ListRange]="range",t[et.CommandType.ListRandom]="lrnd";for(var e=0;e<et.CommandType.TOTAL_VALUES;++e)if(null==t[e])throw new Error("Control command not accounted for in serialisation");return t}();var ve=function(){function e(){if(n(this,e),this._threadCounter=0,this._startOfRoot=dt.Null,arguments[0]instanceof t.Story){var r=arguments[0];this._startOfRoot=dt.StartOf(r.rootContentContainer),this.Reset()}else{var i=arguments[0];this._threads=[];var a,o=S(i._threads);try{for(o.s();!(a=o.n()).done;){var s=a.value;this._threads.push(s.Copy())}}catch(t){o.e(t)}finally{o.f()}this._threadCounter=i._threadCounter,this._startOfRoot=i._startOfRoot.copy()}}return i(e,[{key:"elements",get:function(){return this.callStack}},{key:"depth",get:function(){return this.elements.length}},{key:"currentElement",get:function(){var t=this._threads[this._threads.length-1].callstack;return t[t.length-1]}},{key:"currentElementIndex",get:function(){return this.callStack.length-1}},{key:"currentThread",get:function(){return this._threads[this._threads.length-1]},set:function(t){I.Assert(1==this._threads.length,"Shouldn't be directly setting the current thread when we have a stack of them"),this._threads.length=0,this._threads.push(t)}},{key:"canPop",get:function(){return this.callStack.length>1}},{key:"Reset",value:function(){this._threads=[],this._threads.push(new e.Thread),this._threads[0].callstack.push(new e.Element(ct.Tunnel,this._startOfRoot))}},{key:"SetJsonToken",value:function(t,n){this._threads.length=0;var r,i=S(t.threads);try{for(i.s();!(r=i.n()).done;){var a=r.value,o=new e.Thread(a,n);this._threads.push(o)}}catch(t){i.e(t)}finally{i.f()}this._threadCounter=parseInt(t.threadCounter),this._startOfRoot=dt.StartOf(n.rootContentContainer)}},{key:"WriteJson",value:function(t){var e=this;t.WriteObject((function(t){t.WritePropertyStart("threads"),t.WriteArrayStart();var n,r=S(e._threads);try{for(r.s();!(n=r.n()).done;){n.value.WriteJson(t)}}catch(t){r.e(t)}finally{r.f()}t.WriteArrayEnd(),t.WritePropertyEnd(),t.WritePropertyStart("threadCounter"),t.WriteInt(e._threadCounter),t.WritePropertyEnd()}))}},{key:"PushThread",value:function(){var t=this.currentThread.Copy();this._threadCounter++,t.threadIndex=this._threadCounter,this._threads.push(t)}},{key:"ForkThread",value:function(){var t=this.currentThread.Copy();return this._threadCounter++,t.threadIndex=this._threadCounter,t}},{key:"PopThread",value:function(){if(!this.canPopThread)throw new Error("Can't pop thread");this._threads.splice(this._threads.indexOf(this.currentThread),1)}},{key:"canPopThread",get:function(){return this._threads.length>1&&!this.elementIsEvaluateFromGame}},{key:"elementIsEvaluateFromGame",get:function(){return this.currentElement.type==ct.FunctionEvaluationFromGame}},{key:"Push",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,i=new e.Element(t,this.currentElement.currentPointer,!1);i.evaluationStackHeightWhenPushed=n,i.functionStartInOutputStream=r,this.callStack.push(i)}},{key:"CanPop",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return!!this.canPop&&(null==t||this.currentElement.type==t)}},{key:"Pop",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(!this.CanPop(t))throw new Error("Mismatched push/pop in Callstack");this.callStack.pop()}},{key:"GetTemporaryVariableWithName",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1;-1==e&&(e=this.currentElementIndex+1);var n=this.callStack[e-1],r=q(n.temporaryVariables,t,null);return r.exists?r.result:null}},{key:"SetTemporaryVariable",value:function(t,e,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:-1;-1==r&&(r=this.currentElementIndex+1);var i=this.callStack[r-1];if(!n&&!i.temporaryVariables.get(t))throw new Error("Could not find temporary variable to set: "+t);var a=q(i.temporaryVariables,t,null);a.exists&&Z.RetainListOriginsForAssignment(a.result,e),i.temporaryVariables.set(t,e)}},{key:"ContextForVariableNamed",value:function(t){return this.currentElement.temporaryVariables.get(t)?this.currentElementIndex+1:0}},{key:"ThreadWithIndex",value:function(t){var e=this._threads.filter((function(e){if(e.threadIndex==t)return e}));return e.length>0?e[0]:null}},{key:"callStack",get:function(){return this.currentThread.callstack}},{key:"callStackTrace",get:function(){for(var t=new j,e=0;e<this._threads.length;e++){var n=this._threads[e],r=e==this._threads.length-1;t.AppendFormat("=== THREAD {0}/{1} {2}===\n",e+1,this._threads.length,r?"(current) ":"");for(var i=0;i<n.callstack.length;i++){n.callstack[i].type==ct.Function?t.Append(" [FUNCTION] "):t.Append(" [TUNNEL] ");var a=n.callstack[i].currentPointer;if(!a.isNull){if(t.Append("<SOMEWHERE IN "),null===a.container)return L("pointer.container");t.Append(a.container.path.toString()),t.AppendLine(">")}}}return t.toString()}}]),e}();!function(t){var e=function(){function t(e,r){var i=arguments.length>2&&void 0!==arguments[2]&&arguments[2];n(this,t),this.evaluationStackHeightWhenPushed=0,this.functionStartInOutputStream=0,this.currentPointer=r.copy(),this.inExpressionEvaluation=i,this.temporaryVariables=new Map,this.type=e}return i(t,[{key:"Copy",value:function(){var e=new t(this.type,this.currentPointer,this.inExpressionEvaluation);return e.temporaryVariables=new Map(this.temporaryVariables),e.evaluationStackHeightWhenPushed=this.evaluationStackHeightWhenPushed,e.functionStartInOutputStream=this.functionStartInOutputStream,e}}]),t}();t.Element=e;var r=function(){function t(){if(n(this,t),this.threadIndex=0,this.previousPointer=dt.Null,this.callstack=[],arguments[0]&&arguments[1]){var r=arguments[0],i=arguments[1];this.threadIndex=parseInt(r.threadIndex);var a,o=r.callstack,s=S(o);try{for(s.s();!(a=s.n()).done;){var l=a.value,u=l,c=parseInt(u.type),h=dt.Null,f=void 0,d=u.cPath;if(void 0!==d){f=d.toString();var v=i.ContentAtPath(new R(f));if(h.container=v.container,h.index=parseInt(u.idx),null==v.obj)throw new Error("When loading state, internal story location couldn't be found: "+f+". Has the story changed since this save data was created?");if(v.approximate){if(null===h.container)return L("pointer.container");i.Warning("When loading state, exact internal story location couldn't be found: '"+f+"', so it was approximated to '"+h.container.path.toString()+"' to recover. Has the story changed since this save data was created?")}}var p=!!u.exp,m=new e(c,h,p),y=u.temp;void 0!==y?m.temporaryVariables=de.JObjectToDictionaryRuntimeObjs(y):m.temporaryVariables.clear(),this.callstack.push(m)}}catch(t){s.e(t)}finally{s.f()}var g=r.previousContentObject;if(void 0!==g){var C=new R(g.toString());this.previousPointer=i.PointerAtPath(C)}}}return i(t,[{key:"Copy",value:function(){var e=new t;e.threadIndex=this.threadIndex;var n,r=S(this.callstack);try{for(r.s();!(n=r.n()).done;){var i=n.value;e.callstack.push(i.Copy())}}catch(t){r.e(t)}finally{r.f()}return e.previousPointer=this.previousPointer.copy(),e}},{key:"WriteJson",value:function(t){t.WriteObjectStart(),t.WritePropertyStart("callstack"),t.WriteArrayStart();var e,n=S(this.callstack);try{for(n.s();!(e=n.n()).done;){var r=e.value;if(t.WriteObjectStart(),!r.currentPointer.isNull){if(null===r.currentPointer.container)return L("el.currentPointer.container");t.WriteProperty("cPath",r.currentPointer.container.path.componentsString),t.WriteIntProperty("idx",r.currentPointer.index)}t.WriteProperty("exp",r.inExpressionEvaluation),t.WriteIntProperty("type",r.type),r.temporaryVariables.size>0&&(t.WritePropertyStart("temp"),de.WriteDictionaryRuntimeObjs(t,r.temporaryVariables),t.WritePropertyEnd()),t.WriteObjectEnd()}}catch(t){n.e(t)}finally{n.f()}if(t.WriteArrayEnd(),t.WritePropertyEnd(),t.WriteIntProperty("threadIndex",this.threadIndex),!this.previousPointer.isNull){var i=this.previousPointer.Resolve();if(null===i)return L("this.previousPointer.Resolve()");t.WriteProperty("previousContentObject",i.path.toString())}t.WriteObjectEnd()}}]),t}();t.Thread=r}(ve||(ve={}));var pe=function(){function t(e,r){n(this,t),this.variableChangedEventCallbacks=[],this.patch=null,this._batchObservingVariableChanges=!1,this._defaultGlobalVariables=new Map,this._changedVariablesForBatchObs=new Set,this._globalVariables=new Map,this._callStack=e,this._listDefsOrigin=r;try{return new Proxy(this,{get:function(t,e){return e in t?t[e]:t.$(e)},set:function(t,e,n){return e in t?t[e]=n:t.$(e,n),!0}})}catch(t){}}return i(t,[{key:"variableChangedEvent",value:function(t,e){var n,r=S(this.variableChangedEventCallbacks);try{for(r.s();!(n=r.n()).done;){(0,n.value)(t,e)}}catch(t){r.e(t)}finally{r.f()}}},{key:"batchObservingVariableChanges",get:function(){return this._batchObservingVariableChanges},set:function(t){if(this._batchObservingVariableChanges=t,t)this._changedVariablesForBatchObs=new Set;else if(null!=this._changedVariablesForBatchObs){var e,n=S(this._changedVariablesForBatchObs);try{for(n.s();!(e=n.n()).done;){var r=e.value,i=this._globalVariables.get(r);i?this.variableChangedEvent(r,i):L("currentValue")}}catch(t){n.e(t)}finally{n.f()}this._changedVariablesForBatchObs=null}}},{key:"callStack",get:function(){return this._callStack},set:function(t){this._callStack=t}},{key:"$",value:function(t,e){if(void 0===e){var n=null;return null!==this.patch&&(n=this.patch.TryGetGlobal(t,null)).exists?n.result.valueObject:(void 0===(n=this._globalVariables.get(t))&&(n=this._defaultGlobalVariables.get(t)),void 0!==n?n.valueObject:null)}if(void 0===this._defaultGlobalVariables.get(t))throw new G("Cannot assign to a variable ("+t+") that hasn't been declared in the story");var r=K.Create(e);if(null==r)throw null==e?new Error("Cannot pass null to VariableState"):new Error("Invalid value passed to VariableState: "+e.toString());this.SetGlobal(t,r)}},{key:"ApplyPatch",value:function(){if(null===this.patch)return L("this.patch");var t,e=S(this.patch.globals);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,2),r=n[0],i=n[1];this._globalVariables.set(r,i)}}catch(t){e.e(t)}finally{e.f()}if(null!==this._changedVariablesForBatchObs){var a,o=S(this.patch.changedVariables);try{for(o.s();!(a=o.n()).done;){var s=a.value;this._changedVariablesForBatchObs.add(s)}}catch(t){o.e(t)}finally{o.f()}}this.patch=null}},{key:"SetJsonToken",value:function(t){this._globalVariables.clear();var e,n=S(this._defaultGlobalVariables);try{for(n.s();!(e=n.n()).done;){var r=m(e.value,2),i=r[0],a=r[1],o=t[i];if(void 0!==o){var s=de.JTokenToRuntimeObject(o);if(null===s)return L("tokenInkObject");this._globalVariables.set(i,s)}else this._globalVariables.set(i,a)}}catch(t){n.e(t)}finally{n.f()}}},{key:"WriteJson",value:function(e){e.WriteObjectStart();var n,r=S(this._globalVariables);try{for(r.s();!(n=r.n()).done;){var i=m(n.value,2),a=i[0],o=i[1],s=a,l=o;if(t.dontSaveDefaultValues&&this._defaultGlobalVariables.has(s)){var u=this._defaultGlobalVariables.get(s);if(this.RuntimeObjectsEqual(l,u))continue}e.WritePropertyStart(s),de.WriteRuntimeObject(e,l),e.WritePropertyEnd()}}catch(t){r.e(t)}finally{r.f()}e.WriteObjectEnd()}},{key:"RuntimeObjectsEqual",value:function(t,e){if(null===t)return L("obj1");if(null===e)return L("obj2");if(t.constructor!==e.constructor)return!1;var n=_(t,H);if(null!==n)return n.value===A(e,H).value;var r=_(t,J);if(null!==r)return r.value===A(e,J).value;var i=_(t,z);if(null!==i)return i.value===A(e,z).value;var a=_(t,K),o=_(e,K);if(null!==a&&null!==o)return x(a.valueObject)&&x(o.valueObject)?a.valueObject.Equals(o.valueObject):a.valueObject===o.valueObject;throw new Error("FastRoughDefinitelyEquals: Unsupported runtime object type: "+t.constructor.name)}},{key:"GetVariableWithName",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:-1,n=this.GetRawVariableWithName(t,e),r=_(n,Y);return null!==r&&(n=this.ValueAtVariablePointer(r)),n}},{key:"TryGetDefaultVariableValue",value:function(t){var e=q(this._defaultGlobalVariables,t,null);return e.exists?e.result:null}},{key:"GlobalVariableExistsWithName",value:function(t){return this._globalVariables.has(t)||null!==this._defaultGlobalVariables&&this._defaultGlobalVariables.has(t)}},{key:"GetRawVariableWithName",value:function(t,e){if(0==e||-1==e){var n=null;if(null!==this.patch&&(n=this.patch.TryGetGlobal(t,null)).exists)return n.result;if((n=q(this._globalVariables,t,null)).exists)return n.result;if(null!==this._defaultGlobalVariables&&(n=q(this._defaultGlobalVariables,t,null)).exists)return n.result;if(null===this._listDefsOrigin)return L("VariablesState._listDefsOrigin");var r=this._listDefsOrigin.FindSingleItemListWithName(t);if(r)return r}return this._callStack.GetTemporaryVariableWithName(t,e)}},{key:"ValueAtVariablePointer",value:function(t){return this.GetVariableWithName(t.variableName,t.contextIndex)}},{key:"Assign",value:function(t,e){var n=t.variableName;if(null===n)return L("name");var r=-1,i=!1;if(i=t.isNewDeclaration?t.isGlobal:this.GlobalVariableExistsWithName(n),t.isNewDeclaration){var a=_(e,Y);if(null!==a)e=this.ResolveVariablePointer(a)}else{var o=null;do{null!=(o=_(this.GetRawVariableWithName(n,r),Y))&&(n=o.variableName,i=0==(r=o.contextIndex))}while(null!=o)}i?this.SetGlobal(n,e):this._callStack.SetTemporaryVariable(n,e,t.isNewDeclaration,r)}},{key:"SnapshotDefaultGlobals",value:function(){this._defaultGlobalVariables=new Map(this._globalVariables)}},{key:"RetainListOriginsForAssignment",value:function(t,e){var n=A(t,Z),r=A(e,Z);n.value&&r.value&&0==r.value.Count&&r.value.SetInitialOriginNames(n.value.originNames)}},{key:"SetGlobal",value:function(t,e){var n=null;if(null===this.patch&&(n=q(this._globalVariables,t,null)),null!==this.patch&&((n=this.patch.TryGetGlobal(t,null)).exists||(n=q(this._globalVariables,t,null))),Z.RetainListOriginsForAssignment(n.result,e),null===t)return L("variableName");if(null!==this.patch?this.patch.SetGlobal(t,e):this._globalVariables.set(t,e),null!==this.variableChangedEvent&&null!==n&&e!==n.result)if(this.batchObservingVariableChanges){if(null===this._changedVariablesForBatchObs)return L("this._changedVariablesForBatchObs");null!==this.patch?this.patch.AddChangedVariable(t):null!==this._changedVariablesForBatchObs&&this._changedVariablesForBatchObs.add(t)}else this.variableChangedEvent(t,e)}},{key:"ResolveVariablePointer",value:function(t){var e=t.contextIndex;-1==e&&(e=this.GetContextIndexOfVariableNamed(t.variableName));var n=_(this.GetRawVariableWithName(t.variableName,e),Y);return null!=n?n:new Y(t.variableName,e)}},{key:"GetContextIndexOfVariableNamed",value:function(t){return this.GlobalVariableExistsWithName(t)?0:this._callStack.currentElementIndex}},{key:"ObserveVariableChange",value:function(t){this.variableChangedEventCallbacks.push(t)}}]),t}();pe.dontSaveDefaultValues=!0;var me=function(){function t(e){n(this,t),this.seed=e%2147483647,this.seed<=0&&(this.seed+=2147483646)}return i(t,[{key:"next",value:function(){return this.seed=48271*this.seed%2147483647}},{key:"nextFloat",value:function(){return(this.next()-1)/2147483646}}]),t}(),ye=function(){function t(){if(n(this,t),this._changedVariables=new Set,this._visitCounts=new Map,this._turnIndices=new Map,1===arguments.length&&null!==arguments[0]){var e=arguments[0];this._globals=new Map(e._globals),this._changedVariables=new Set(e._changedVariables),this._visitCounts=new Map(e._visitCounts),this._turnIndices=new Map(e._turnIndices)}else this._globals=new Map,this._changedVariables=new Set,this._visitCounts=new Map,this._turnIndices=new Map}return i(t,[{key:"globals",get:function(){return this._globals}},{key:"changedVariables",get:function(){return this._changedVariables}},{key:"visitCounts",get:function(){return this._visitCounts}},{key:"turnIndices",get:function(){return this._turnIndices}},{key:"TryGetGlobal",value:function(t,e){return null!==t&&this._globals.has(t)?{result:this._globals.get(t),exists:!0}:{result:e,exists:!1}}},{key:"SetGlobal",value:function(t,e){this._globals.set(t,e)}},{key:"AddChangedVariable",value:function(t){return this._changedVariables.add(t)}},{key:"TryGetVisitCount",value:function(t,e){return this._visitCounts.has(t)?{result:this._visitCounts.get(t),exists:!0}:{result:e,exists:!1}}},{key:"SetVisitCount",value:function(t,e){this._visitCounts.set(t,e)}},{key:"SetTurnIndex",value:function(t,e){this._turnIndices.set(t,e)}},{key:"TryGetTurnIndex",value:function(t,e){return this._turnIndices.has(t)?{result:this._turnIndices.get(t),exists:!0}:{result:e,exists:!1}}}]),t}(),ge=function(){function t(){n(this,t)}return i(t,null,[{key:"TextToDictionary",value:function(e){return new t.Reader(e).ToDictionary()}},{key:"TextToArray",value:function(e){return new t.Reader(e).ToArray()}}]),t}();!function(t){var e=function(){function t(e){n(this,t),this._rootObject=JSON.parse(e)}return i(t,[{key:"ToDictionary",value:function(){return this._rootObject}},{key:"ToArray",value:function(){return this._rootObject}}]),t}();t.Reader=e;var r=function(){function e(){n(this,e),this._currentPropertyName=null,this._currentString=null,this._stateStack=[],this._collectionStack=[],this._propertyNameStack=[],this._jsonObject=null}return i(e,[{key:"WriteObject",value:function(t){this.WriteObjectStart(),t(this),this.WriteObjectEnd()}},{key:"WriteObjectStart",value:function(){this.StartNewObject(!0);var e={};if(this.state===t.Writer.State.Property){this.Assert(null!==this.currentCollection),this.Assert(null!==this.currentPropertyName);var n=this._propertyNameStack.pop();this.currentCollection[n]=e,this._collectionStack.push(e)}else this.state===t.Writer.State.Array?(this.Assert(null!==this.currentCollection),this.currentCollection.push(e),this._collectionStack.push(e)):(this.Assert(this.state===t.Writer.State.None),this._jsonObject=e,this._collectionStack.push(e));this._stateStack.push(new t.Writer.StateElement(t.Writer.State.Object))}},{key:"WriteObjectEnd",value:function(){this.Assert(this.state===t.Writer.State.Object),this._collectionStack.pop(),this._stateStack.pop()}},{key:"WriteProperty",value:function(t,e){if(this.WritePropertyStart(t),arguments[1]instanceof Function){var n=arguments[1];n(this)}else{var r=arguments[1];this.Write(r)}this.WritePropertyEnd()}},{key:"WriteIntProperty",value:function(t,e){this.WritePropertyStart(t),this.WriteInt(e),this.WritePropertyEnd()}},{key:"WriteFloatProperty",value:function(t,e){this.WritePropertyStart(t),this.WriteFloat(e),this.WritePropertyEnd()}},{key:"WritePropertyStart",value:function(e){this.Assert(this.state===t.Writer.State.Object),this._propertyNameStack.push(e),this.IncrementChildCount(),this._stateStack.push(new t.Writer.StateElement(t.Writer.State.Property))}},{key:"WritePropertyEnd",value:function(){this.Assert(this.state===t.Writer.State.Property),this.Assert(1===this.childCount),this._stateStack.pop()}},{key:"WritePropertyNameStart",value:function(){this.Assert(this.state===t.Writer.State.Object),this.IncrementChildCount(),this._currentPropertyName="",this._stateStack.push(new t.Writer.StateElement(t.Writer.State.Property)),this._stateStack.push(new t.Writer.StateElement(t.Writer.State.PropertyName))}},{key:"WritePropertyNameEnd",value:function(){this.Assert(this.state===t.Writer.State.PropertyName),this.Assert(null!==this._currentPropertyName),this._propertyNameStack.push(this._currentPropertyName),this._currentPropertyName=null,this._stateStack.pop()}},{key:"WritePropertyNameInner",value:function(e){this.Assert(this.state===t.Writer.State.PropertyName),this.Assert(null!==this._currentPropertyName),this._currentPropertyName+=e}},{key:"WriteArrayStart",value:function(){this.StartNewObject(!0);var e=[];if(this.state===t.Writer.State.Property){this.Assert(null!==this.currentCollection),this.Assert(null!==this.currentPropertyName);var n=this._propertyNameStack.pop();this.currentCollection[n]=e,this._collectionStack.push(e)}else this.state===t.Writer.State.Array?(this.Assert(null!==this.currentCollection),this.currentCollection.push(e),this._collectionStack.push(e)):(this.Assert(this.state===t.Writer.State.None),this._jsonObject=e,this._collectionStack.push(e));this._stateStack.push(new t.Writer.StateElement(t.Writer.State.Array))}},{key:"WriteArrayEnd",value:function(){this.Assert(this.state===t.Writer.State.Array),this._collectionStack.pop(),this._stateStack.pop()}},{key:"Write",value:function(t){null!==t?(this.StartNewObject(!1),this._addToCurrentObject(t)):console.error("Warning: trying to write a null value")}},{key:"WriteBool",value:function(t){null!==t&&(this.StartNewObject(!1),this._addToCurrentObject(t))}},{key:"WriteInt",value:function(t){null!==t&&(this.StartNewObject(!1),this._addToCurrentObject(Math.floor(t)))}},{key:"WriteFloat",value:function(t){null!==t&&(this.StartNewObject(!1),t==Number.POSITIVE_INFINITY?this._addToCurrentObject(34e37):t==Number.NEGATIVE_INFINITY?this._addToCurrentObject(-34e37):isNaN(t)?this._addToCurrentObject(0):this._addToCurrentObject(t))}},{key:"WriteNull",value:function(){this.StartNewObject(!1),this._addToCurrentObject(null)}},{key:"WriteStringStart",value:function(){this.StartNewObject(!1),this._currentString="",this._stateStack.push(new t.Writer.StateElement(t.Writer.State.String))}},{key:"WriteStringEnd",value:function(){this.Assert(this.state==t.Writer.State.String),this._stateStack.pop(),this._addToCurrentObject(this._currentString),this._currentString=null}},{key:"WriteStringInner",value:function(e){this.Assert(this.state===t.Writer.State.String),null!==e?this._currentString+=e:console.error("Warning: trying to write a null string")}},{key:"toString",value:function(){return null===this._jsonObject?"":JSON.stringify(this._jsonObject)}},{key:"StartNewObject",value:function(e){e?this.Assert(this.state===t.Writer.State.None||this.state===t.Writer.State.Property||this.state===t.Writer.State.Array):this.Assert(this.state===t.Writer.State.Property||this.state===t.Writer.State.Array),this.state===t.Writer.State.Property&&this.Assert(0===this.childCount),this.state!==t.Writer.State.Array&&this.state!==t.Writer.State.Property||this.IncrementChildCount()}},{key:"state",get:function(){return this._stateStack.length>0?this._stateStack[this._stateStack.length-1].type:t.Writer.State.None}},{key:"childCount",get:function(){return this._stateStack.length>0?this._stateStack[this._stateStack.length-1].childCount:0}},{key:"currentCollection",get:function(){return this._collectionStack.length>0?this._collectionStack[this._collectionStack.length-1]:null}},{key:"currentPropertyName",get:function(){return this._propertyNameStack.length>0?this._propertyNameStack[this._propertyNameStack.length-1]:null}},{key:"IncrementChildCount",value:function(){this.Assert(this._stateStack.length>0);var t=this._stateStack.pop();t.childCount++,this._stateStack.push(t)}},{key:"Assert",value:function(t){if(!t)throw Error("Assert failed while writing JSON")}},{key:"_addToCurrentObject",value:function(e){this.Assert(null!==this.currentCollection),this.state===t.Writer.State.Array?(this.Assert(Array.isArray(this.currentCollection)),this.currentCollection.push(e)):this.state===t.Writer.State.Property&&(this.Assert(!Array.isArray(this.currentCollection)),this.Assert(null!==this.currentPropertyName),this.currentCollection[this.currentPropertyName]=e,this._propertyNameStack.pop())}}]),e}();t.Writer=r,function(e){var r;(r=e.State||(e.State={}))[r.None=0]="None",r[r.Object=1]="Object",r[r.Array=2]="Array",r[r.Property=3]="Property",r[r.PropertyName=4]="PropertyName",r[r.String=5]="String";var a=i((function e(r){n(this,e),this.type=t.Writer.State.None,this.childCount=0,this.type=r}));e.StateElement=a}(r=t.Writer||(t.Writer={}))}(ge||(ge={}));var Ce,Se=function(){function t(){n(this,t);var e=arguments[0],r=arguments[1];if(this.name=e,this.callStack=new ve(r),arguments[2]){var i=arguments[2];this.callStack.SetJsonToken(i.callstack,r),this.outputStream=de.JArrayToRuntimeObjList(i.outputStream),this.currentChoices=de.JArrayToRuntimeObjList(i.currentChoices);var a=i.choiceThreads;void 0!==a&&this.LoadFlowChoiceThreads(a,r)}else this.outputStream=[],this.currentChoices=[]}return i(t,[{key:"WriteJson",value:function(t){var e=this;t.WriteObjectStart(),t.WriteProperty("callstack",(function(t){return e.callStack.WriteJson(t)})),t.WriteProperty("outputStream",(function(t){return de.WriteListRuntimeObjs(t,e.outputStream)}));var n,r=!1,i=S(this.currentChoices);try{for(i.s();!(n=i.n()).done;){var a=n.value;if(null===a.threadAtGeneration)return L("c.threadAtGeneration");a.originalThreadIndex=a.threadAtGeneration.threadIndex,null===this.callStack.ThreadWithIndex(a.originalThreadIndex)&&(r||(r=!0,t.WritePropertyStart("choiceThreads"),t.WriteObjectStart()),t.WritePropertyStart(a.originalThreadIndex),a.threadAtGeneration.WriteJson(t),t.WritePropertyEnd())}}catch(t){i.e(t)}finally{i.f()}r&&(t.WriteObjectEnd(),t.WritePropertyEnd()),t.WriteProperty("currentChoices",(function(t){t.WriteArrayStart();var n,r=S(e.currentChoices);try{for(r.s();!(n=r.n()).done;){var i=n.value;de.WriteChoice(t,i)}}catch(t){r.e(t)}finally{r.f()}t.WriteArrayEnd()})),t.WriteObjectEnd()}},{key:"LoadFlowChoiceThreads",value:function(t,e){var n,r=S(this.currentChoices);try{for(r.s();!(n=r.n()).done;){var i=n.value,a=this.callStack.ThreadWithIndex(i.originalThreadIndex);if(null!==a)i.threadAtGeneration=a.Copy();else{var o=t["".concat(i.originalThreadIndex)];i.threadAtGeneration=new ve.Thread(o,e)}}}catch(t){r.e(t)}finally{r.f()}}}]),t}(),be=function(){function e(t){n(this,e),this.kInkSaveStateVersion=9,this.kMinCompatibleLoadVersion=8,this.onDidLoadState=null,this._currentErrors=null,this._currentWarnings=null,this.divertedPointer=dt.Null,this._currentTurnIndex=0,this.storySeed=0,this.previousRandom=0,this.didSafeExit=!1,this._currentText=null,this._currentTags=null,this._outputStreamTextDirty=!0,this._outputStreamTagsDirty=!0,this._patch=null,this._namedFlows=null,this.kDefaultFlowName="DEFAULT_FLOW",this.story=t,this._currentFlow=new Se(this.kDefaultFlowName,t),this.OutputStreamDirty(),this._evaluationStack=[],this._variablesState=new pe(this.callStack,t.listDefinitions),this._visitCounts=new Map,this._turnIndices=new Map,this.currentTurnIndex=-1;var r=(new Date).getTime();this.storySeed=new me(r).next()%100,this.previousRandom=0,this.GoToStart()}return i(e,[{key:"ToJson",value:function(){var t=new ge.Writer;return this.WriteJson(t),t.toString()}},{key:"toJson",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return this.ToJson(t)}},{key:"LoadJson",value:function(t){var e=ge.TextToDictionary(t);this.LoadJsonObj(e),null!==this.onDidLoadState&&this.onDidLoadState()}},{key:"VisitCountAtPathString",value:function(t){var e;if(null!==this._patch){var n=this.story.ContentAtPath(new R(t)).container;if(null===n)throw new Error("Content at path not found: "+t);if((e=this._patch.TryGetVisitCount(n,0)).exists)return e.result}return(e=q(this._visitCounts,t,null)).exists?e.result:0}},{key:"VisitCountForContainer",value:function(t){if(null===t)return L("container");if(!t.visitsShouldBeCounted)return this.story.Error("Read count for target ("+t.name+" - on "+t.debugMetadata+") unknown. The story may need to be compiled with countAllVisits flag (-c)."),0;if(null!==this._patch){var e=this._patch.TryGetVisitCount(t,0);if(e.exists)return e.result}var n=t.path.toString(),r=q(this._visitCounts,n,null);return r.exists?r.result:0}},{key:"IncrementVisitCountForContainer",value:function(t){if(null!==this._patch){var e=this.VisitCountForContainer(t);return e++,void this._patch.SetVisitCount(t,e)}var n=t.path.toString(),r=q(this._visitCounts,n,null);r.exists?this._visitCounts.set(n,r.result+1):this._visitCounts.set(n,1)}},{key:"RecordTurnIndexVisitToContainer",value:function(t){if(null===this._patch){var e=t.path.toString();this._turnIndices.set(e,this.currentTurnIndex)}else this._patch.SetTurnIndex(t,this.currentTurnIndex)}},{key:"TurnsSinceForContainer",value:function(t){if(t.turnIndexShouldBeCounted||this.story.Error("TURNS_SINCE() for target ("+t.name+" - on "+t.debugMetadata+") unknown. The story may need to be compiled with countAllVisits flag (-c)."),null!==this._patch){var e=this._patch.TryGetTurnIndex(t,0);if(e.exists)return this.currentTurnIndex-e.result}var n=t.path.toString(),r=q(this._turnIndices,n,0);return r.exists?this.currentTurnIndex-r.result:-1}},{key:"callstackDepth",get:function(){return this.callStack.depth}},{key:"outputStream",get:function(){return this._currentFlow.outputStream}},{key:"currentChoices",get:function(){return this.canContinue?[]:this._currentFlow.currentChoices}},{key:"generatedChoices",get:function(){return this._currentFlow.currentChoices}},{key:"currentErrors",get:function(){return this._currentErrors}},{key:"currentWarnings",get:function(){return this._currentWarnings}},{key:"variablesState",get:function(){return this._variablesState},set:function(t){this._variablesState=t}},{key:"callStack",get:function(){return this._currentFlow.callStack}},{key:"evaluationStack",get:function(){return this._evaluationStack}},{key:"currentTurnIndex",get:function(){return this._currentTurnIndex},set:function(t){this._currentTurnIndex=t}},{key:"currentPathString",get:function(){var t=this.currentPointer;return t.isNull?null:null===t.path?L("pointer.path"):t.path.toString()}},{key:"currentPointer",get:function(){return this.callStack.currentElement.currentPointer.copy()},set:function(t){this.callStack.currentElement.currentPointer=t.copy()}},{key:"previousPointer",get:function(){return this.callStack.currentThread.previousPointer.copy()},set:function(t){this.callStack.currentThread.previousPointer=t.copy()}},{key:"canContinue",get:function(){return!this.currentPointer.isNull&&!this.hasError}},{key:"hasError",get:function(){return null!=this.currentErrors&&this.currentErrors.length>0}},{key:"hasWarning",get:function(){return null!=this.currentWarnings&&this.currentWarnings.length>0}},{key:"currentText",get:function(){if(this._outputStreamTextDirty){var t,e=new j,n=S(this.outputStream);try{for(n.s();!(t=n.n()).done;){var r=_(t.value,$);null!==r&&e.Append(r.value)}}catch(t){n.e(t)}finally{n.f()}this._currentText=this.CleanOutputWhitespace(e.toString()),this._outputStreamTextDirty=!1}return this._currentText}},{key:"CleanOutputWhitespace",value:function(t){for(var e=new j,n=-1,r=0,i=0;i<t.length;i++){var a=t.charAt(i),o=" "==a||"\t"==a;o&&-1==n&&(n=i),o||("\n"!=a&&n>0&&n!=r&&e.Append(" "),n=-1),"\n"==a&&(r=i+1),o||e.Append(a)}return e.toString()}},{key:"currentTags",get:function(){if(this._outputStreamTagsDirty){this._currentTags=[];var t,e=S(this.outputStream);try{for(e.s();!(t=e.n()).done;){var n=_(t.value,ce);null!==n&&this._currentTags.push(n.text)}}catch(t){e.e(t)}finally{e.f()}this._outputStreamTagsDirty=!1}return this._currentTags}},{key:"currentFlowName",get:function(){return this._currentFlow.name}},{key:"inExpressionEvaluation",get:function(){return this.callStack.currentElement.inExpressionEvaluation},set:function(t){this.callStack.currentElement.inExpressionEvaluation=t}},{key:"GoToStart",value:function(){this.callStack.currentElement.currentPointer=dt.StartOf(this.story.mainContentContainer)}},{key:"SwitchFlow_Internal",value:function(t){if(null===t)throw new Error("Must pass a non-null string to Story.SwitchFlow");if(null===this._namedFlows&&(this._namedFlows=new Map,this._namedFlows.set(this.kDefaultFlowName,this._currentFlow)),t!==this._currentFlow.name){var e,n=q(this._namedFlows,t,null);n.exists?e=n.result:(e=new Se(t,this.story),this._namedFlows.set(t,e)),this._currentFlow=e,this.variablesState.callStack=this._currentFlow.callStack,this.OutputStreamDirty()}}},{key:"SwitchToDefaultFlow_Internal",value:function(){null!==this._namedFlows&&this.SwitchFlow_Internal(this.kDefaultFlowName)}},{key:"RemoveFlow_Internal",value:function(t){if(null===t)throw new Error("Must pass a non-null string to Story.DestroyFlow");if(t===this.kDefaultFlowName)throw new Error("Cannot destroy default flow");if(this._currentFlow.name===t&&this.SwitchToDefaultFlow_Internal(),null===this._namedFlows)return L("this._namedFlows");this._namedFlows.delete(t)}},{key:"CopyAndStartPatching",value:function(){var t,n,r,i,a,o=new e(this.story);if(o._patch=new ye(this._patch),o._currentFlow.name=this._currentFlow.name,o._currentFlow.callStack=new ve(this._currentFlow.callStack),(t=o._currentFlow.currentChoices).push.apply(t,y(this._currentFlow.currentChoices)),(n=o._currentFlow.outputStream).push.apply(n,y(this._currentFlow.outputStream)),o.OutputStreamDirty(),null!==this._namedFlows){o._namedFlows=new Map;var s,l=S(this._namedFlows);try{for(l.s();!(s=l.n()).done;){var u=m(s.value,2),c=u[0],h=u[1];o._namedFlows.set(c,h)}}catch(t){l.e(t)}finally{l.f()}o._namedFlows.set(this._currentFlow.name,o._currentFlow)}this.hasError&&(o._currentErrors=[],(i=o._currentErrors).push.apply(i,y(this.currentErrors||[])));this.hasWarning&&(o._currentWarnings=[],(a=o._currentWarnings).push.apply(a,y(this.currentWarnings||[])));return o.variablesState=this.variablesState,o.variablesState.callStack=o.callStack,o.variablesState.patch=o._patch,(r=o.evaluationStack).push.apply(r,y(this.evaluationStack)),this.divertedPointer.isNull||(o.divertedPointer=this.divertedPointer.copy()),o.previousPointer=this.previousPointer.copy(),o._visitCounts=this._visitCounts,o._turnIndices=this._turnIndices,o.currentTurnIndex=this.currentTurnIndex,o.storySeed=this.storySeed,o.previousRandom=this.previousRandom,o.didSafeExit=this.didSafeExit,o}},{key:"RestoreAfterPatch",value:function(){this.variablesState.callStack=this.callStack,this.variablesState.patch=this._patch}},{key:"ApplyAnyPatch",value:function(){if(null!==this._patch){this.variablesState.ApplyPatch();var t,e=S(this._patch.visitCounts);try{for(e.s();!(t=e.n()).done;){var n=m(t.value,2),r=n[0],i=n[1];this.ApplyCountChanges(r,i,!0)}}catch(t){e.e(t)}finally{e.f()}var a,o=S(this._patch.turnIndices);try{for(o.s();!(a=o.n()).done;){var s=m(a.value,2),l=s[0],u=s[1];this.ApplyCountChanges(l,u,!1)}}catch(t){o.e(t)}finally{o.f()}this._patch=null}}},{key:"ApplyCountChanges",value:function(t,e,n){(n?this._visitCounts:this._turnIndices).set(t.path.toString(),e)}},{key:"WriteJson",value:function(e){var n=this;if(e.WriteObjectStart(),e.WritePropertyStart("flows"),e.WriteObjectStart(),null!==this._namedFlows){var r,i=S(this._namedFlows);try{var a=function(){var t=m(r.value,2),n=t[0],i=t[1];e.WriteProperty(n,(function(t){return i.WriteJson(t)}))};for(i.s();!(r=i.n()).done;)a()}catch(t){i.e(t)}finally{i.f()}}else e.WriteProperty(this._currentFlow.name,(function(t){return n._currentFlow.WriteJson(t)}));if(e.WriteObjectEnd(),e.WritePropertyEnd(),e.WriteProperty("currentFlowName",this._currentFlow.name),e.WriteProperty("variablesState",(function(t){return n.variablesState.WriteJson(t)})),e.WriteProperty("evalStack",(function(t){return de.WriteListRuntimeObjs(t,n.evaluationStack)})),!this.divertedPointer.isNull){if(null===this.divertedPointer.path)return L("divertedPointer");e.WriteProperty("currentDivertTarget",this.divertedPointer.path.componentsString)}e.WriteProperty("visitCounts",(function(t){return de.WriteIntDictionary(t,n._visitCounts)})),e.WriteProperty("turnIndices",(function(t){return de.WriteIntDictionary(t,n._turnIndices)})),e.WriteIntProperty("turnIdx",this.currentTurnIndex),e.WriteIntProperty("storySeed",this.storySeed),e.WriteIntProperty("previousRandom",this.previousRandom),e.WriteIntProperty("inkSaveVersion",this.kInkSaveStateVersion),e.WriteIntProperty("inkFormatVersion",t.Story.inkVersionCurrent),e.WriteObjectEnd()}},{key:"LoadJsonObj",value:function(t){var e=t,n=e.inkSaveVersion;if(null==n)throw new Error("ink save format incorrect, can't load.");if(parseInt(n)<this.kMinCompatibleLoadVersion)throw new Error("Ink save format isn't compatible with the current version (saw '"+n+"', but minimum is "+this.kMinCompatibleLoadVersion+"), so can't load.");var r=e.flows;if(null!=r){var i=r;1===Object.keys(i).length?this._namedFlows=null:null===this._namedFlows?this._namedFlows=new Map:this._namedFlows.clear();for(var a=0,o=Object.entries(i);a<o.length;a++){var s=m(o[a],2),l=s[0],u=s[1],c=new Se(l,this.story,u);if(1===Object.keys(i).length)this._currentFlow=new Se(l,this.story,u);else{if(null===this._namedFlows)return L("this._namedFlows");this._namedFlows.set(l,c)}}if(null!=this._namedFlows&&this._namedFlows.size>1){var h=e.currentFlowName;this._currentFlow=this._namedFlows.get(h)}}else{this._namedFlows=null,this._currentFlow.name=this.kDefaultFlowName,this._currentFlow.callStack.SetJsonToken(e.callstackThreads,this.story),this._currentFlow.outputStream=de.JArrayToRuntimeObjList(e.outputStream),this._currentFlow.currentChoices=de.JArrayToRuntimeObjList(e.currentChoices);var f=e.choiceThreads;this._currentFlow.LoadFlowChoiceThreads(f,this.story)}this.OutputStreamDirty(),this.variablesState.SetJsonToken(e.variablesState),this.variablesState.callStack=this._currentFlow.callStack,this._evaluationStack=de.JArrayToRuntimeObjList(e.evalStack);var d=e.currentDivertTarget;if(null!=d){var v=new R(d.toString());this.divertedPointer=this.story.PointerAtPath(v)}this._visitCounts=de.JObjectToIntDictionary(e.visitCounts),this._turnIndices=de.JObjectToIntDictionary(e.turnIndices),this.currentTurnIndex=parseInt(e.turnIdx),this.storySeed=parseInt(e.storySeed),this.previousRandom=parseInt(e.previousRandom)}},{key:"ResetErrors",value:function(){this._currentErrors=null,this._currentWarnings=null}},{key:"ResetOutput",value:function(){var t,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;this.outputStream.length=0,null!==e&&(t=this.outputStream).push.apply(t,y(e)),this.OutputStreamDirty()}},{key:"PushToOutputStream",value:function(t){var e=_(t,$);if(null!==e){var n=this.TrySplittingHeadTailWhitespace(e);if(null!==n){var r,i=S(n);try{for(i.s();!(r=i.n()).done;){var a=r.value;this.PushToOutputStreamIndividual(a)}}catch(t){i.e(t)}finally{i.f()}return void this.OutputStreamDirty()}}this.PushToOutputStreamIndividual(t),this.OutputStreamDirty()}},{key:"PopFromOutputStream",value:function(t){this.outputStream.splice(this.outputStream.length-t,t),this.OutputStreamDirty()}},{key:"TrySplittingHeadTailWhitespace",value:function(t){var e=t.value;if(null===e)return L("single.value");for(var n=-1,r=-1,i=0;i<e.length;i++){var a=e[i];if("\n"!=a){if(" "==a||"\t"==a)continue;break}-1==n&&(n=i),r=i}for(var o=-1,s=-1,l=e.length-1;l>=0;l--){var u=e[l];if("\n"!=u){if(" "==u||"\t"==u)continue;break}-1==o&&(o=l),s=l}if(-1==n&&-1==o)return null;var c=[],h=0,f=e.length;if(-1!=n){if(n>0){var d=new $(e.substring(0,n));c.push(d)}c.push(new $("\n")),h=r+1}if(-1!=o&&(f=s),f>h){var v=e.substring(h,f-h);c.push(new $(v))}if(-1!=o&&s>r&&(c.push(new $("\n")),o<e.length-1)){var p=e.length-o-1,m=new $(e.substring(o+1,p));c.push(m)}return c}},{key:"PushToOutputStreamIndividual",value:function(t){var e=_(t,ne),n=_(t,$),r=!0;if(e)this.TrimNewlinesFromOutputStream(),r=!0;else if(n){var i=-1,a=this.callStack.currentElement;a.type==ct.Function&&(i=a.functionStartInOutputStream);for(var o=-1,s=this.outputStream.length-1;s>=0;s--){var l=this.outputStream[s],u=l instanceof et?l:null;if(null!=(l instanceof ne?l:null)){o=s;break}if(null!=u&&u.commandType==et.CommandType.BeginString){s>=i&&(i=-1);break}}if(-1!=(-1!=o&&-1!=i?Math.min(i,o):-1!=o?o:i)){if(n.isNewline)r=!1;else if(n.isNonWhitespace&&(o>-1&&this.RemoveExistingGlue(),i>-1))for(var c=this.callStack.elements,h=c.length-1;h>=0;h--){var f=c[h];if(f.type!=ct.Function)break;f.functionStartInOutputStream=-1}}else n.isNewline&&(!this.outputStreamEndsInNewline&&this.outputStreamContainsContent||(r=!1))}if(r){if(null===t)return L("obj");this.outputStream.push(t),this.OutputStreamDirty()}}},{key:"TrimNewlinesFromOutputStream",value:function(){for(var t=-1,e=this.outputStream.length-1;e>=0;){var n=this.outputStream[e],r=_(n,et),i=_(n,$);if(null!=r||null!=i&&i.isNonWhitespace)break;null!=i&&i.isNewline&&(t=e),e--}if(t>=0)for(e=t;e<this.outputStream.length;){_(this.outputStream[e],$)?this.outputStream.splice(e,1):e++}this.OutputStreamDirty()}},{key:"RemoveExistingGlue",value:function(){for(var t=this.outputStream.length-1;t>=0;t--){var e=this.outputStream[t];if(e instanceof ne)this.outputStream.splice(t,1);else if(e instanceof et)break}this.OutputStreamDirty()}},{key:"outputStreamEndsInNewline",get:function(){if(this.outputStream.length>0)for(var t=this.outputStream.length-1;t>=0;t--){if(this.outputStream[t]instanceof et)break;var e=this.outputStream[t];if(e instanceof $){if(e.isNewline)return!0;if(e.isNonWhitespace)break}}return!1}},{key:"outputStreamContainsContent",get:function(){var t,e=S(this.outputStream);try{for(e.s();!(t=e.n()).done;){if(t.value instanceof $)return!0}}catch(t){e.e(t)}finally{e.f()}return!1}},{key:"inStringEvaluation",get:function(){for(var t=this.outputStream.length-1;t>=0;t--){var e=_(this.outputStream[t],et);if(e instanceof et&&e.commandType==et.CommandType.BeginString)return!0}return!1}},{key:"PushEvaluationStack",value:function(t){var e=_(t,Z);if(e){var n=e.value;if(null===n)return L("rawList");if(null!=n.originNames){n.origins||(n.origins=[]),n.origins.length=0;var r,i=S(n.originNames);try{for(i.s();!(r=i.n()).done;){var a=r.value;if(null===this.story.listDefinitions)return L("StoryState.story.listDefinitions");var o=this.story.listDefinitions.TryListGetDefinition(a,null);if(null===o.result)return L("StoryState def.result");n.origins.indexOf(o.result)<0&&n.origins.push(o.result)}}catch(t){i.e(t)}finally{i.f()}}}if(null===t)return L("obj");this.evaluationStack.push(t)}},{key:"PopEvaluationStack",value:function(t){if(void 0===t)return P(this.evaluationStack.pop());if(t>this.evaluationStack.length)throw new Error("trying to pop too many objects");return P(this.evaluationStack.splice(this.evaluationStack.length-t,t))}},{key:"PeekEvaluationStack",value:function(){return this.evaluationStack[this.evaluationStack.length-1]}},{key:"ForceEnd",value:function(){this.callStack.Reset(),this._currentFlow.currentChoices.length=0,this.currentPointer=dt.Null,this.previousPointer=dt.Null,this.didSafeExit=!0}},{key:"TrimWhitespaceFromFunctionEnd",value:function(){I.Assert(this.callStack.currentElement.type==ct.Function);var t=this.callStack.currentElement.functionStartInOutputStream;-1==t&&(t=0);for(var e=this.outputStream.length-1;e>=t;e--){var n=this.outputStream[e],r=_(n,$),i=_(n,et);if(null!=r){if(i)break;if(!r.isNewline&&!r.isInlineWhitespace)break;this.outputStream.splice(e,1),this.OutputStreamDirty()}}}},{key:"PopCallStack",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;this.callStack.currentElement.type==ct.Function&&this.TrimWhitespaceFromFunctionEnd(),this.callStack.Pop(t)}},{key:"SetChosenPath",value:function(t,e){this._currentFlow.currentChoices.length=0;var n=this.story.PointerAtPath(t);n.isNull||-1!=n.index||(n.index=0),this.currentPointer=n,e&&this.currentTurnIndex++}},{key:"StartFunctionEvaluationFromGame",value:function(t,e){this.callStack.Push(ct.FunctionEvaluationFromGame,this.evaluationStack.length),this.callStack.currentElement.currentPointer=dt.StartOf(t),this.PassArgumentsToEvaluationStack(e)}},{key:"PassArgumentsToEvaluationStack",value:function(t){if(null!==t)for(var e=0;e<t.length;e++){if("number"!=typeof t[e]&&"string"!=typeof t[e]||t[e]instanceof B)throw new Error((P(arguments[e]),"null"));this.PushEvaluationStack(K.Create(t[e]))}}},{key:"TryExitFunctionEvaluationFromGame",value:function(){return this.callStack.currentElement.type==ct.FunctionEvaluationFromGame&&(this.currentPointer=dt.Null,this.didSafeExit=!0,!0)}},{key:"CompleteFunctionEvaluationFromGame",value:function(){if(this.callStack.currentElement.type!=ct.FunctionEvaluationFromGame)throw new Error("Expected external function evaluation to be complete. Stack trace: "+this.callStack.callStackTrace);for(var t=this.callStack.currentElement.evaluationStackHeightWhenPushed,e=null;this.evaluationStack.length>t;){var n=this.PopEvaluationStack();null===e&&(e=n)}if(this.PopCallStack(ct.FunctionEvaluationFromGame),e){if(e instanceof rt)return null;var r=A(e,K);return r.valueType==U.DivertTarget?r.valueObject.toString():r.valueObject}return null}},{key:"AddError",value:function(t,e){e?(null==this._currentWarnings&&(this._currentWarnings=[]),this._currentWarnings.push(t)):(null==this._currentErrors&&(this._currentErrors=[]),this._currentErrors.push(t))}},{key:"OutputStreamDirty",value:function(){this._outputStreamTextDirty=!0,this._outputStreamTagsDirty=!0}}]),e}(),we=function(){function t(){n(this,t),this.startTime=void 0}return i(t,[{key:"ElapsedMilliseconds",get:function(){return void 0===this.startTime?0:(new Date).getTime()-this.startTime}},{key:"Start",value:function(){this.startTime=(new Date).getTime()}},{key:"Stop",value:function(){this.startTime=void 0}}]),t}();!function(t){t[t.Author=0]="Author",t[t.Warning=1]="Warning",t[t.Error=2]="Error"}(Ce||(Ce={})),Number.isInteger||(Number.isInteger=function(t){return"number"==typeof t&&isFinite(t)&&t>-9007199254740992&&t<9007199254740992&&Math.floor(t)===t}),t.Story=function(t){a(o,t);var r=d(o);function o(){var t,e;n(this,o),(t=r.call(this)).inkVersionMinimumCompatible=18,t.onError=null,t.onDidContinue=null,t.onMakeChoice=null,t.onEvaluateFunction=null,t.onCompleteEvaluateFunction=null,t.onChoosePathString=null,t._prevContainers=[],t.allowExternalFunctionFallbacks=!1,t._listDefinitions=null,t._variableObservers=null,t._hasValidatedExternals=!1,t._temporaryEvaluationContainer=null,t._asyncContinueActive=!1,t._stateSnapshotAtLastNewline=null,t._sawLookaheadUnsafeFunctionAfterNewline=!1,t._recursiveContinueCount=0,t._asyncSaving=!1,t._profiler=null;var i=null,a=null;if(arguments[0]instanceof tt)e=arguments[0],void 0!==arguments[1]&&(i=arguments[1]),t._mainContentContainer=e;else if("string"==typeof arguments[0]){var s=arguments[0];a=ge.TextToDictionary(s)}else a=arguments[0];if(null!=i&&(t._listDefinitions=new fe(i)),t._externals=new Map,null!==a){var l=a,u=l.inkVersion;if(null==u)throw new Error("ink version number not found. Are you sure it's a valid .ink.json file?");var c=parseInt(u);if(c>o.inkVersionCurrent)throw new Error("Version of ink used to build story was newer than the current version of the engine");if(c<t.inkVersionMinimumCompatible)throw new Error("Version of ink used to build story is too old to be loaded by this version of the engine");c!=o.inkVersionCurrent&&console.warn("WARNING: Version of ink used to build story doesn't match current version of engine. Non-critical, but recommend synchronising.");var h,f=l.root;if(null==f)throw new Error("Root node for ink not found. Are you sure it's a valid .ink.json file?");(h=l.listDefs)&&(t._listDefinitions=de.JTokenToListDefinitions(h)),t._mainContentContainer=A(de.JTokenToRuntimeObject(f),tt),t.ResetState()}return t}return i(o,[{key:"currentChoices",get:function(){var t=[];if(null===this._state)return L("this._state");var e,n=S(this._state.currentChoices);try{for(n.s();!(e=n.n()).done;){var r=e.value;r.isInvisibleDefault||(r.index=t.length,t.push(r))}}catch(t){n.e(t)}finally{n.f()}return t}},{key:"currentText",get:function(){return this.IfAsyncWeCant("call currentText since it's a work in progress"),this.state.currentText}},{key:"currentTags",get:function(){return this.IfAsyncWeCant("call currentTags since it's a work in progress"),this.state.currentTags}},{key:"currentErrors",get:function(){return this.state.currentErrors}},{key:"currentWarnings",get:function(){return this.state.currentWarnings}},{key:"currentFlowName",get:function(){return this.state.currentFlowName}},{key:"hasError",get:function(){return this.state.hasError}},{key:"hasWarning",get:function(){return this.state.hasWarning}},{key:"variablesState",get:function(){return this.state.variablesState}},{key:"listDefinitions",get:function(){return this._listDefinitions}},{key:"state",get:function(){return this._state}},{key:"StartProfiling",value:function(){}},{key:"EndProfiling",value:function(){}},{key:"ToJson",value:function(t){var e=this,n=!1;if(t||(n=!0,t=new ge.Writer),t.WriteObjectStart(),t.WriteIntProperty("inkVersion",o.inkVersionCurrent),t.WriteProperty("root",(function(t){return de.WriteRuntimeContainer(t,e._mainContentContainer)})),null!=this._listDefinitions){t.WritePropertyStart("listDefs"),t.WriteObjectStart();var r,i=S(this._listDefinitions.lists);try{for(i.s();!(r=i.n()).done;){var a=r.value;t.WritePropertyStart(a.name),t.WriteObjectStart();var s,l=S(a.items);try{for(l.s();!(s=l.n()).done;){var u=m(s.value,2),c=u[0],h=u[1],f=M.fromSerializedKey(c),d=h;t.WriteIntProperty(f.itemName,d)}}catch(t){l.e(t)}finally{l.f()}t.WriteObjectEnd(),t.WritePropertyEnd()}}catch(t){i.e(t)}finally{i.f()}t.WriteObjectEnd(),t.WritePropertyEnd()}if(t.WriteObjectEnd(),n)return t.toString()}},{key:"ResetState",value:function(){this.IfAsyncWeCant("ResetState"),this._state=new be(this),this._state.variablesState.ObserveVariableChange(this.VariableStateDidChangeEvent.bind(this)),this.ResetGlobals()}},{key:"ResetErrors",value:function(){if(null===this._state)return L("this._state");this._state.ResetErrors()}},{key:"ResetCallstack",value:function(){if(this.IfAsyncWeCant("ResetCallstack"),null===this._state)return L("this._state");this._state.ForceEnd()}},{key:"ResetGlobals",value:function(){if(this._mainContentContainer.namedContent.get("global decl")){var t=this.state.currentPointer.copy();this.ChoosePath(new R("global decl"),!1),this.ContinueInternal(),this.state.currentPointer=t}this.state.variablesState.SnapshotDefaultGlobals()}},{key:"SwitchFlow",value:function(t){if(this.IfAsyncWeCant("switch flow"),this._asyncSaving)throw new Error("Story is already in background saving mode, can't switch flow to "+t);this.state.SwitchFlow_Internal(t)}},{key:"RemoveFlow",value:function(t){this.state.RemoveFlow_Internal(t)}},{key:"SwitchToDefaultFlow",value:function(){this.state.SwitchToDefaultFlow_Internal()}},{key:"Continue",value:function(){return this.ContinueAsync(0),this.currentText}},{key:"canContinue",get:function(){return this.state.canContinue}},{key:"asyncContinueComplete",get:function(){return!this._asyncContinueActive}},{key:"ContinueAsync",value:function(t){this._hasValidatedExternals||this.ValidateExternalBindings(),this.ContinueInternal(t)}},{key:"ContinueInternal",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;null!=this._profiler&&this._profiler.PreContinue();var e=t>0;if(this._recursiveContinueCount++,!this._asyncContinueActive){if(this._asyncContinueActive=e,!this.canContinue)throw new Error("Can't continue - should check canContinue before calling Continue");this._state.didSafeExit=!1,this._state.ResetOutput(),1==this._recursiveContinueCount&&(this._state.variablesState.batchObservingVariableChanges=!0)}var n=new we;n.Start();var r=!1;this._sawLookaheadUnsafeFunctionAfterNewline=!1;do{try{r=this.ContinueSingleStep()}catch(t){if(!(t instanceof G))throw t;this.AddError(t.message,void 0,t.useEndLineNumber);break}if(r)break;if(this._asyncContinueActive&&n.ElapsedMilliseconds>t)break}while(this.canContinue);if(n.Stop(),!r&&this.canContinue||(null!==this._stateSnapshotAtLastNewline&&this.RestoreStateSnapshot(),this.canContinue||(this.state.callStack.canPopThread&&this.AddError("Thread available to pop, threads should always be flat by the end of evaluation?"),0!=this.state.generatedChoices.length||this.state.didSafeExit||null!=this._temporaryEvaluationContainer||(this.state.callStack.CanPop(ct.Tunnel)?this.AddError("unexpectedly reached end of content. Do you need a '->->' to return from a tunnel?"):this.state.callStack.CanPop(ct.Function)?this.AddError("unexpectedly reached end of content. Do you need a '~ return'?"):this.state.callStack.canPop?this.AddError("unexpectedly reached end of content for unknown reason. Please debug compiler!"):this.AddError("ran out of content. Do you need a '-> DONE' or '-> END'?"))),this.state.didSafeExit=!1,this._sawLookaheadUnsafeFunctionAfterNewline=!1,1==this._recursiveContinueCount&&(this._state.variablesState.batchObservingVariableChanges=!1),this._asyncContinueActive=!1,null!==this.onDidContinue&&this.onDidContinue()),this._recursiveContinueCount--,null!=this._profiler&&this._profiler.PostContinue(),this.state.hasError||this.state.hasWarning){if(null===this.onError){var i=new j;throw i.Append("Ink had "),this.state.hasError&&(i.Append("".concat(this.state.currentErrors.length)),i.Append(1==this.state.currentErrors.length?" error":"errors"),this.state.hasWarning&&i.Append(" and ")),this.state.hasWarning&&(i.Append("".concat(this.state.currentWarnings.length)),i.Append(1==this.state.currentWarnings.length?" warning":"warnings"),this.state.hasWarning&&i.Append(" and ")),i.Append(". It is strongly suggested that you assign an error handler to story.onError. The first issue was: "),i.Append(this.state.hasError?this.state.currentErrors[0]:this.state.currentWarnings[0]),new G(i.toString())}if(this.state.hasError){var a,o=S(this.state.currentErrors);try{for(o.s();!(a=o.n()).done;){var s=a.value;this.onError(s,Ce.Error)}}catch(s){o.e(s)}finally{o.f()}}if(this.state.hasWarning){var l,u=S(this.state.currentWarnings);try{for(u.s();!(l=u.n()).done;){var c=l.value;this.onError(c,Ce.Warning)}}catch(s){u.e(s)}finally{u.f()}}this.ResetErrors()}}},{key:"ContinueSingleStep",value:function(){if(null!=this._profiler&&this._profiler.PreStep(),this.Step(),null!=this._profiler&&this._profiler.PostStep(),this.canContinue||this.state.callStack.elementIsEvaluateFromGame||this.TryFollowDefaultInvisibleChoice(),null!=this._profiler&&this._profiler.PreSnapshot(),!this.state.inStringEvaluation){if(null!==this._stateSnapshotAtLastNewline){if(null===this._stateSnapshotAtLastNewline.currentTags)return L("this._stateAtLastNewline.currentTags");if(null===this.state.currentTags)return L("this.state.currentTags");var t=this.CalculateNewlineOutputStateChange(this._stateSnapshotAtLastNewline.currentText,this.state.currentText,this._stateSnapshotAtLastNewline.currentTags.length,this.state.currentTags.length);if(t==o.OutputStateChange.ExtendedBeyondNewline||this._sawLookaheadUnsafeFunctionAfterNewline)return this.RestoreStateSnapshot(),!0;t==o.OutputStateChange.NewlineRemoved&&this.DiscardSnapshot()}this.state.outputStreamEndsInNewline&&(this.canContinue?null==this._stateSnapshotAtLastNewline&&this.StateSnapshot():this.DiscardSnapshot())}return null!=this._profiler&&this._profiler.PostSnapshot(),!1}},{key:"CalculateNewlineOutputStateChange",value:function(t,e,n,r){if(null===t)return L("prevText");if(null===e)return L("currText");var i=e.length>=t.length&&"\n"==e.charAt(t.length-1);if(n==r&&t.length==e.length&&i)return o.OutputStateChange.NoChange;if(!i)return o.OutputStateChange.NewlineRemoved;if(r>n)return o.OutputStateChange.ExtendedBeyondNewline;for(var a=t.length;a<e.length;a++){var s=e.charAt(a);if(" "!=s&&"\t"!=s)return o.OutputStateChange.ExtendedBeyondNewline}return o.OutputStateChange.NoChange}},{key:"ContinueMaximally",value:function(){this.IfAsyncWeCant("ContinueMaximally");for(var t=new j;this.canContinue;)t.Append(this.Continue());return t.toString()}},{key:"ContentAtPath",value:function(t){return this.mainContentContainer.ContentAtPath(t)}},{key:"KnotContainerWithName",value:function(t){var e=this.mainContentContainer.namedContent.get(t);return e instanceof tt?e:null}},{key:"PointerAtPath",value:function(t){if(0==t.length)return dt.Null;var e=new dt,n=t.length,r=null;return null===t.lastComponent?L("path.lastComponent"):(t.lastComponent.isIndex?(n=t.length-1,r=this.mainContentContainer.ContentAtPath(t,void 0,n),e.container=r.container,e.index=t.lastComponent.index):(r=this.mainContentContainer.ContentAtPath(t),e.container=r.container,e.index=-1),null==r.obj||r.obj==this.mainContentContainer&&n>0?this.Error("Failed to find content at path '"+t+"', and no approximation of it was possible."):r.approximate&&this.Warning("Failed to find content at path '"+t+"', so it was approximated to: '"+r.obj.path+"'."),e)}},{key:"StateSnapshot",value:function(){this._stateSnapshotAtLastNewline=this._state,this._state=this._state.CopyAndStartPatching()}},{key:"RestoreStateSnapshot",value:function(){null===this._stateSnapshotAtLastNewline&&L("_stateSnapshotAtLastNewline"),this._stateSnapshotAtLastNewline.RestoreAfterPatch(),this._state=this._stateSnapshotAtLastNewline,this._stateSnapshotAtLastNewline=null,this._asyncSaving||this._state.ApplyAnyPatch()}},{key:"DiscardSnapshot",value:function(){this._asyncSaving||this._state.ApplyAnyPatch(),this._stateSnapshotAtLastNewline=null}},{key:"CopyStateForBackgroundThreadSave",value:function(){if(this.IfAsyncWeCant("start saving on a background thread"),this._asyncSaving)throw new Error("Story is already in background saving mode, can't call CopyStateForBackgroundThreadSave again!");var t=this._state;return this._state=this._state.CopyAndStartPatching(),this._asyncSaving=!0,t}},{key:"BackgroundSaveComplete",value:function(){null===this._stateSnapshotAtLastNewline&&this._state.ApplyAnyPatch(),this._asyncSaving=!1}},{key:"Step",value:function(){var t=!0,e=this.state.currentPointer.copy();if(!e.isNull){for(var n=_(e.Resolve(),tt);n&&(this.VisitContainer(n,!0),0!=n.content.length);)n=_((e=dt.StartOf(n)).Resolve(),tt);this.state.currentPointer=e.copy(),null!=this._profiler&&this._profiler.Step(this.state.callStack);var r=e.Resolve(),i=this.PerformLogicAndFlowControl(r);if(!this.state.currentPointer.isNull){i&&(t=!1);var a=_(r,ht);if(a){var o=this.ProcessChoice(a);o&&this.state.generatedChoices.push(o),r=null,t=!1}if(r instanceof tt&&(t=!1),t){var s=_(r,Y);if(s&&-1==s.contextIndex){var l=this.state.callStack.ContextForVariableNamed(s.variableName);r=new Y(s.variableName,l)}this.state.inExpressionEvaluation?this.state.PushEvaluationStack(r):this.state.PushToOutputStream(r)}this.NextContent();var u=_(r,et);u&&u.commandType==et.CommandType.StartThread&&this.state.callStack.PushThread()}}}},{key:"VisitContainer",value:function(t,e){t.countingAtStartOnly&&!e||(t.visitsShouldBeCounted&&this.state.IncrementVisitCountForContainer(t),t.turnIndexShouldBeCounted&&this.state.RecordTurnIndexVisitToContainer(t))}},{key:"VisitChangedContainersDueToDivert",value:function(){var t=this.state.previousPointer.copy(),e=this.state.currentPointer.copy();if(!e.isNull&&-1!=e.index){if(this._prevContainers.length=0,!t.isNull)for(var n=_(t.Resolve(),tt)||_(t.container,tt);n;)this._prevContainers.push(n),n=_(n.parent,tt);var r=e.Resolve();if(null!=r)for(var i=_(r.parent,tt),a=!0;i&&(this._prevContainers.indexOf(i)<0||i.countingAtStartOnly);){var o=i.content.length>0&&r==i.content[0]&&a;o||(a=!1),this.VisitContainer(i,o),r=i,i=_(i.parent,tt)}}}},{key:"ProcessChoice",value:function(t){var e=!0;if(t.hasCondition){var n=this.state.PopEvaluationStack();this.IsTruthy(n)||(e=!1)}var r="",i="";t.hasChoiceOnlyContent&&(i=A(this.state.PopEvaluationStack(),$).value||"");t.hasStartContent&&(r=A(this.state.PopEvaluationStack(),$).value||"");t.onceOnly&&(this.state.VisitCountForContainer(t.choiceTarget)>0&&(e=!1));if(!e)return null;var a=new he;return a.targetPath=t.pathOnChoice,a.sourcePath=t.path.toString(),a.isInvisibleDefault=t.isInvisibleDefault,a.threadAtGeneration=this.state.callStack.ForkThread(),a.text=(r+i).replace(/^[ \t]+|[ \t]+$/g,""),a}},{key:"IsTruthy",value:function(t){if(t instanceof K){var e=t;if(e instanceof X){var n=e;return this.Error("Shouldn't use a divert target (to "+n.targetPath+") as a conditional value. Did you intend a function call 'likeThis()' or a read count check 'likeThis'? (no arrows)"),!1}return e.isTruthy}return!1}},{key:"PerformLogicAndFlowControl",value:function(t){if(null==t)return!1;if(t instanceof vt){var e=t;if(e.isConditional){var n=this.state.PopEvaluationStack();if(!this.IsTruthy(n))return!0}if(e.hasVariableTarget){var r=e.variableDivertName,i=this.state.variablesState.GetVariableWithName(r);if(null==i)this.Error("Tried to divert using a target from a variable that could not be found ("+r+")");else if(!(i instanceof X)){var a=_(i,J),o="Tried to divert to a target from a variable, but the variable ("+r+") didn't contain a divert target, it ";a instanceof J&&0==a.value?o+="was empty/null (the value 0).":o+="contained '"+i+"'.",this.Error(o)}var s=A(i,X);this.state.divertedPointer=this.PointerAtPath(s.targetPath)}else{if(e.isExternal)return this.CallExternalFunction(e.targetPathString,e.externalArgs),!0;this.state.divertedPointer=e.targetPointer.copy()}return e.pushesToStack&&this.state.callStack.Push(e.stackPushType,void 0,this.state.outputStream.length),this.state.divertedPointer.isNull&&!e.isExternal&&(e&&e.debugMetadata&&null!=e.debugMetadata.sourceName?this.Error("Divert target doesn't exist: "+e.debugMetadata.sourceName):this.Error("Divert resolution failed: "+e)),!0}if(t instanceof et){var l=t;switch(l.commandType){case et.CommandType.EvalStart:this.Assert(!1===this.state.inExpressionEvaluation,"Already in expression evaluation?"),this.state.inExpressionEvaluation=!0;break;case et.CommandType.EvalEnd:this.Assert(!0===this.state.inExpressionEvaluation,"Not in expression evaluation mode"),this.state.inExpressionEvaluation=!1;break;case et.CommandType.EvalOutput:if(this.state.evaluationStack.length>0){var u=this.state.PopEvaluationStack();if(!(u instanceof rt)){var c=new $(u.toString());this.state.PushToOutputStream(c)}}break;case et.CommandType.NoOp:break;case et.CommandType.Duplicate:this.state.PushEvaluationStack(this.state.PeekEvaluationStack());break;case et.CommandType.PopEvaluatedValue:this.state.PopEvaluationStack();break;case et.CommandType.PopFunction:case et.CommandType.PopTunnel:var h=l.commandType==et.CommandType.PopFunction?ct.Function:ct.Tunnel,f=null;if(h==ct.Tunnel){var d=this.state.PopEvaluationStack();null===(f=_(d,X))&&this.Assert(d instanceof rt,"Expected void if ->-> doesn't override target")}if(this.state.TryExitFunctionEvaluationFromGame())break;if(this.state.callStack.currentElement.type==h&&this.state.callStack.canPop)this.state.PopCallStack(),f&&(this.state.divertedPointer=this.PointerAtPath(f.targetPath));else{var v=new Map;v.set(ct.Function,"function return statement (~ return)"),v.set(ct.Tunnel,"tunnel onwards statement (->->)");var p=v.get(this.state.callStack.currentElement.type);this.state.callStack.canPop||(p="end of flow (-> END or choice)");var m="Found "+v.get(h)+", when expected "+p;this.Error(m)}break;case et.CommandType.BeginString:this.state.PushToOutputStream(l),this.Assert(!0===this.state.inExpressionEvaluation,"Expected to be in an expression when evaluating a string"),this.state.inExpressionEvaluation=!1;break;case et.CommandType.EndString:for(var y=[],g=0,C=this.state.outputStream.length-1;C>=0;--C){var b=this.state.outputStream[C];g++;var w=_(b,et);if(w&&w.commandType==et.CommandType.BeginString)break;b instanceof $&&y.push(b)}this.state.PopFromOutputStream(g),y=y.reverse();var k,E=new j,T=S(y);try{for(T.s();!(k=T.n()).done;){var P=k.value;E.Append(P.toString())}}catch(t){T.e(t)}finally{T.f()}this.state.inExpressionEvaluation=!0,this.state.PushEvaluationStack(new $(E.toString()));break;case et.CommandType.ChoiceCount:var x=this.state.generatedChoices.length;this.state.PushEvaluationStack(new J(x));break;case et.CommandType.Turns:this.state.PushEvaluationStack(new J(this.state.currentTurnIndex+1));break;case et.CommandType.TurnsSince:case et.CommandType.ReadCount:var N=this.state.PopEvaluationStack();if(!(N instanceof X)){var O="";N instanceof J&&(O=". Did you accidentally pass a read count ('knot_name') instead of a target ('-> knot_name')?"),this.Error("TURNS_SINCE / READ_COUNT expected a divert target (knot, stitch, label name), but saw "+N+O);break}var I,W=A(N,X),F=_(this.ContentAtPath(W.targetPath).correctObj,tt);null!=F?I=l.commandType==et.CommandType.TurnsSince?this.state.TurnsSinceForContainer(F):this.state.VisitCountForContainer(F):(I=l.commandType==et.CommandType.TurnsSince?-1:0,this.Warning("Failed to find container for "+l.toString()+" lookup at "+W.targetPath.toString())),this.state.PushEvaluationStack(new J(I));break;case et.CommandType.Random:var R=_(this.state.PopEvaluationStack(),J),D=_(this.state.PopEvaluationStack(),J);if(null==D||D instanceof J==!1)return this.Error("Invalid value for minimum parameter of RANDOM(min, max)");if(null==R||D instanceof J==!1)return this.Error("Invalid value for maximum parameter of RANDOM(min, max)");if(null===R.value)return L("maxInt.value");if(null===D.value)return L("minInt.value");var V=R.value-D.value+1;(!isFinite(V)||V>Number.MAX_SAFE_INTEGER)&&(V=Number.MAX_SAFE_INTEGER,this.Error("RANDOM was called with a range that exceeds the size that ink numbers can use.")),V<=0&&this.Error("RANDOM was called with minimum as "+D.value+" and maximum as "+R.value+". The maximum must be larger");var q=this.state.storySeed+this.state.previousRandom,U=new me(q).next(),H=U%V+D.value;this.state.PushEvaluationStack(new J(H)),this.state.previousRandom=U;break;case et.CommandType.SeedRandom:var z=_(this.state.PopEvaluationStack(),J);if(null==z||z instanceof J==!1)return this.Error("Invalid value passed to SEED_RANDOM");if(null===z.value)return L("minInt.value");this.state.storySeed=z.value,this.state.previousRandom=0,this.state.PushEvaluationStack(new rt);break;case et.CommandType.VisitIndex:var Y=this.state.VisitCountForContainer(this.state.currentPointer.container)-1;this.state.PushEvaluationStack(new J(Y));break;case et.CommandType.SequenceShuffleIndex:var Q=this.NextSequenceShuffleIndex();this.state.PushEvaluationStack(new J(Q));break;case et.CommandType.StartThread:break;case et.CommandType.Done:this.state.callStack.canPopThread?this.state.callStack.PopThread():(this.state.didSafeExit=!0,this.state.currentPointer=dt.Null);break;case et.CommandType.End:this.state.ForceEnd();break;case et.CommandType.ListFromInt:var nt=_(this.state.PopEvaluationStack(),J),at=A(this.state.PopEvaluationStack(),$);if(null===nt)throw new G("Passed non-integer when creating a list element from a numerical value.");var ot=null;if(null===this.listDefinitions)return L("this.listDefinitions");var st=this.listDefinitions.TryListGetDefinition(at.value,null);if(!st.exists)throw new G("Failed to find LIST called "+at.value);if(null===nt.value)return L("minInt.value");var lt=st.result.TryGetItemWithValue(nt.value,M.Null);lt.exists&&(ot=new Z(lt.result,nt.value)),null==ot&&(ot=new Z),this.state.PushEvaluationStack(ot);break;case et.CommandType.ListRange:var ut=_(this.state.PopEvaluationStack(),K),ht=_(this.state.PopEvaluationStack(),K),ft=_(this.state.PopEvaluationStack(),Z);if(null===ft||null===ht||null===ut)throw new G("Expected list, minimum and maximum for LIST_RANGE");if(null===ft.value)return L("targetList.value");var mt=ft.value.ListWithSubRange(ht.valueObject,ut.valueObject);this.state.PushEvaluationStack(new Z(mt));break;case et.CommandType.ListRandom:var yt=this.state.PopEvaluationStack();if(null===yt)throw new G("Expected list for LIST_RANDOM");var gt=yt.value,Ct=null;if(null===gt)throw L("list");if(0==gt.Count)Ct=new B;else{for(var St=this.state.storySeed+this.state.previousRandom,bt=new me(St).next(),wt=bt%gt.Count,kt=gt.entries(),Et=0;Et<=wt-1;Et++)kt.next();var _t=kt.next().value,At={Key:M.fromSerializedKey(_t[0]),Value:_t[1]};if(null===At.Key.originName)return L("randomItem.Key.originName");(Ct=new B(At.Key.originName,this)).Add(At.Key,At.Value),this.state.previousRandom=bt}this.state.PushEvaluationStack(new Z(Ct));break;default:this.Error("unhandled ControlCommand: "+l)}return!0}if(t instanceof pt){var Tt=t,Pt=this.state.PopEvaluationStack();return this.state.variablesState.Assign(Tt,Pt),!0}if(t instanceof Wt){var xt=t,Nt=null;if(null!=xt.pathForCount){var Ot=xt.containerForCount,It=this.state.VisitCountForContainer(Ot);Nt=new J(It)}else null==(Nt=this.state.variablesState.GetVariableWithName(xt.name))&&(this.Warning("Variable not found: '"+xt.name+"'. Using default value of 0 (false). This can happen with temporary variables if the declaration hasn't yet been hit. Globals are always given a default value on load if a value doesn't exist in the save state."),Nt=new J(0));return this.state.PushEvaluationStack(Nt),!0}if(t instanceof it){var Ft=t,Rt=this.state.PopEvaluationStack(Ft.numberOfParameters),Dt=Ft.Call(Rt);return this.state.PushEvaluationStack(Dt),!0}return!1}},{key:"ChoosePathString",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];if(this.IfAsyncWeCant("call ChoosePathString right now"),null!==this.onChoosePathString&&this.onChoosePathString(t,n),e)this.ResetCallstack();else if(this.state.callStack.currentElement.type==ct.Function){var r="",i=this.state.callStack.currentElement.currentPointer.container;throw null!=i&&(r="("+i.path.toString()+") "),new Error("Story was running a function "+r+"when you called ChoosePathString("+t+") - this is almost certainly not not what you want! Full stack trace: \n"+this.state.callStack.callStackTrace)}this.state.PassArgumentsToEvaluationStack(n),this.ChoosePath(new R(t))}},{key:"IfAsyncWeCant",value:function(t){if(this._asyncContinueActive)throw new Error("Can't "+t+". Story is in the middle of a ContinueAsync(). Make more ContinueAsync() calls or a single Continue() call beforehand.")}},{key:"ChoosePath",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.state.SetChosenPath(t,e),this.VisitChangedContainersDueToDivert()}},{key:"ChooseChoiceIndex",value:function(t){t=t;var e=this.currentChoices;this.Assert(t>=0&&t<e.length,"choice out of range");var n=e[t];return null!==this.onMakeChoice&&this.onMakeChoice(n),null===n.threadAtGeneration?L("choiceToChoose.threadAtGeneration"):null===n.targetPath?L("choiceToChoose.targetPath"):(this.state.callStack.currentThread=n.threadAtGeneration,void this.ChoosePath(n.targetPath))}},{key:"HasFunction",value:function(t){try{return null!=this.KnotContainerWithName(t)}catch(t){return!1}}},{key:"EvaluateFunction",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(null!==this.onEvaluateFunction&&this.onEvaluateFunction(t,e),this.IfAsyncWeCant("evaluate a function"),null==t)throw new Error("Function is null");if(""==t||""==t.trim())throw new Error("Function is empty or white space.");var r=this.KnotContainerWithName(t);if(null==r)throw new Error("Function doesn't exist: '"+t+"'");var i=[];i.push.apply(i,y(this.state.outputStream)),this._state.ResetOutput(),this.state.StartFunctionEvaluationFromGame(r,e);for(var a=new j;this.canContinue;)a.Append(this.Continue());var o=a.toString();this._state.ResetOutput(i);var s=this.state.CompleteFunctionEvaluationFromGame();return null!=this.onCompleteEvaluateFunction&&this.onCompleteEvaluateFunction(t,e,o,s),n?{returned:s,output:o}:s}},{key:"EvaluateExpression",value:function(t){var e=this.state.callStack.elements.length;this.state.callStack.Push(ct.Tunnel),this._temporaryEvaluationContainer=t,this.state.GoToStart();var n=this.state.evaluationStack.length;return this.Continue(),this._temporaryEvaluationContainer=null,this.state.callStack.elements.length>e&&this.state.PopCallStack(),this.state.evaluationStack.length>n?this.state.PopEvaluationStack():null}},{key:"CallExternalFunction",value:function(t,n){if(null===t)return L("funcName");var r=this._externals.get(t),i=null,a=void 0!==r;if(!a||r.lookAheadSafe||null===this._stateSnapshotAtLastNewline){if(!a){if(this.allowExternalFunctionFallbacks)return i=this.KnotContainerWithName(t),this.Assert(null!==i,"Trying to call EXTERNAL function '"+t+"' which has not been bound, and fallback ink function could not be found."),this.state.callStack.Push(ct.Function,void 0,this.state.outputStream.length),void(this.state.divertedPointer=dt.StartOf(i));this.Assert(!1,"Trying to call EXTERNAL function '"+t+"' which has not been bound (and ink fallbacks disabled).")}for(var o=[],s=0;s<n;++s){var l=A(this.state.PopEvaluationStack(),K).valueObject;o.push(l)}o.reverse();var u=r.function(o),c=null;null!=u?(c=K.Create(u),this.Assert(null!==c,"Could not create ink value from returned object of type "+e(u))):c=new rt,this.state.PushEvaluationStack(c)}else this._sawLookaheadUnsafeFunctionAfterNewline=!0}},{key:"BindExternalFunctionGeneral",value:function(t,e,n){this.IfAsyncWeCant("bind an external function"),this.Assert(!this._externals.has(t),"Function '"+t+"' has already been bound."),this._externals.set(t,{function:e,lookAheadSafe:n})}},{key:"TryCoerce",value:function(t){return t}},{key:"BindExternalFunction",value:function(t,e,n){var r=this;this.Assert(null!=e,"Can't bind a null function"),this.BindExternalFunctionGeneral(t,(function(t){r.Assert(t.length>=e.length,"External function expected "+e.length+" arguments");for(var n=[],i=0,a=t.length;i<a;i++)n[i]=r.TryCoerce(t[i]);return e.apply(null,n)}),n)}},{key:"UnbindExternalFunction",value:function(t){this.IfAsyncWeCant("unbind an external a function"),this.Assert(this._externals.has(t),"Function '"+t+"' has not been bound."),this._externals.delete(t)}},{key:"ValidateExternalBindings",value:function(){var t=null,e=null,n=arguments[1]||new Set;if(arguments[0]instanceof tt&&(t=arguments[0]),arguments[0]instanceof V&&(e=arguments[0]),null===t&&null===e)if(this.ValidateExternalBindings(this._mainContentContainer,n),this._hasValidatedExternals=!0,0==n.size)this._hasValidatedExternals=!0;else{var r="Error: Missing function binding for external";r+=n.size>1?"s":"",r+=": '",r+=Array.from(n).join("', '"),r+="' ",r+=this.allowExternalFunctionFallbacks?", and no fallback ink function found.":" (ink fallbacks disabled)",this.Error(r)}else if(null!=t){var i,a=S(t.content);try{for(a.s();!(i=a.n()).done;){var o=i.value,s=o;null!=s&&s.hasValidName||this.ValidateExternalBindings(o,n)}}catch(t){a.e(t)}finally{a.f()}var l,u=S(t.namedContent);try{for(u.s();!(l=u.n()).done;){var c=m(l.value,2),h=c[1];this.ValidateExternalBindings(_(h,V),n)}}catch(t){u.e(t)}finally{u.f()}}else if(null!=e){var f=_(e,vt);if(f&&f.isExternal){var d=f.targetPathString;if(null===d)return L("name");if(!this._externals.has(d))if(this.allowExternalFunctionFallbacks){var v=this.mainContentContainer.namedContent.has(d);v||n.add(d)}else n.add(d)}}}},{key:"ObserveVariable",value:function(t,e){if(this.IfAsyncWeCant("observe a new variable"),null===this._variableObservers&&(this._variableObservers=new Map),!this.state.variablesState.GlobalVariableExistsWithName(t))throw new Error("Cannot observe variable '"+t+"' because it wasn't declared in the ink story.");this._variableObservers.has(t)?this._variableObservers.get(t).push(e):this._variableObservers.set(t,[e])}},{key:"ObserveVariables",value:function(t,e){for(var n=0,r=t.length;n<r;n++)this.ObserveVariable(t[n],e[n])}},{key:"RemoveVariableObserver",value:function(t,e){if(this.IfAsyncWeCant("remove a variable observer"),null!==this._variableObservers)if(null!=e){if(this._variableObservers.has(e))if(null!=t){var n=this._variableObservers.get(e);null!=n&&(n.splice(n.indexOf(t),1),0===n.length&&this._variableObservers.delete(e))}else this._variableObservers.delete(e)}else if(null!=t){var r,i=S(this._variableObservers.keys());try{for(i.s();!(r=i.n()).done;){var a=r.value,o=this._variableObservers.get(a);null!=o&&(o.splice(o.indexOf(t),1),0===o.length&&this._variableObservers.delete(a))}}catch(t){i.e(t)}finally{i.f()}}}},{key:"VariableStateDidChangeEvent",value:function(t,e){if(null!==this._variableObservers){var n=this._variableObservers.get(t);if(void 0!==n){if(!(e instanceof K))throw new Error("Tried to get the value of a variable that isn't a standard type");var r,i=A(e,K),a=S(n);try{for(a.s();!(r=a.n()).done;){(0,r.value)(t,i.valueObject)}}catch(t){a.e(t)}finally{a.f()}}}}},{key:"globalTags",get:function(){return this.TagsAtStartOfFlowContainerWithPathString("")}},{key:"TagsForContentAtPath",value:function(t){return this.TagsAtStartOfFlowContainerWithPathString(t)}},{key:"TagsAtStartOfFlowContainerWithPathString",value:function(t){var e=new R(t),n=this.ContentAtPath(e).container;if(null===n)return L("flowContainer");for(;;){var r=n.content[0];if(!(r instanceof tt))break;n=r}var i,a=null,o=S(n.content);try{for(o.s();!(i=o.n()).done;){var s=_(i.value,ce);if(!s)break;null==a&&(a=[]),a.push(s.text)}}catch(t){o.e(t)}finally{o.f()}return a}},{key:"BuildStringOfHierarchy",value:function(){var t=new j;return this.mainContentContainer.BuildStringOfHierarchy(t,0,this.state.currentPointer.Resolve()),t.toString()}},{key:"BuildStringOfContainer",value:function(t){var e=new j;return t.BuildStringOfHierarchy(e,0,this.state.currentPointer.Resolve()),e.toString()}},{key:"NextContent",value:function(){if((this.state.previousPointer=this.state.currentPointer.copy(),this.state.divertedPointer.isNull||(this.state.currentPointer=this.state.divertedPointer.copy(),this.state.divertedPointer=dt.Null,this.VisitChangedContainersDueToDivert(),this.state.currentPointer.isNull))&&!this.IncrementContentPointer()){var t=!1;this.state.callStack.CanPop(ct.Function)?(this.state.PopCallStack(ct.Function),this.state.inExpressionEvaluation&&this.state.PushEvaluationStack(new rt),t=!0):this.state.callStack.canPopThread?(this.state.callStack.PopThread(),t=!0):this.state.TryExitFunctionEvaluationFromGame(),t&&!this.state.currentPointer.isNull&&this.NextContent()}}},{key:"IncrementContentPointer",value:function(){var t=!0,e=this.state.callStack.currentElement.currentPointer.copy();if(e.index++,null===e.container)return L("pointer.container");for(;e.index>=e.container.content.length;){t=!1;var n=_(e.container.parent,tt);if(n instanceof tt==!1)break;var r=n.content.indexOf(e.container);if(-1==r)break;if((e=new dt(n,r)).index++,t=!0,null===e.container)return L("pointer.container")}return t||(e=dt.Null),this.state.callStack.currentElement.currentPointer=e.copy(),t}},{key:"TryFollowDefaultInvisibleChoice",value:function(){var t=this._state.currentChoices,e=t.filter((function(t){return t.isInvisibleDefault}));if(0==e.length||t.length>e.length)return!1;var n=e[0];return null===n.targetPath?L("choice.targetPath"):null===n.threadAtGeneration?L("choice.threadAtGeneration"):(this.state.callStack.currentThread=n.threadAtGeneration,null!==this._stateSnapshotAtLastNewline&&(this.state.callStack.currentThread=this.state.callStack.ForkThread()),this.ChoosePath(n.targetPath,!1),!0)}},{key:"NextSequenceShuffleIndex",value:function(){var t=_(this.state.PopEvaluationStack(),J);if(!(t instanceof J))return this.Error("expected number of elements in sequence for shuffle index"),0;var e=this.state.currentPointer.container;if(null===e)return L("seqContainer");if(null===t.value)return L("numElementsIntVal.value");var n=t.value,r=A(this.state.PopEvaluationStack(),J).value;if(null===r)return L("seqCount");for(var i=r/n,a=r%n,o=e.path.toString(),s=0,l=0,u=o.length;l<u;l++)s+=o.charCodeAt(l)||0;for(var c=s+i+this.state.storySeed,h=new me(Math.floor(c)),f=[],d=0;d<n;++d)f.push(d);for(var v=0;v<=a;++v){var p=h.next()%f.length,m=f[p];if(f.splice(p,1),v==a)return m}throw new Error("Should never reach here")}},{key:"Error",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=new G(t);throw n.useEndLineNumber=e,n}},{key:"Warning",value:function(t){this.AddError(t,!0)}},{key:"AddError",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=this.currentDebugMetadata,i=e?"WARNING":"ERROR";if(null!=r){var a=n?r.endLineNumber:r.startLineNumber;t="RUNTIME "+i+": '"+r.fileName+"' line "+a+": "+t}else t=this.state.currentPointer.isNull?"RUNTIME "+i+": "+t:"RUNTIME "+i+": ("+this.state.currentPointer+"): "+t;this.state.AddError(t,e),e||this.state.ForceEnd()}},{key:"Assert",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;if(0==t)throw null==e&&(e="Story assert"),new Error(e+" "+this.currentDebugMetadata)}},{key:"currentDebugMetadata",get:function(){var t,e=this.state.currentPointer;if(!e.isNull&&null!==e.Resolve()&&null!==(t=e.Resolve().debugMetadata))return t;for(var n=this.state.callStack.elements.length-1;n>=0;--n)if(!(e=this.state.callStack.elements[n].currentPointer).isNull&&null!==e.Resolve()&&null!==(t=e.Resolve().debugMetadata))return t;for(var r=this.state.outputStream.length-1;r>=0;--r){if(null!==(t=this.state.outputStream[r].debugMetadata))return t}return null}},{key:"mainContentContainer",get:function(){return this._temporaryEvaluationContainer?this._temporaryEvaluationContainer:this._mainContentContainer}}]),o}(V),t.Story.inkVersionCurrent=20,function(t){var e;(e=t.OutputStateChange||(t.OutputStateChange={}))[e.NoChange=0]="NoChange",e[e.ExtendedBeyondNewline=1]="ExtendedBeyondNewline",e[e.NewlineRemoved=2]="NewlineRemoved"}(t.Story||(t.Story={}));var ke=function(e){a(s,e);var r=d(s);function s(e){var i,a=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return n(this,s),(i=r.call(this,null,e,null,!1,a))._errorHandler=null,i._hadError=!1,i._hadWarning=!1,i._dontFlattenContainers=new Set,i._listDefs=new Map,i.constants=new Map,i.externals=new Map,i.countAllVisits=!1,i.ExportRuntime=function(){var e,n,r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;i._errorHandler=r,i.constants=new Map;var a,o=S(i.FindAll(_t)());try{for(o.s();!(a=o.n()).done;){var s=a.value,l=i.constants.get(s.constantName);if(l&&!l.Equals(s.expression)){var u="CONST '".concat(s.constantName,"' has been redefined with a different value. Multiple definitions of the same CONST are valid so long as they contain the same value. Initial definition was on ").concat(l.debugMetadata,".");i.Error(u,s,!1)}i.constants.set(s.constantName,s.expression)}}catch(t){o.e(t)}finally{o.f()}i._listDefs=new Map;var c,f=S(i.FindAll(Ht)());try{for(f.s();!(c=f.n()).done;){var d=c.value;(null===(e=d.identifier)||void 0===e?void 0:e.name)&&i._listDefs.set(null===(n=d.identifier)||void 0===n?void 0:n.name,d)}}catch(t){f.e(t)}finally{f.f()}i.externals=new Map,i.ResolveWeavePointNaming();var v=i.runtimeObject,p=new tt;p.AddContent(et.EvalStart());var y,g=[],C=S(i.variableDeclarations);try{for(C.s();!(y=C.n()).done;){var b=m(y.value,2),w=b[0],k=b[1];if(k.isGlobalDeclaration){if(k.listDefinition)i._listDefs.set(w,k.listDefinition),p.AddContent(k.listDefinition.runtimeObject),g.push(k.listDefinition.runtimeListDefinition);else{if(!k.expression)throw new Error;k.expression.GenerateIntoContainer(p)}var E=new pt(w,!0);E.isGlobal=!0,p.AddContent(E)}}}catch(t){C.e(t)}finally{C.f()}p.AddContent(et.EvalEnd()),p.AddContent(et.End()),i.variableDeclarations.size>0&&(p.name="global decl",v.AddToNamedContentOnly(p)),v.AddContent(et.Done());var _=new t.Story(v,g);return i.runtimeObject=_,i.hadError?null:(i.FlattenContainersIn(v),i.ResolveReferences(h(i)),i.hadError?null:(_.ResetState(),_))},i.ResolveList=function(t){var e=i._listDefs.get(t);return e||null},i.ResolveListItem=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=null;if(t)return(r=i._listDefs.get(t))?r.ItemNamed(e):null;var a,o=null,s=null,l=S(i._listDefs.entries());try{for(l.s();!(a=l.n()).done;){var u=m(a.value,2),c=u[1],h=c.ItemNamed(e);h&&(o?i.Error("Ambiguous item name '".concat(e,"' found in multiple sets, including ").concat(s.identifier," and ").concat(c.identifier),n,!1):(o=h,s=c))}}catch(t){l.e(t)}finally{l.f()}return o},i.FlattenContainersIn=function(t){var e=new Set;if(t.content){var n,r=S(t.content);try{for(r.s();!(n=r.n()).done;){var a=_(n.value,tt);a&&e.add(a)}}catch(t){r.e(t)}finally{r.f()}}if(t.namedContent){var o,s=S(t.namedContent);try{for(s.s();!(o=s.n()).done;){var l=_(m(o.value,2)[1],tt);l&&e.add(l)}}catch(t){s.e(t)}finally{s.f()}}var u,c=S(e);try{for(c.s();!(u=c.n()).done;){var h=u.value;i.TryFlattenContainer(h),i.FlattenContainersIn(h)}}catch(t){c.e(t)}finally{c.f()}},i.TryFlattenContainer=function(t){if(!(t.namedContent&&t.namedContent.size>0||t.hasValidName||i._dontFlattenContainers.has(t))){var e=_(t.parent,tt);if(e){var n=e.content.indexOf(t);e.content.splice(n,1);var r=t.ownDebugMetadata;if(t.content){var a,o=S(t.content);try{for(o.s();!(a=o.n()).done;){var s=a.value;s.parent=null,null!==r&&null===s.ownDebugMetadata&&(s.debugMetadata=r),e.InsertContent(s,n),n+=1}}catch(t){o.e(t)}finally{o.f()}}}}},i.Error=function(t,e,n){var r=n?b.Warning:b.Error,a="";if(e instanceof F?(a+="TODO: ",r=b.Author):a+=n?"WARNING: ":"ERROR: ",e&&null!==e.debugMetadata&&e.debugMetadata.startLineNumber>=1&&(null!=e.debugMetadata.fileName&&(a+="'".concat(e.debugMetadata.fileName,"' ")),a+="line ".concat(e.debugMetadata.startLineNumber,": ")),t=a+=t,null===i._errorHandler)throw new Error(t);i._errorHandler(t,r),i._hadError=r===b.Error,i._hadWarning=r===b.Warning},i.ResetError=function(){i._hadError=!1,i._hadWarning=!1},i.IsExternal=function(t){return i.externals.has(t)},i.AddExternal=function(t){i.externals.has(t.name)?i.Error("Duplicate EXTERNAL definition of '".concat(t.name,"'"),t,!1):t.name&&i.externals.set(t.name,t)},i.DontFlattenContainer=function(t){i._dontFlattenContainers.add(t)},i.NameConflictError=function(t,e,n,r){t.Error("".concat(r," '").concat(e,"': name has already been used for a ").concat(n.typeName.toLowerCase()," on ").concat(n.debugMetadata))},i.CheckForNamingCollisions=function(t,e,n){var r,a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"",o=a||t.typeName;if(s.IsReservedKeyword(null==e?void 0:e.name))t.Error("'".concat(e,"' cannot be used for the name of a ").concat(o.toLowerCase()," because it's a reserved keyword"));else if(Rt.IsBuiltIn((null==e?void 0:e.name)||""))t.Error("'".concat(e,"' cannot be used for the name of a ").concat(o.toLowerCase()," because it's a built in function"));else{var l=i.ContentWithNameAtLevel((null==e?void 0:e.name)||"",bt.Knot),u=_(l,Ot);if(!u||u===t&&n!==ft.Arg){if(!(n<ft.List)){var c,h=S(i._listDefs);try{for(h.s();!(c=h.n()).done;){var f=m(c.value,2),d=f[0],v=f[1];if((null==e?void 0:e.name)===d&&t!==v&&v.variableAssignment!==t&&i.NameConflictError(t,null==e?void 0:e.name,v,o),!(t instanceof le)){var p,y=S(v.itemDefinitions);try{for(y.s();!(p=y.n()).done;){var g=p.value;(null==e?void 0:e.name)===g.name&&i.NameConflictError(t,(null==e?void 0:e.name)||"",g,o)}}catch(t){y.e(t)}finally{y.f()}}}}catch(t){h.e(t)}finally{h.f()}if(!(n<=ft.Var)){var C=(null==e?void 0:e.name)&&i.variableDeclarations.get(null==e?void 0:e.name)||null;if(C&&C!==t&&C.isGlobalDeclaration&&null==C.listDefinition&&i.NameConflictError(t,(null==e?void 0:e.name)||"",C,o),!(n<ft.SubFlowAndWeave)){var b=new Tt(e),w=b.ResolveFromContext(t);if(w&&w!==t)i.NameConflictError(t,(null==e?void 0:e.name)||"",w,o);else if(!(n<ft.Arg)&&n!==ft.Arg){var k=_(t,Ot);if(k||(k=xt(t)),k&&k.hasParameters&&k.args){var E,A=S(k.args);try{for(A.s();!(E=A.n()).done;){var T=E.value;if((null===(r=T.identifier)||void 0===r?void 0:r.name)===(null==e?void 0:e.name))return void t.Error("".concat(o," '").concat(e,"': name has already been used for a argument to ").concat(k.identifier," on ").concat(k.debugMetadata))}}catch(t){A.e(t)}finally{A.f()}}}}}}}else i.NameConflictError(t,(null==e?void 0:e.name)||"",u,o)}},i}return i(s,[{key:"flowLevel",get:function(){return bt.Story}},{key:"hadError",get:function(){return this._hadError}},{key:"hadWarning",get:function(){return this._hadWarning}},{key:"typeName",get:function(){return"Story"}},{key:"PreProcessTopLevelObjects",value:function(t){p(o(s.prototype),"PreProcessTopLevelObjects",this).call(this,t);var e,n=[],r=S(t);try{for(r.s();!(e=r.n()).done;){var i=e.value;if(i instanceof ie){var a=i,l=t.indexOf(i);if(t.splice(l,1),a.includedStory){var u=[],c=a.includedStory;if(null!=c.content){var h,f=S(c.content);try{for(f.s();!(h=f.n()).done;){var d=h.value;d instanceof Ot?n.push(d):u.push(d)}}catch(t){f.e(t)}finally{f.f()}u.push(new Et("\n")),t.splice.apply(t,[l,0].concat(u))}}}else;}}catch(t){r.e(t)}finally{r.f()}t.splice.apply(t,[0,0].concat(n))}}]),s}(Ot);ke.IsReservedKeyword=function(t){switch(t){case"true":case"false":case"not":case"return":case"else":case"VAR":case"CONST":case"temp":case"LIST":case"function":return!0}return!1};var Ee=function(t){a(r,t);var e=d(r);function r(t){var i;return n(this,r),(i=e.call(this)).GenerateIntoContainer=function(t){t.AddContent(et.BeginString());var e,n=S(i.content);try{for(n.s();!(e=n.n()).done;){var r=e.value;t.AddContent(r.runtimeObject)}}catch(t){n.e(t)}finally{n.f()}t.AddContent(et.EndString())},i.toString=function(){var t,e="",n=S(i.content);try{for(n.s();!(t=n.n()).done;){e+=t.value}}catch(t){n.e(t)}finally{n.f()}return e},i.AddContent(t),i}return i(r,[{key:"isSingleString",get:function(){return 1===this.content.length&&this.content[0]instanceof Et}},{key:"typeName",get:function(){return"String"}},{key:"Equals",value:function(t){var e=_(t,r);return null!==e&&(!(!this.isSingleString||!e.isSingleString)&&this.toString()===e.toString())}}]),r}(nt),_e=function(t){a(r,t);var e=d(r);function r(t){return n(this,r),e.call(this,t)}return i(r,[{key:"typeName",get:function(){return"Tag"}}]),r}(te),Ae=i((function t(e){n(this,t),this.rootPath=e,this.ResolveInkFilename=function(){throw Error("Can't resolve filename because no FileHandler was provided when instantiating the parser / compiler.")},this.LoadInkFileContents=function(){throw Error("Can't load ink content because no FileHandler was provided when instantiating the parser / compiler.")}})),Te=function(t){a(o,t);var r=d(o);function o(t){var i,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,l=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,u=arguments.length>4&&void 0!==arguments[4]?arguments[4]:null;if(n(this,o),(i=r.call(this,t)).ParseStory=function(){var t=i.StatementsAtLevel(Xt.Top);return new ke(t,i._rootParser!==h(i))},i.SeparatedList=function(t,e){var n=i.Parse(t);if(null===n)return null;var r=[];for(r.push(n);;){var a=i.BeginRule();if(null===e()){i.FailRule(a);break}var o=i.Parse(t);if(null===o){i.FailRule(a);break}i.SucceedRule(a),r.push(o)}return r},i.CreateDebugMetadata=function(t,e){var n=new Yt;return n.startLineNumber=((null==t?void 0:t.lineIndex)||0)+1,n.endLineNumber=e.lineIndex+1,n.startCharacterNumber=((null==t?void 0:t.characterInLineIndex)||0)+1,n.endCharacterNumber=e.characterInLineIndex+1,n.fileName=i._filename,n},i.RuleDidSucceed=function(t,e,n){var r=_(t,W);r&&(r.debugMetadata=i.CreateDebugMetadata(e,n));var a=Array.isArray(t)?t:null;if(null!==a){var o,s=S(a);try{for(s.s();!(o=s.n()).done;){var l=o.value;_(l,W)&&(l.hasOwnDebugMetadata||(l.debugMetadata=i.CreateDebugMetadata(e,n)))}}catch(t){s.e(t)}finally{s.f()}}var u=_(t,Nt);null!=u&&(u.debugMetadata=i.CreateDebugMetadata(e,n))},i.OnStringParserError=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],a=r?"WARNING:":"ERROR:",o=a;if(null!==i._filename&&(o+=" '".concat(i._filename,"'")),o+=" line ".concat(n+1,": ").concat(t),null===i._externalErrorHandler)throw new Error(o);i._externalErrorHandler(o,r?b.Warning:b.Error)},i.AuthorWarning=function(){i.Whitespace();var t=i.Parse(i.IdentifierWithMetadata);if(null===t||"TODO"!==t.name)return null;i.Whitespace(),i.ParseString(":"),i.Whitespace();var e=i.ParseUntilCharactersFromString("\n\r");return e?new F(e):null},i.ExtendIdentifierCharacterRanges=function(t){var e,n=S(o.ListAllCharacterRanges());try{for(n.s();!(e=n.n()).done;){var r=e.value;t.AddCharacters(r.ToCharacterSet())}}catch(t){n.e(t)}finally{n.f()}},i._parsingChoice=!1,i.Choice=function(){var t=!0,e=i.Interleave(i.OptionalExclude(i.Whitespace),i.String("*"));if(!e){if(null===(e=i.Interleave(i.OptionalExclude(i.Whitespace),i.String("+"))))return null;t=!1}var n=i.Parse(i.BracketedName);i.Whitespace();var r=i.Parse(i.ChoiceCondition);if(i.Whitespace(),i._parsingChoice)throw new Error("Already parsing a choice - shouldn't have nested choices");i._parsingChoice=!0;var a=null,o=i.Parse(i.MixedTextAndLogic);o&&(a=new It(o));var s=null,l=null,u=null!==i.ParseString("[");if(u){var c=i.Parse(i.MixedTextAndLogic);null!==c&&(s=new It(c)),i.Expect(i.String("]"),"closing ']' for weave-style option");var h=i.Parse(i.MixedTextAndLogic);null!==h&&(l=new It(h))}i.Whitespace();var f=i.Parse(i.MultiDivert);i._parsingChoice=!1,i.Whitespace();var d=!a&&!l&&!s;d&&null===f&&i.Warning("Choice is completely empty. Interpretting as a default fallback choice. Add a divert arrow to remove this warning: * ->"),a||!u||s||i.Warning("Blank choice - if you intended a default fallback choice, use the `* ->` syntax"),l||(l=new It);var v=i.Parse(i.Tags);if(null!==v&&l.AddContent(v),null!==f){var p,m=S(f);try{for(m.s();!(p=m.n()).done;){var y=p.value,g=_(y,jt);g&&g.isEmpty||l.AddContent(y)}}catch(t){m.e(t)}finally{m.f()}}l.AddContent(new Et("\n"));var C=new mt(a,s,l);return n&&(C.identifier=n),C.indentationDepth=e.length,C.hasWeaveStyleInlineBrackets=u,C.condition=r,C.onceOnly=t,C.isInvisibleDefault=d,C},i.ChoiceCondition=function(){var t=i.Interleave(i.ChoiceSingleCondition,i.ChoiceConditionsSpace);return null===t?null:1===t.length?t[0]:new Lt(t)},i.ChoiceConditionsSpace=function(){return i.Newline(),i.Whitespace(),Ct},i.ChoiceSingleCondition=function(){if(null===i.ParseString("{"))return null;var t=i.Expect(i.Expression,"choice condition inside { }");return i.DisallowIncrement(t),i.Expect(i.String("}"),"closing '}' for choice condition"),t},i.Gather=function(){var t=i.Parse(i.GatherDashes);if(null===t)return null;var e=Number(t),n=i.Parse(i.BracketedName),r=new At(n,e);return i.Newline(),r},i.GatherDashes=function(){i.Whitespace();for(var t=0;null!==i.ParseDashNotArrow();)t+=1,i.Whitespace();return 0===t?null:t},i.ParseDashNotArrow=function(){var t=i.BeginRule();return null===i.ParseString("->")&&"-"===i.ParseSingleCharacter()?i.SucceedRule(t):i.FailRule(t)},i.BracketedName=function(){if(null===i.ParseString("("))return null;i.Whitespace();var t=i.Parse(i.IdentifierWithMetadata);return null===t?null:(i.Whitespace(),i.Expect(i.String(")"),"closing ')' for bracketed name"),t)},i.InnerConditionalContent=function(t){if(void 0===t){var e=i.Parse(i.ConditionExpression),n=i.Parse((function(){return i.InnerConditionalContent(e)}));return null===n?null:n}var r,a=null!==t,o=null===i.Parse(i.Newline);if(o&&!a)return null;if(o)r=i.InlineConditionalBranches();else{if(null===(r=i.MultilineConditionalBranches())){if(t){var s=i.StatementsAtLevel(Xt.InnerBlock);if(null!==s){r=[new $t(s)];var l=i.Parse(i.SingleMultilineCondition);l&&(l.isElse||(i.ErrorWithParsedObject("Expected an '- else:' clause here rather than an extra condition",l),l.isElse=!0),r.push(l))}}if(null===r)return null}else if(1===r.length&&r[0].isElse&&t){var u=new $t(null);u.isTrueBranch=!0,r.unshift(u)}if(t)for(var c=!1,h=0;h<r.length;++h){var f=r[h],d=h===r.length-1;f.ownExpression?(f.matchingEquality=!0,c=!0):c&&d?(f.matchingEquality=!0,f.isElse=!0):!d&&r.length>2?i.ErrorWithParsedObject("Only final branch can be an 'else'. Did you miss a ':'?",f):0===h?f.isTrueBranch=!0:f.isElse=!0}else{for(var v=0;v<r.length;++v){var p=r[v],m=v===r.length-1;if(null===p.ownExpression)if(m)p.isElse=!0;else if(p.isElse){var y=r[r.length-1];y.isElse?i.ErrorWithParsedObject("Multiple 'else' cases. Can have a maximum of one, at the end.",y):i.ErrorWithParsedObject("'else' case in conditional should always be the final one",p)}else i.ErrorWithParsedObject("Branch doesn't have condition. Are you missing a ':'? ",p)}1===r.length&&null===r[0].ownExpression&&i.ErrorWithParsedObject("Condition block with no conditions",r[0])}}if(null===r)return null;var g,C=S(r);try{for(C.s();!(g=C.n()).done;){g.value.isInline=o}}catch(t){C.e(t)}finally{C.f()}return new kt(t,r)},i.InlineConditionalBranches=function(){var t=i.Interleave(i.MixedTextAndLogic,i.Exclude(i.String("|")),null,!1);if(null===t||0===t.length)return null;var e=[];if(t.length>2)i.Error("Expected one or two alternatives separated by '|' in inline conditional");else{var n=new $t(t[0]);if(n.isTrueBranch=!0,e.push(n),t.length>1){var r=new $t(t[1]);r.isElse=!0,e.push(r)}}return e},i.MultilineConditionalBranches=function(){i.MultilineWhitespace();var t=i.OneOrMore(i.SingleMultilineCondition);return null===t?null:(i.MultilineWhitespace(),t)},i.SingleMultilineCondition=function(){if(i.Whitespace(),null!==i.ParseString("->")||null===i.ParseString("-"))return null;i.Whitespace();var t=null,e=null!==i.Parse(i.ElseExpression);e||(t=i.Parse(i.ConditionExpression));var n=i.StatementsAtLevel(Xt.InnerBlock);null===t&&null===n&&(i.Error("expected content for the conditional branch following '-'"),n=[new Et("")]),i.MultilineWhitespace();var r=new $t(n);return r.ownExpression=t,r.isElse=e,r},i.ConditionExpression=function(){var t=i.Parse(i.Expression);return null===t?null:(i.DisallowIncrement(t),i.Whitespace(),null===i.ParseString(":")?null:t)},i.ElseExpression=function(){return null===i.ParseString("else")?null:(i.Whitespace(),null===i.ParseString(":")?null:Ct)},i._nonTextPauseCharacters=null,i._nonTextEndCharacters=null,i._notTextEndCharactersChoice=null,i._notTextEndCharactersString=null,i.TrimEndWhitespace=function(t,e){if(t.length>0){var n=t.length-1,r=t[n];if(r instanceof Et){var a=r;a.text=a.text.replace(new RegExp(/[ \t]+$/g),""),e?a.text+=" ":0===a.text.length&&(t.splice(n,1),i.TrimEndWhitespace(t,!1))}}},i.LineOfMixedTextAndLogic=function(){i.Parse(i.Whitespace);var t=i.Parse(i.MixedTextAndLogic),e=!1,n=i.Parse(i.Tags);if(n)if(t){var r,a=S(n);try{for(a.s();!(r=a.n()).done;){var o=r.value;t.push(o)}}catch(t){a.e(t)}finally{a.f()}}else t=n,e=!0;if(!t||!t.length)return null;var s=t[0];return s&&s.text&&s.text.startsWith("return")&&i.Warning("Do you need a '~' before 'return'? If not, perhaps use a glue: <> (since it's lowercase) or rewrite somehow?"),0===t.length?null:(t[t.length-1]instanceof jt||i.TrimEndWhitespace(t,!1),e||t.push(new Et("\n")),i.Expect(i.EndOfLine,"end of line",i.SkipToNextLine),t)},i.MixedTextAndLogic=function(){null!==i.ParseObject(i.Spaced(i.String("~")))&&i.Error("You shouldn't use a '~' here - tildas are for logic that's on its own line. To do inline logic, use { curly braces } instead");var t=i.Interleave(i.Optional(i.ContentText),i.Optional(i.InlineLogicOrGlue));if(!i._parsingChoice){var e,n=i.Parse(i.MultiDivert);if(null!==n)null===t&&(t=[]),i.TrimEndWhitespace(t,!0),(e=t).push.apply(e,y(n))}return t||null},i.ContentText=function(){return i.ContentTextAllowingEscapeChar()},i.ContentTextAllowingEscapeChar=function(){for(var t=null;;){var e=i.Parse(i.ContentTextNoEscape),n=null!==i.ParseString("\\");if(!n&&null===e)break;null===t&&(t=""),null!==e&&(t+=String(e)),n&&(t+=i.ParseSingleCharacter())}return null!==t?new Et(t):null},i.ContentTextNoEscape=function(){null===i._nonTextPauseCharacters&&(i._nonTextPauseCharacters=new lt("-<")),null===i._nonTextEndCharacters&&(i._nonTextEndCharacters=new lt("{}|\n\r\\#"),i._notTextEndCharactersChoice=new lt(i._nonTextEndCharacters),i._notTextEndCharactersChoice.AddCharacters("[]"),i._notTextEndCharactersString=new lt(i._nonTextEndCharacters),i._notTextEndCharactersString.AddCharacters('"'));var t=null;t=i.parsingStringExpression?i._notTextEndCharactersString:i._parsingChoice?i._notTextEndCharactersChoice:i._nonTextEndCharacters;var e=i.ParseUntil((function(){return i.OneOf([i.ParseDivertArrow,i.ParseThreadArrow,i.EndOfLine,i.Glue])}),i._nonTextPauseCharacters,t);return null!==e?e:null},i.MultiDivert=function(){i.Whitespace();var t=[],e=i.Parse(i.StartThread);if(e)return t=[e];var n=i.Interleave(i.ParseDivertArrowOrTunnelOnwards,i.DivertIdentifierWithArguments);if(!n)return null;t=[];for(var r=0;r<n.length;++r){if(r%2==0){if("->->"===n[r]){0===r||r===n.length-1||r===n.length-2||i.Error("Tunnel onwards '->->' must only come at the begining or the start of a divert");var a=new Ut;if(r<n.length-1){var o=_(n[r+1],jt);a.divertAfter=o}t.push(a);break}}else{var s=n[r];r<n.length-1&&(s.isTunnel=!0),t.push(s)}}if(0===t.length&&1===n.length){var l=new jt(null);l.isEmpty=!0,t.push(l),i._parsingChoice||i.Error("Empty diverts (->) are only valid on choices")}return t},i.StartThread=function(){if(i.Whitespace(),null===i.ParseThreadArrow())return null;i.Whitespace();var t=i.Expect(i.DivertIdentifierWithArguments,"target for new thread",(function(){return new jt(null)}));return t.isThread=!0,t},i.DivertIdentifierWithArguments=function(){i.Whitespace();var t=i.Parse(i.DotSeparatedDivertPathComponents);if(!t)return null;i.Whitespace();var e=i.Parse(i.ExpressionFunctionCallArguments);i.Whitespace();var n=new Tt(t);return new jt(n,e)},i.SingleDivert=function(){var t=i.Parse(i.MultiDivert);if(!t)return null;if(1!==t.length)return null;if(t[0]instanceof Ut)return null;var e=t[0];return e.isTunnel?null:e},i.DotSeparatedDivertPathComponents=function(){return i.Interleave(i.Spaced(i.IdentifierWithMetadata),i.Exclude(i.String(".")))},i.ParseDivertArrowOrTunnelOnwards=function(){for(var t=0;null!==i.ParseString("->");)t+=1;return 0===t?null:1===t?"->":(2===t||i.Error("Unexpected number of arrows in divert. Should only have '->' or '->->'"),"->->")},i.ParseDivertArrow=function(){return i.ParseString("->")},i.ParseThreadArrow=function(){return i.ParseString("<-")},i._binaryOperators=[],i._maxBinaryOpLength=0,i.TempDeclarationOrAssignment=function(){i.Whitespace();var t=i.ParseTempKeyword();i.Whitespace();var e=null;if(null===(e=t?i.Expect(i.IdentifierWithMetadata,"variable name"):i.Parse(i.IdentifierWithMetadata)))return null;i.Whitespace();var n=null!==i.ParseString("+"),r=null!==i.ParseString("-");if(n&&r&&i.Error("Unexpected sequence '+-'"),null===i.ParseString("="))return t&&i.Error("Expected '='"),null;var a=i.Expect(i.Expression,"value expression to be assigned");return n||r?new re(e,a,n):new Jt({variableIdentifier:e,assignedExpression:a,isTemporaryNewDeclaration:t})},i.DisallowIncrement=function(t){t instanceof re&&i.Error("Can't use increment/decrement here. It can only be used on a ~ line")},i.ParseTempKeyword=function(){var t=i.BeginRule();return"temp"===i.Parse(i.Identifier)?(i.SucceedRule(t),!0):(i.FailRule(t),!1)},i.ReturnStatement=function(){if(i.Whitespace(),"return"!==i.Parse(i.Identifier))return null;i.Whitespace();var t=i.Parse(i.Expression);return new Pt(t)},i.Expression=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;i.Whitespace();var n=i.ExpressionUnary();if(null===n)return null;i.Whitespace();for(var r=function(){var e=i.BeginRule(),r=i.ParseInfixOperator();if(null!==r&&r.precedence>t){var a="right side of '".concat(r.type,"' expression"),o=i.Expect((function(){return i.ExpressionInfixRight(n,r)}),a);return null===o?(i.FailRule(e),{v:null}):(n=i.SucceedRule(e,o),"continue")}return i.FailRule(e),"break"};;){var a=r();if("continue"!==a){if("break"===a)break;if("object"===e(a))return a.v}}return i.Whitespace(),n},i.ExpressionUnary=function(){var t=i.Parse(i.ExpressionDivertTarget);if(null!==t)return t;var e=i.OneOf([i.String("-"),i.String("!")]);null===e&&(e=i.Parse(i.ExpressionNot)),i.Whitespace();var n=i.OneOf([i.ExpressionList,i.ExpressionParen,i.ExpressionFunctionCall,i.ExpressionVariableName,i.ExpressionLiteral]);if(null===n&&null!==e&&(n=i.ExpressionUnary()),null===n)return null;null!==e&&(n=ot.WithInner(n,e)),i.Whitespace();var r=i.OneOf([i.String("++"),i.String("--")]);if(null!==r){var a="++"===r;if(n instanceof Ft)n=new re(n.identifier,a);else i.Error("can only increment and decrement variables, but saw '".concat(n,"'."))}return n},i.ExpressionNot=function(){var t=i.Identifier();return"not"===t?t:null},i.ExpressionLiteral=function(){return i.OneOf([i.ExpressionFloat,i.ExpressionInt,i.ExpressionBool,i.ExpressionString])},i.ExpressionDivertTarget=function(){i.Whitespace();var t=i.Parse(i.SingleDivert);return!t||t&&t.isThread?null:(i.Whitespace(),new Vt(t))},i.ExpressionInt=function(){var t=i.ParseInt();return null===t?null:new at(t,"int")},i.ExpressionFloat=function(){var t=i.ParseFloat();return null===t?null:new at(t,"float")},i.ExpressionString=function(){if(null===i.ParseString('"'))return null;i.parsingStringExpression=!0;var t=i.Parse(i.MixedTextAndLogic);return i.Expect(i.String('"'),"close quote for string expression"),i.parsingStringExpression=!1,null===t?t=[new Et("")]:t.find((function(t){return t instanceof jt}))&&i.Error("String expressions cannot contain diverts (->)"),new Ee(t)},i.ExpressionBool=function(){var t=i.Parse(i.Identifier);return"true"===t?new at(!0,"bool"):"false"===t?new at(!1,"bool"):null},i.ExpressionFunctionCall=function(){var t=i.Parse(i.IdentifierWithMetadata);if(null===t)return null;i.Whitespace();var e=i.Parse(i.ExpressionFunctionCallArguments);return null===e?null:new Rt(t,e)},i.ExpressionFunctionCallArguments=function(){if(null===i.ParseString("("))return null;var t=i.Exclude(i.String(",")),e=i.Interleave(i.Expression,t);return null===e&&(e=[]),i.Whitespace(),i.Expect(i.String(")"),"closing ')' for function call"),e},i.ExpressionVariableName=function(){var t=i.Interleave(i.IdentifierWithMetadata,i.Exclude(i.Spaced(i.String("."))));return null===t||ke.IsReservedKeyword(t[0].name)?null:new Ft(t)},i.ExpressionParen=function(){if(null===i.ParseString("("))return null;var t=i.Parse(i.Expression);return null===t?null:(i.Whitespace(),i.Expect(i.String(")"),"closing parenthesis ')' for expression"),t)},i.ExpressionInfixRight=function(t,e){if(!t)return null;i.Whitespace();var n=i.Parse((function(){return i.Expression(e.precedence)}));return n?new st(t,n,e.type):null},i.ParseInfixOperator=function(){var t,e=S(i._binaryOperators);try{for(e.s();!(t=e.n()).done;){var n=t.value,r=i.BeginRule();if(null!==i.ParseString(n.type)){if(n.requireWhitespace&&null===i.Whitespace()){i.FailRule(r);continue}return i.SucceedRule(r,n)}i.FailRule(r)}}catch(t){e.e(t)}finally{e.f()}return null},i.ExpressionList=function(){if(i.Whitespace(),null===i.ParseString("("))return null;i.Whitespace();var t=i.SeparatedList(i.ListMember,i.Spaced(i.String(",")));return i.Whitespace(),null===i.ParseString(")")?null:new se(t)},i.ListMember=function(){i.Whitespace();var t=i.Parse(i.IdentifierWithMetadata);if(null===t)return null;if(null!==i.ParseString(".")){var e=i.Expect(i.IdentifierWithMetadata,"element name within the set ".concat(t));t.name+=".".concat(null==e?void 0:e.name)}return i.Whitespace(),t},i.RegisterExpressionOperators=function(){i.RegisterBinaryOperator("&&",1),i.RegisterBinaryOperator("||",1),i.RegisterBinaryOperator("and",1,!0),i.RegisterBinaryOperator("or",1,!0),i.RegisterBinaryOperator("==",2),i.RegisterBinaryOperator(">=",2),i.RegisterBinaryOperator("<=",2),i.RegisterBinaryOperator("<",2),i.RegisterBinaryOperator(">",2),i.RegisterBinaryOperator("!=",2),i.RegisterBinaryOperator("?",3),i.RegisterBinaryOperator("has",3,!0),i.RegisterBinaryOperator("!?",3),i.RegisterBinaryOperator("hasnt",3,!0),i.RegisterBinaryOperator("^",3),i.RegisterBinaryOperator("+",4),i.RegisterBinaryOperator("-",5),i.RegisterBinaryOperator("*",6),i.RegisterBinaryOperator("/",7),i.RegisterBinaryOperator("%",8),i.RegisterBinaryOperator("mod",8,!0)},i.RegisterBinaryOperator=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=new ae(t,e,n);i._binaryOperators.push(r),i._maxBinaryOpLength=Math.max(i._maxBinaryOpLength,t.length)},i._openFilenames=[],i.IncludeStatement=function(){if(i.Whitespace(),null===i.ParseString("INCLUDE"))return null;i.Whitespace();var t=i.Expect((function(){return i.ParseUntilCharactersFromString("\n\r")}),"filename for include statement");t=t.replace(new RegExp(/[ \t]+$/g),"");var e=i.fileHandler.ResolveInkFilename(t);if(i.FilenameIsAlreadyOpen(e))return i.Error("Recursive INCLUDE detected: '".concat(e,"' is already open.")),i.ParseUntilCharactersFromString("\r\n"),new ie(null);i.AddOpenFilename(e);var n=null,r="";try{r=i._rootParser.fileHandler.LoadInkFileContents(e)}catch(e){i.Error("Failed to load: '".concat(t,"'.\nError:").concat(e))}r&&(n=new o(r,t,i._externalErrorHandler,i._rootParser,i.fileHandler).ParseStory());return i.RemoveOpenFilename(e),new ie(n)},i.FilenameIsAlreadyOpen=function(t){return i._rootParser._openFilenames.includes(t)},i.AddOpenFilename=function(t){i._rootParser._openFilenames.push(t)},i.RemoveOpenFilename=function(t){i._rootParser._openFilenames.splice(i._rootParser._openFilenames.indexOf(t),1)},i.KnotDefinition=function(){var t=i.Parse(i.KnotDeclaration);if(null===t)return null;i.Expect(i.EndOfLine,"end of line after knot name definition",i.SkipToNextLine);var e=i.Expect((function(){return i.StatementsAtLevel(Xt.Knot)}),"at least one line within the knot",i.KnotStitchNoContentRecoveryRule);return new oe(t.name,e,t.args,t.isFunction)},i.KnotDeclaration=function(){if(i.Whitespace(),null===i.KnotTitleEquals())return null;i.Whitespace();var t,e=i.Parse(i.IdentifierWithMetadata),n="function"===(null==e?void 0:e.name);n?(i.Expect(i.Whitespace,"whitespace after the 'function' keyword"),t=i.Parse(i.IdentifierWithMetadata)):t=e,null===t&&(i.Error("Expected the name of the ".concat(n?"function":"knot")),t=new Nt("")),i.Whitespace();var r=i.Parse(i.BracketedKnotDeclArguments);return i.Whitespace(),i.Parse(i.KnotTitleEquals),new Qt(t,r,n)},i.KnotTitleEquals=function(){var t=i.ParseCharactersFromString("=");return null===t||t.length<=1?null:t},i.StitchDefinition=function(){var t=i.Parse(i.StitchDeclaration);if(null===t)return null;i.Expect(i.EndOfLine,"end of line after stitch name",i.SkipToNextLine);var e=i.Expect((function(){return i.StatementsAtLevel(Xt.Stitch)}),"at least one line within the stitch",i.KnotStitchNoContentRecoveryRule);return new ue(t.name,e,t.args,t.isFunction)},i.StitchDeclaration=function(){if(i.Whitespace(),null===i.ParseString("="))return null;if(null!==i.ParseString("="))return null;i.Whitespace();var t=null!==i.ParseString("function");t&&i.Whitespace();var e=i.Parse(i.IdentifierWithMetadata);if(null===e)return null;i.Whitespace();var n=i.Parse(i.BracketedKnotDeclArguments);return i.Whitespace(),new Qt(e,n,t)},i.KnotStitchNoContentRecoveryRule=function(){return i.ParseUntil(i.KnotDeclaration,new lt("="),null),[new Et("<ERROR IN FLOW>")]},i.BracketedKnotDeclArguments=function(){if(null===i.ParseString("("))return null;var t=i.Interleave(i.Spaced(i.FlowDeclArgument),i.Exclude(i.String(",")));return i.Expect(i.String(")"),"closing ')' for parameter list"),null===t&&(t=[]),t},i.FlowDeclArgument=function(){var t=i.Parse(i.IdentifierWithMetadata);i.Whitespace();var e=i.ParseDivertArrow();i.Whitespace();var n=i.Parse(i.IdentifierWithMetadata);if(null==t&&null===n)return null;var r=new E;return null!==e&&(r.isDivertTarget=!0),null!==t&&"ref"===t.name?(null===n&&i.Error("Expected an parameter name after 'ref'"),r.identifier=n,r.isByReference=!0):(r.isDivertTarget?r.identifier=n:r.identifier=t,null===r.identifier&&i.Error("Expected an parameter name"),r.isByReference=!1),r},i.ExternalDeclaration=function(){i.Whitespace();var t=i.Parse(i.IdentifierWithMetadata);if(null===t||"EXTERNAL"!=t.name)return null;i.Whitespace();var e=i.Expect(i.IdentifierWithMetadata,"name of external function")||new Nt("");i.Whitespace();var n=i.Expect(i.BracketedKnotDeclArguments,"declaration of arguments for EXTERNAL, even if empty, i.e. 'EXTERNAL ".concat(e,"()'"));null===n&&(n=[]);var r=n.map((function(t){var e;return null===(e=t.identifier)||void 0===e?void 0:e.name})).filter(O);return new Zt(e,r)},i._identifierCharSet=null,i.LogicLine=function(){if(i.Whitespace(),null===i.ParseString("~"))return null;i.Whitespace();var t=i.Expect((function(){return i.OneOf([i.ReturnStatement,i.TempDeclarationOrAssignment,i.Expression])}),"expression after '~'",i.SkipToNextLine);if(null===t)return new It;t instanceof nt&&!(t instanceof Rt||t instanceof re)&&i.Error("Logic following a '~' can't be that type of expression. It can only be something like:\n\t~ return\n\t~ var x = blah\n\t~ x++\n\t~ myFunction()");var e=_(t,Rt);return e&&(e.shouldPopReturnedValue=!0),null!==t.Find(Rt)()&&(t=new It(t,new Et("\n"))),i.Expect(i.EndOfLine,"end of line",i.SkipToNextLine),t},i.VariableDeclaration=function(){if(i.Whitespace(),"VAR"!==i.Parse(i.Identifier))return null;i.Whitespace();var t=i.Expect(i.IdentifierWithMetadata,"variable name");i.Whitespace(),i.Expect(i.String("="),"the '=' for an assignment of a value, e.g. '= 5' (initial values are mandatory)"),i.Whitespace();var e=i.Expect(i.Expression,"initial value for ");if(e){if(e instanceof at||e instanceof Ee||e instanceof Vt||e instanceof Ft||e instanceof se||i.Error("initial value for a variable must be a number, constant, list or divert target"),null!==i.Parse(i.ListElementDefinitionSeparator))i.Error("Unexpected ','. If you're trying to declare a new list, use the LIST keyword, not VAR");else if(e instanceof Ee){e.isSingleString||i.Error("Constant strings cannot contain any logic.")}return new Jt({assignedExpression:e,isGlobalDeclaration:!0,variableIdentifier:t})}return null},i.ListDeclaration=function(){if(i.Whitespace(),"LIST"!=i.Parse(i.Identifier))return null;i.Whitespace();var t=i.Expect(i.IdentifierWithMetadata,"list name");i.Whitespace(),i.Expect(i.String("="),"the '=' for an assignment of the list definition"),i.Whitespace();var e=i.Expect(i.ListDefinition,"list item names");return e?(e.identifier=new Nt(t.name),new Jt({variableIdentifier:t,listDef:e})):null},i.ListDefinition=function(){i.AnyWhitespace();var t=i.SeparatedList(i.ListElementDefinition,i.ListElementDefinitionSeparator);return null===t?null:new Ht(t)},i.ListElementDefinitionSeparator=function(){return i.AnyWhitespace(),null===i.ParseString(",")?null:(i.AnyWhitespace(),",")},i.ListElementDefinition=function(){var t=null!==i.ParseString("("),e=t;i.Whitespace();var n=i.Parse(i.IdentifierWithMetadata);if(null===n)return null;i.Whitespace(),t&&null!=i.ParseString(")")&&(e=!1,i.Whitespace());var r=null;if(null!==i.ParseString("=")){i.Whitespace();var a=i.Expect(i.ExpressionInt,"value to be assigned to list item");null!==a&&(r=a.value),e&&(i.Whitespace(),null!==i.ParseString(")")&&(e=!1))}return e&&i.Error("Expected closing ')'"),new le(n,t,r)},i.ConstDeclaration=function(){if(i.Whitespace(),"CONST"!==i.Parse(i.Identifier))return null;i.Whitespace();var t=i.Expect(i.IdentifierWithMetadata,"constant name");i.Whitespace(),i.Expect(i.String("="),"the '=' for an assignment of a value, e.g. '= 5' (initial values are mandatory)"),i.Whitespace();var e=i.Expect(i.Expression,"initial value for ");if(e instanceof at||e instanceof Vt||e instanceof Ee){if(e instanceof Ee){e.isSingleString||i.Error("Constant strings cannot contain any logic.")}}else i.Error("initial value for a constant must be a number or divert target");return new _t(t,e)},i.InlineLogicOrGlue=function(){return i.OneOf([i.InlineLogic,i.Glue])},i.Glue=function(){return null!==i.ParseString("<>")?new ee(new ne):null},i.InlineLogic=function(){if(null===i.ParseString("{"))return null;i.Whitespace();var t=i.Expect(i.InnerLogic,"some kind of logic, conditional or sequence within braces: { ... }");if(null===t)return null;i.DisallowIncrement(t);var e=_(t,It);return e||(e=new It(t)),i.Whitespace(),i.Expect(i.String("}"),"closing brace '}' for inline logic"),e},i.InnerLogic=function(){i.Whitespace();var t=i.ParseObject(i.SequenceTypeAnnotation);if(null!==t){var e=i.Expect(i.InnerSequenceObjects,"sequence elements (for cycle/stoping etc)");return null===e?null:new qt(e,t)}var n=i.Parse(i.ConditionExpression);if(n)return i.Expect((function(){return i.InnerConditionalContent(n)}),"conditional content following query");for(var r=0,a=[i.InnerConditionalContent,i.InnerSequence,i.InnerExpression];r<a.length;r++){var o=a[r],s=i.BeginRule(),l=i.ParseObject(o);if(l){if(null!==i.Peek(i.Spaced(i.String("}"))))return i.SucceedRule(s,l);i.FailRule(s)}else i.FailRule(s)}return null},i.InnerExpression=function(){var t=i.Parse(i.Expression);return t&&(t.outputWhenComplete=!0),t},i.IdentifierWithMetadata=function(){var t=i.Identifier();return null===t?null:new Nt(t)},i.Identifier=function(){var t=i.ParseCharactersFromCharSet(i.identifierCharSet);if(null===t)return null;var e,n=!0,r=S(t);try{for(r.s();!(e=r.n()).done;){var a=e.value;if(!(a>="0"&&a<="9")){n=!1;break}}}catch(t){r.e(t)}finally{r.f()}return n?null:t},i._sequenceTypeSymbols=new lt("!&~$"),i.InnerSequence=function(){i.Whitespace();var t=Dt.Stopping,e=i.Parse(i.SequenceTypeAnnotation);null!==e&&(t=e);var n=i.Parse(i.InnerSequenceObjects);return null===n||n.length<=1?null:new qt(n,t)},i.SequenceTypeAnnotation=function(){var t=i.Parse(i.SequenceTypeSymbolAnnotation);if(null===t&&(t=i.Parse(i.SequenceTypeWordAnnotation)),null===t)return null;switch(t){case Dt.Once:case Dt.Cycle:case Dt.Stopping:case Dt.Shuffle:case Dt.Shuffle|Dt.Stopping:case Dt.Shuffle|Dt.Once:break;default:return i.Error("Sequence type combination not supported: ".concat(t)),Dt.Stopping}return t},i.SequenceTypeSymbolAnnotation=function(){null===i._sequenceTypeSymbols&&(i._sequenceTypeSymbols=new lt("!&~$ "));var t=0,e=i.ParseCharactersFromCharSet(i._sequenceTypeSymbols);if(null===e)return null;var n,r=S(e);try{for(r.s();!(n=r.n()).done;){switch(n.value){case"!":t|=Dt.Once;break;case"&":t|=Dt.Cycle;break;case"~":t|=Dt.Shuffle;break;case"$":t|=Dt.Stopping}}}catch(t){r.e(t)}finally{r.f()}return 0===t?null:t},i.SequenceTypeWordAnnotation=function(){var t=i.Interleave(i.SequenceTypeSingleWord,i.Exclude(i.Whitespace));if(null===t||0===t.length)return null;if(null===i.ParseString(":"))return null;var e,n=0,r=S(t);try{for(r.s();!(e=r.n()).done;){n|=e.value}}catch(t){r.e(t)}finally{r.f()}return n},i.SequenceTypeSingleWord=function(){var t=null,e=i.Parse(i.IdentifierWithMetadata);if(null!==e)switch(e.name){case"once":t=Dt.Once;break;case"cycle":t=Dt.Cycle;break;case"shuffle":t=Dt.Shuffle;break;case"stopping":t=Dt.Stopping}return null===t?null:t},i.InnerSequenceObjects=function(){return null!==i.Parse(i.Newline)?i.Parse(i.InnerMultilineSequenceObjects):i.Parse(i.InnerInlineSequenceObjects)},i.InnerInlineSequenceObjects=function(){var t=i.Interleave(i.Optional(i.MixedTextAndLogic),i.String("|"),null,!1);if(null===t)return null;var e,n=[],r=!1,a=S(t);try{for(a.s();!(e=a.n()).done;){var o=e.value;if("|"===o)r||n.push(new It),r=!1;else{var s=o;null===s?i.Error("Expected content, but got ".concat(o," (this is an ink compiler bug!)")):n.push(new It(s)),r=!0}}}catch(t){a.e(t)}finally{a.f()}return r||n.push(new It),n},i.InnerMultilineSequenceObjects=function(){i.MultilineWhitespace();var t=i.OneOrMore(i.SingleMultilineSequenceElement);return null===t?null:t},i.SingleMultilineSequenceElement=function(){if(i.Whitespace(),null!==i.ParseString("->"))return null;if(null===i.ParseString("-"))return null;i.Whitespace();var t=i.StatementsAtLevel(Xt.InnerBlock);return null===t?i.MultilineWhitespace():t.unshift(new Et("\n")),new It(t)},i._statementRulesAtLevel=[],i._statementBreakRulesAtLevel=[],i.StatementsAtLevel=function(t){t===Xt.InnerBlock&&(null!==i.Parse(i.GatherDashes)&&i.Error("You can't use a gather (the dashes) within the { curly braces } context. For multi-line sequences and conditions, you should only use one dash."));return i.Interleave(i.Optional(i.MultilineWhitespace),(function(){return i.StatementAtLevel(t)}),(function(){return i.StatementsBreakForLevel(t)}))},i.StatementAtLevel=function(t){var e=i._statementRulesAtLevel[t],n=i.OneOf(e);return t===Xt.Top&&n instanceof Pt&&i.Error("should not have return statement outside of a knot"),n},i.StatementsBreakForLevel=function(t){i.Whitespace();var e=i._statementBreakRulesAtLevel[t],n=i.OneOf(e);return null===n?null:n},i.GenerateStatementLevelRules=function(){var t=Object.values(Xt);i._statementRulesAtLevel="f".repeat(t.length).split("f").map((function(){return[]})),i._statementBreakRulesAtLevel="f".repeat(t.length).split("f").map((function(){return[]}));for(var e=0,n=t;e<n.length;e++){var r=n[e],a=[],o=[];a.push(i.Line(i.MultiDivert)),r>=Xt.Top&&a.push(i.KnotDefinition),a.push(i.Line(i.Choice)),a.push(i.Line(i.AuthorWarning)),r>Xt.InnerBlock&&a.push(i.Gather),r>=Xt.Knot&&a.push(i.StitchDefinition),a.push(i.Line(i.ListDeclaration)),a.push(i.Line(i.VariableDeclaration)),a.push(i.Line(i.ConstDeclaration)),a.push(i.Line(i.ExternalDeclaration)),a.push(i.Line(i.IncludeStatement)),a.push(i.LogicLine),a.push(i.LineOfMixedTextAndLogic),r<=Xt.Knot&&o.push(i.KnotDeclaration),r<=Xt.Stitch&&o.push(i.StitchDeclaration),r<=Xt.InnerBlock&&(o.push(i.ParseDashNotArrow),o.push(i.String("}"))),i._statementRulesAtLevel[r]=a,i._statementBreakRulesAtLevel[r]=o}},i.SkipToNextLine=function(){return i.ParseUntilCharactersFromString("\n\r"),i.ParseNewline(),Ct},i.Line=function(t){return function(){var e=i.ParseObject(t);return null===e?null:(i.Expect(i.EndOfLine,"end of line",i.SkipToNextLine),e)}},i._endOfTagCharSet=new lt("#\n\r\\"),i.Tag=function(){if(i.Whitespace(),null===i.ParseString("#"))return null;i.Whitespace();for(var t="";;){if(t+=i.ParseUntilCharactersFromCharSet(i._endOfTagCharSet)||"",null===i.ParseString("\\"))break;var e=i.ParseSingleCharacter();"\0"!==e&&(t+=e)}var n=t.trim();return new _e(new ce(n))},i.Tags=function(){var t=i.OneOrMore(i.Tag);return null===t?null:t},i._inlineWhitespaceChars=new lt(" \t"),i.EndOfLine=function(){return i.OneOf([i.Newline,i.EndOfFile])},i.Newline=function(){return i.Whitespace(),null!==i.ParseNewline()?Ct:null},i.EndOfFile=function(){return i.Whitespace(),i.endOfInput?Ct:null},i.MultilineWhitespace=function(){var t=i.OneOrMore(i.Newline);return null===t?null:t.length>=1?Ct:null},i.Whitespace=function(){return null!==i.ParseCharactersFromCharSet(i._inlineWhitespaceChars)?Ct:null},i.Spaced=function(t){return function(){i.Whitespace();var e=i.ParseObject(t);return null===e?null:(i.Whitespace(),e)}},i.AnyWhitespace=function(){for(var t=!1;null!==i.OneOf([i.Whitespace,i.MultilineWhitespace]);)t=!0;return t?Ct:null},i.MultiSpaced=function(t){return function(){i.AnyWhitespace();var e=i.ParseObject(t);return null===e?null:(i.AnyWhitespace(),e)}},i._filename=null,i._externalErrorHandler=null,i._fileHandler=null,i._filename=a,i.RegisterExpressionOperators(),i.GenerateStatementLevelRules(),i.errorHandler=i.OnStringParserError,i._externalErrorHandler=s,i._fileHandler=null===u?new Ae:u,null===l){if(i._rootParser=h(i),i._openFilenames=[],null!==i._filename){var c=i.fileHandler.ResolveInkFilename(i._filename);i._openFilenames.push(c)}}else i._rootParser=l;return i}return i(o,[{key:"fileHandler",get:function(){if(!this._fileHandler)throw new Error("No FileHandler defined");return this._fileHandler},set:function(t){this._fileHandler=t}},{key:"PreProcessInputString",value:function(t){return new wt(t).Process()}},{key:"parsingStringExpression",get:function(){return this.GetFlag(Number(Gt.ParsingString))},set:function(t){this.SetFlag(Number(Gt.ParsingString),t)}},{key:"identifierCharSet",get:function(){return null===this._identifierCharSet&&((this._identifierCharSet=new lt).AddRange("A","Z").AddRange("a","z").AddRange("0","9").Add("_"),this.ExtendIdentifierCharacterRanges(this._identifierCharSet)),this._identifierCharSet}}]),o}(St);Te.LatinBasic=ut.Define("A","z",(new lt).AddRange("[","`")),Te.LatinExtendedA=ut.Define("Ā","ſ"),Te.LatinExtendedB=ut.Define("ƀ","ɏ"),Te.Greek=ut.Define("Ͱ","Ͽ",(new lt).AddRange("͸","΅").AddCharacters("ʹ͵͸·΋΍΢")),Te.Cyrillic=ut.Define("Ѐ","ӿ",(new lt).AddRange("҂","҉")),Te.Armenian=ut.Define("԰","֏",(new lt).AddCharacters("԰").AddRange("՗","ՠ").AddRange("ֈ","֎")),Te.Hebrew=ut.Define("֐","׿",new lt),Te.Arabic=ut.Define("؀","ۿ",new lt),Te.Korean=ut.Define("가","힯",new lt),Te.ListAllCharacterRanges=function(){return[Te.LatinBasic,Te.LatinExtendedA,Te.LatinExtendedB,Te.Arabic,Te.Armenian,Te.Cyrillic,Te.Greek,Te.Hebrew,Te.Korean]};var Pe=function(){function t(e){var r=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;n(this,t),this._errors=[],this._warnings=[],this._authorMessages=[],this._parsedStory=null,this._runtimeStory=null,this._parser=null,this._debugSourceRanges=[],this.Compile=function(){return r._parser=new Te(r.inputString,r.options.sourceFilename||null,r.OnError,null,r.options.fileHandler),r._parsedStory=r.parser.ParseStory(),0===r.errors.length?(r.parsedStory.countAllVisits=r.options.countAllVisits,r._runtimeStory=r.parsedStory.ExportRuntime(r.OnError)):r._runtimeStory=null,r.runtimeStory},this.RetrieveDebugSourceForLatestContent=function(){var t,e,n=S(r.runtimeStory.state.outputStream);try{for(n.s();!(e=n.n()).done;){var i=_(e.value,$);if(null!==i){var a=new k((null===(t=i.value)||void 0===t?void 0:t.length)||0,i.debugMetadata,i.value||"unknown");r.debugSourceRanges.push(a)}}}catch(t){n.e(t)}finally{n.f()}},this.DebugMetadataForContentAtOffset=function(t){var e,n=0,i=null,a=S(r.debugSourceRanges);try{for(a.s();!(e=a.n()).done;){var o=e.value;if(null!==o.debugMetadata&&(i=o.debugMetadata),t>=n&&t<n+o.length)return i;n+=o.length}}catch(t){a.e(t)}finally{a.f()}return null},this.OnError=function(t,e){switch(e){case b.Author:r._authorMessages.push(t);break;case b.Warning:r._warnings.push(t);break;case b.Error:r._errors.push(t)}null!==r.options.errorHandler&&r.options.errorHandler(t,e)},this._inputString=e,this._options=i||new w}return i(t,[{key:"errors",get:function(){return this._errors}},{key:"warnings",get:function(){return this._warnings}},{key:"authorMessages",get:function(){return this._authorMessages}},{key:"inputString",get:function(){return this._inputString}},{key:"options",get:function(){return this._options}},{key:"parsedStory",get:function(){if(!this._parsedStory)throw new Error;return this._parsedStory}},{key:"runtimeStory",get:function(){if(!this._runtimeStory)throw new Error("Compilation failed.");return this._runtimeStory}},{key:"parser",get:function(){if(!this._parser)throw new Error;return this._parser}},{key:"debugSourceRanges",get:function(){return this._debugSourceRanges}}]),t}();t.Compiler=Pe,t.CompilerOptions=w,t.InkList=B,Object.defineProperty(t,"__esModule",{value:!0})}));
//# sourceMappingURL=ink-full.js.map
</script>
<script>async function preload() {
const canvas = ONE("#player-canvas");
const rendering = canvas.getContext("2d");
rendering.drawImage(ONE("#loading-splash"), 0, 0);
scaleElementToParent(canvas.parentElement);
}
</script>
<script>async function startEditor(font) {
const editor = new BipsiEditor(font);
await editor.init();
// used to show/hide elements in css
document.documentElement.setAttribute("data-app-mode", "editor");
// no embedded project, start editor with save or editor embed
const save = await storage.load(SAVE_SLOT).catch(() => undefined);
const fallback = BIPSI_HD ? makeBlankBundle() : maker.bundleFromHTML(document, "#editor-embed");
const bundle = save || fallback;
// load bundle and enter editor mode
await editor.loadBundle(bundle);
const savedInkSource = await storage.load(`${SAVE_SLOT}-story`).catch(() => undefined);
const inkSource = savedInkSource || maker.storyFromHTML(document, "#story-source");
editor.loadInkSource(inkSource)
// unsaved changes warning
window.addEventListener("beforeunload", (event) => {
if (!editor.unsavedChanges) return;
event.preventDefault();
return event.returnValue = "Are you sure you want to exit?";
});
return editor;
}
async function makePlayback(font, bundle, story) {
const playback = new BipsiPlayback(font);
await playback.initWithStory(story);
const playCanvas = /** @type {HTMLCanvasElement} */ (ONE("#player-canvas"));
const playRendering = /** @type {CanvasRenderingContext2D} */ (playCanvas.getContext("2d"));
// update the canvas size every render just in case..
playback.addEventListener("render", () => {
fillRendering2D(playRendering);
playRendering.drawImage(playback.rendering.canvas, 0, 0);
scaleElementToParent(playCanvas.parentElement);
document.documentElement.style.setProperty('--vh', `${window.innerHeight / 100}px`);
});
// update the canvas size whenever the browser window resizes
window.addEventListener("resize", () => scaleElementToParent(playCanvas.parentElement));
// update the canvas size initially
scaleElementToParent(playCanvas.parentElement);
let moveCooldown = 0;
const heldKeys = new Set();
const keys = new Map();
keys.set("ArrowLeft", () => playback.move(-1, 0));
keys.set("ArrowRight", () => playback.move( 1, 0));
keys.set("ArrowUp", () => playback.move( 0, -1));
keys.set("ArrowDown", () => playback.move( 0, 1));
const keyToCode = new Map();
keyToCode.set("ArrowUp", "KeyW");
keyToCode.set("ArrowLeft", "KeyA");
keyToCode.set("ArrowDown", "KeyS");
keyToCode.set("ArrowRight", "KeyD");
function doMove(key) {
const move = keys.get(key);
if (move) {
move();
moveCooldown = .2;
}
}
function doChoice(key){
const choiceEvent = new CustomEvent('choice', { detail: key});
playback.dispatchEvent(choiceEvent);
}
let prev;
const timer = (next) => {
prev = prev ?? Date.now();
next = next ?? Date.now();
const dt = Math.max(0, (next - prev) / 1000.);
moveCooldown = Math.max(moveCooldown - dt, 0);
prev = next;
window.requestAnimationFrame(timer);
if (moveCooldown === 0) {
const key = Array.from(keys.keys()).find((key) => heldKeys.has(key) || heldKeys.has(keyToCode.get(key)));
if (key) doMove(key);
}
playback.update(dt);
}
timer();
function down(key, code) {
if (!playback.canMove) {
if(playback.choiceExpected && playback.dialoguePlayback.completed()){
return doChoice(key);
};
playback.proceed();
} else {
heldKeys.add(key);
heldKeys.add(code);
doMove(key);
}
}
function up(key, code) {
heldKeys.delete(key);
heldKeys.delete(code);
}
const turnToKey = ["ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp"];
let ignoreMouse = false;
window.onblur = () => setTimeout(() => ignoreMouse = true, 0);
window.onfocus = () => setTimeout(() => ignoreMouse = false, 0);
document.addEventListener("keydown", (event) => {
if (!event.repeat) down(event.key, event.code);
if (keys.has(event.key)) {
event.stopPropagation();
event.preventDefault();
}
}, { capture: true });
document.addEventListener("keyup", (event) => up(event.key, event.code));
document.addEventListener("pointerdown", (event) => {
if (ignoreMouse) return;
const threshold = playCanvas.getBoundingClientRect().width / ROOM_SIZE * 2;
const drag = ui.drag(event);
let [x0, y0] = [drag.downEvent.clientX, drag.downEvent.clientY];
if(!playback.choiceExpected){
playback.proceed();
};
drag.addEventListener("move", () => {
const [x1, y1] = [drag.lastEvent.clientX, drag.lastEvent.clientY];
const [dx, dy] = [x1 - x0, y1 - y0];
const dist = Math.max(Math.abs(dx), Math.abs(dy));
const angle = Math.atan2(dy, dx) + Math.PI * 2;
const turns = Math.round(angle / (Math.PI * .5)) % 4;
const nextKey = turnToKey[turns];
if (dist >= threshold) {
if(playback.choiceExpected && playback.dialoguePlayback.completed()){
return doChoice(nextKey);
}else{
doMove(nextKey);
x0 = x1;
y0 = y1;
}
}
});
});
function captureGif() {
const frames = recordFrames(playback);
const giffer = window.open(
"https://kool.tools/tools/gif/",
"gif maker",
"left=10,top=10,width=512,height=512,resizable=no,location=no",
);
sleep(500).then(() => giffer.postMessage({ name: "bipsi", frames }, "https://kool.tools"));
}
function getRoomListing() {
const current = getLocationOfEvent(playback.data, getEventById(playback.data, playback.avatarId));
const rooms = [];
const thumb = createRendering2D(ROOM_SIZE, ROOM_SIZE);
const preview = createRendering2D(ROOM_PX, ROOM_PX);
playback.data.rooms.forEach((room) => {
drawRoomPreviewPlayback(preview, playback, room.id);
drawRoomThumbPlayback(thumb, playback, room.id);
rooms.push({ id: room.id, thumb: thumb.canvas.toDataURL(), preview: preview.canvas.toDataURL() });
});
postMessageParent({ type: "room-listing", rooms, current }, "*");
}
/** @type {Map<string, (any) => void>} */
const debugHandlers = new Map();
debugHandlers.set("move-to", (message) => moveEventById(playback.data, playback.avatarId, message.destination));
debugHandlers.set("key-down", (message) => down(message.key, message.code));
debugHandlers.set("key-up", (message) => up(message.key, message.code));
debugHandlers.set("capture-gif", (message) => captureGif());
debugHandlers.set("get-room-listing", (message) => getRoomListing());
debugHandlers.set("touch-location", (message) => playback.touch(getEventAtLocation(playback.data, message.location)));
debugHandlers.set("touch-tagged", (message) => playback.touch(findEventByTag(playback.data, message.tag)));
// only allow these when playtesting from editor
if (document.documentElement.getAttribute("data-debug")) {
// if the game runs javascript from variables then this would be a
// vector to run arbitrary javascript on the game's origin giving
// read/write access to storage for that origin and the power to e.g
// erase all game saves etc
debugHandlers.set("set-variable", (message) => playback.setVariable(message.key, message.value));
}
window.addEventListener("message", (event) => {
debugHandlers.get(event.data.type)?.call(this, event.data);
});
document.documentElement.setAttribute("data-app-mode", "player");
await playback.loadBundle(bundle);
playback.start();
return playback;
}
let PLAYBACK;
let EDITOR;
async function start() {
const font = await loadBasicFont(ONE("#font-embed"));
if (BIPSI_HD) document.documentElement.dataset.hd = "true";
// determine if there is a project bundle embedded in this page
const bundle = maker.bundleFromHTML(document);
const storyContent = maker.bundleFromHTML(document, "#story-embed");
if (bundle) {
const story = new inkjs.Story(storyContent);
PLAYBACK = await makePlayback(font, bundle, story);
window.PLAYBACK = PLAYBACK;
} else {
EDITOR = await startEditor(font);
window.EDITOR = EDITOR;
}
}
</script>
<!-- styles-->
<style>
/* prevent weird highlights https://stackoverflow.com/questions/21003535/ */
.no-select {
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* hidden elements should be hidden regardless of their display style */
[hidden] { display: none !important; }
/* default to width/height including padding and border */
* { box-sizing: border-box; }
/* used dynamically to prevent or cancel smooth transitions */
.skip-transition { transition: none !important; }
/* make buttons and select inherit font */
button, select { font-family: inherit; font-size: inherit; }
/* clickable things should use this cursor imo */
button, a, input[type="radio"], input[type="checkbox"], select, option, label, summary { cursor: pointer; }
/* crisp pixelart for images and backgrounds */
* {
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-crisp-edges;
image-rendering: pixelated;
image-rendering: crisp-edges;
}
/* prevent pull down to refresh page (and lose data rip) */
body {
overscroll-behavior-y: contain;
}
html, body {
margin: 0; padding: 0;
width: 100%;
min-height: calc(var(--vh, 1vh) * 100);
overflow: hidden auto;
overscroll-behavior-y: contain;
}
body {
display: flex; flex-direction: column;
justify-content: center;
align-items: center;
color: white;
}
</style>
<style>body {
background: var(--page-color, black);
}
body, canvas {
touch-action: none;
}
#player {
width: 256px;
height: 256px;
position: absolute;
left: 50%; top: 50%;
transform: translate(-50%, -50%);
overflow: hidden;
}
</style>
<script src="ext-searchbox.js"></script></head>
<body class="no-select" onload="start()">
<div id="player">
<canvas id="player-canvas" width="256" height="256"></canvas>
</div>
<img id="loading-splash" hidden="hidden" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEABAMAAACuXLVVAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAGUExURQAAAP/YAFIewjUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACXSURBVHja7dJBCgMhDEDReIN4/8sOkba4mEULogN9DxcusvhEAwAAAAAAAAAAAAAAAABmfRMBAgQ8PCA/czndDwX0QwHRxonaQdT85oCx+szXra1/iW8CIs4G5LSBeoJ6iHF2BLw/QP2BVgG1kI0BN/Otr/VrwHICBAgQIECAAAECBAh4bgAAAAAAAAAAAAAAAAAAfyjiAkM9EgGHYOwCAAAAAElFTkSuQmCC">
<script id="plugins"></script>
<script>preload();</script>
<script id="bundle-embed" type="application/json">{"project":{"rooms":[{"id":1,"palette":1,"tilemap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,1,1,0,0,1,1,1,1,1,0,0,0],[0,0,0,1,2,2,0,0,2,2,2,2,1,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0],[0,0,0,1,0,0,0,0,0,18,0,0,1,0,0,0],[0,0,0,0,0,0,0,0,0,20,0,0,1,0,0,0],[0,0,0,1,0,18,18,20,19,20,0,0,1,0,0,0],[0,0,0,1,0,18,0,19,19,20,20,0,1,0,0,0],[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"backmap":[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],"foremap":[[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,5,5,5,2,2,2,2],[2,2,2,2,2,2,2,2,2,5,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,5,2,2,2,2,2,2],[2,2,2,2,2,6,6,6,6,5,2,2,2,2,2,2],[2,2,2,2,2,6,6,6,6,5,5,5,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]],"wallmap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0],[0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0],[0,0,0,1,0,0,1,1,0,0,0,0,1,0,0,0],[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"events":[{"id":19,"position":[11,6],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":10}]},{"id":20,"position":[11,7],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":12}]},{"id":21,"position":[11,8],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":15}]},{"id":23,"position":[10,7],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":11}]},{"id":24,"position":[10,8],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":14},{"key":"lamp-on-bed","type":"tag","data":true}]},{"id":27,"position":[6,3],"fields":[{"key":"window","type":"tag","data":true},{"key":"graphic","type":"tile","data":8}]},{"id":31,"position":[10,6],"fields":[{"key":"bed","type":"tag","data":true},{"key":"graphic","type":"tile","data":13}]},{"id":32,"position":[6,9],"fields":[{"key":"desk","type":"tag","data":true},{"key":"graphic","type":"tile","data":16},{"key":"lamp-on-desk","type":"tag","data":true}]},{"id":33,"position":[7,9],"fields":[{"key":"desk","type":"tag","data":true},{"key":"graphic","type":"tile","data":17}]},{"id":34,"position":[7,3],"fields":[{"key":"window","type":"tag","data":true},{"key":"graphic","type":"tile","data":8}]},{"id":35,"position":[6,4],"fields":[{"key":"window","type":"tag","data":true},{"key":"graphic","type":"tile","data":8}]},{"id":36,"position":[7,4],"fields":[{"key":"window","type":"tag","data":true},{"key":"graphic","type":"tile","data":8}]},{"id":37,"position":[3,7],"fields":[{"key":"graphic","type":"tile","data":4},{"key":"colors","type":"colors","data":{"bg":1,"fg":3}},{"key":"solid","type":"tag","data":true},{"key":"exit-room","type":"tag","data":true}]},{"id":38,"position":[13,1],"fields":[{"key":"visited","type":"tag","data":true},{"key":"colors","type":"colors","data":{"fg":7,"bg":1}},{"key":"visit-desk","type":"javascript","data":"const desks = FIND_EVENTS(\"desk\")\nconst visitedColors = FIELD(EVENT, \"colors\", \"colors\")\n\ndesks.forEach(desk => {\n SET_FIELDS(desk, \"colors\", \"colors\", visitedColors)\n})"},{"key":"visit-bed","type":"javascript","data":"const beds = FIND_EVENTS(\"bed\")\nconst visitedColors = FIELD(EVENT, \"colors\", \"colors\")\n\nbeds.forEach(bed => {\n SET_FIELDS(bed, \"colors\", \"colors\", visitedColors)\n})"},{"key":"visit-window","type":"javascript","data":"const windows = FIND_EVENTS(\"window\")\nconst visitedColors = FIELD(EVENT, \"colors\", \"colors\")\n\nwindows.forEach(windowpane => {\n SET_FIELDS(windowpane, \"colors\", \"colors\", visitedColors)\n})"},{"key":"light-desk","type":"javascript","data":"const room \n= this.PLAYBACK.data.rooms.find((room) => room.events.includes(EVENT));\n\nroom.palette = 2"},{"key":"light-floor","type":"javascript","data":"const room \n= this.PLAYBACK.data.rooms.find((room) => room.events.includes(EVENT));\n\nroom.palette = 3"},{"key":"switch-light-off","type":"javascript","data":"const room \n= this.PLAYBACK.data.rooms.find((room) => room.events.includes(EVENT));\n\nroom.palette = 1"},{"key":"exit-available","type":"javascript","data":"const exits = FIND_EVENTS(\"exit-room\")\nconst baseColors = { bg: 1, fg: 3 }\n\nexits.forEach(exi => {\n SET_FIELDS(exi, \"colors\", \"colors\", baseColors)\n})"},{"key":"exit-disabled","type":"javascript","data":"const beds = FIND_EVENTS(\"exit-room\")\nconst visitedColors = FIELD(EVENT, \"colors\", \"colors\")\n\nbeds.forEach(bed => {\n SET_FIELDS(bed, \"colors\", \"colors\", visitedColors)\n})"},{"key":"ending","type":"javascript","data":"await RESTART()"},{"key":"unvisit-bed","type":"javascript","data":"const beds = FIND_EVENTS(\"bed\")\nconst baseColors = { bg: 1, fg: 3 }\n\nbeds.forEach(bed => {\n SET_FIELDS(bed, \"colors\", \"colors\", baseColors)\n})"},{"key":"move-away-from-light-floor","type":"javascript","data":"const lightFloor = FIND_EVENT(\"lamp-on-floor\")\n\nconst lo_lightFloor = LOCATION_OF(lightFloor)\nconst lo_avatar = LOCATION_OF(AVATAR)\nLOG(lo_lightFloor)\nLOG(lo_avatar)\nif(lo_lightFloor.x == lo_avatar.x && lo_lightFloor.y == lo_avatar.y){\n WALK(AVATAR, \"^\")\n}"}]},{"id":39,"position":[9,8],"fields":[{"key":"lamp-on-floor","type":"tag","data":true}]},{"id":41,"position":[5,9],"fields":[{"key":"graphic","type":"tile","data":22},{"key":"colors","type":"colors","data":{"bg":1,"fg":3}},{"key":"solid","type":"tag","data":true},{"key":"cane","type":"tag","data":true},{"key":"one-time","type":"tag","data":true},{"key":"invisible","type":"tag","data":true}]},{"id":43,"position":[8,6],"fields":[{"key":"knife-on-floor","type":"tag","data":true}]},{"id":46,"position":[4,7],"fields":[{"key":"is-player","type":"tag","data":true},{"key":"graphic","type":"tile","data":6},{"key":"colors","type":"colors","data":{"bg":1,"fg":4}},{"key":"page-color","type":"text","data":"black"},{"key":"say-style","type":"json","data":{"noMargin":true,"anchorX":0,"anchorY":1,"lineWidth":240,"lines":4}}]}]},{"id":2,"palette":0,"tilemap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"backmap":[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],"foremap":[[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]],"wallmap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"events":[{"id":42,"position":[2,1],"fields":[{"key":"graphic","type":"tile","data":23},{"key":"colors","type":"colors","data":{"bg":1,"fg":3}},{"key":"solid","type":"tag","data":true},{"key":"knife","type":"tag","data":true},{"key":"one-time","type":"tag","data":true}]},{"id":47,"position":[5,1],"fields":[{"key":"graphic","type":"tile","data":21},{"key":"colors","type":"colors","data":{"bg":1,"fg":3}},{"key":"solid","type":"tag","data":true},{"key":"lamp","type":"tag","data":true}]}]},{"id":3,"palette":0,"tilemap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,1,2,2,2,2,2,2,2,2,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,4,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,4,0,0,0,0,0,0,0,0,4,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"backmap":[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],"foremap":[[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],[2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]],"wallmap":[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],"events":[{"id":44,"position":[7,8],"fields":[{"key":"graphic","type":"tile","data":9},{"key":"colors","type":"colors","data":{"bg":1,"fg":7}},{"key":"page-color","type":"text","data":"black"},{"key":"joe","type":"tag","data":true},{"key":"solid","type":"tag","data":true}]},{"id":45,"position":[10,8],"fields":[{"key":"player-in-hall","type":"tag","data":true}]}]}],"palettes":[{"id":0,"colors":["#000000","#3c6fad","#d8d4dd","#ff8e9e","#ffcb6b","#3c6fad","#3c6fad","#2d4814"]},{"id":1,"colors":["#000000","#192b33","#201f7f","#958fbf","#b28e4a","#192b33","#192b33","#6a565b"]},{"id":2,"colors":["#000000","#192b33","#201f7f","#958fbf","#b28e4a","#192b33","#528da8","#6a565b"]},{"id":3,"colors":["#000000","#192b33","#201f7f","#958fbf","#b28e4a","#528da8","#192b33","#6a565b"]}],"tileset":"34","tiles":[{"id":1,"frames":[1]},{"id":18,"frames":[16]},{"id":20,"frames":[18]},{"id":21,"frames":[19]},{"id":22,"frames":[20]},{"id":23,"frames":[21]},{"id":19,"frames":[17]},{"id":2,"frames":[5]},{"id":8,"frames":[8]},{"id":4,"frames":[6]},{"id":6,"frames":[0]},{"id":13,"frames":[11]},{"id":10,"frames":[4]},{"id":11,"frames":[7]},{"id":12,"frames":[10]},{"id":14,"frames":[12]},{"id":15,"frames":[13]},{"id":9,"frames":[9]},{"id":7,"frames":[2,3]},{"id":16,"frames":[14]},{"id":17,"frames":[15]}]},"resources":{"34":{"type":"canvas-datauri","data":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAAAQCAYAAADeWHeIAAACLklEQVRoQ+1ZQZKDMAyD/z+aDp1Jx1VlSQndvdC9bEvAVmxZdui+lb/jOI7xdd/3/fxcr9V78T62dvWa8+0wjOfHXhge56OLg7KJcXP+na0ujg57Ev9nkhXg00kHUK0lzhOCnfec/pGcmFwMRk3cagLq/rrPHakQs4rHVQJcef5FgJqManBsnAW4ro0N1/+VXOr6FYYzu2MvijjVZ0LwjmBMQVE1VgnoiihROGXjmb+uCrGCHAFY62DyycjVKVDnU/nqSMfaWyWKqmQWI7c3VlAqhi7Zqn05BZBK1lV4lV4mZ1jxswRQkqowYSASBVitQIcjCTzG0aniDBFSBVgiQE36DAGQCE5hWBVi4N0MwGYRbE+qzagWwGaQLqnooyYIMab4nIQPLMl9tEiRkZiQdAh0PVKtq+C4ivgPBZiJScWbEsDtMVl3atSSMyGAAsCmbVWRXcVXH6y/skpUk35aYUhM1mK+QQBUQoU9SXjF5PbQ2TsxvJ0CkL0pSNljhI90oyvyfdX2XZ7/OAbilI49ppPrpEq6SbyqUNLTajXNSt9dEpvu80MB0p6fOsDkMqlPyMPUSWGdxXfX+59v2FgVqWNaMjckL1e6lqOSkeC6azJX9v16EcSmaXbOZMPVzAyQEC7p+b/qX0n35zN/1gK6k8CAgArhEuqOmd8Jx/2svP0YpF7TdmsYMpfIpLqZzXQ4rAMi2vkNjEQBVE9VLQAHt+T7Sn0xDImd36yQRGnbHlRzrCL/Tv81AAAAAElFTkSuQmCC"}}}</script>
<script id="story-embed" type="application/json">{"inkVersion":20,"root":[["^Crime Scene -- Script by Inkle, adapted by @smwhr for binksi",{"#":"TITLE"},"\n","^SPAWN_AT(lamp-on-desk, lamp)","\n",{"->":"murder_scene"},["done",{"#n":"g-0"}],null],"done",{"pop":[{"temp=":"list"},"ev",{"VAR?":"list"},"LIST_MIN","/ev",{"temp=":"x"},"\n","ev",{"VAR?":"list"},{"VAR?":"x"},"-",{"temp=":"list","re":true},"/ev","ev",{"VAR?":"x"},"/ev","~ret",null],"get":[{"temp=":"x"},"ev",{"VAR?":"Inventory"},{"VAR?":"x"},"+",{"VAR=":"Inventory","re":true},"/ev",null],"move_to_supporter":[{"temp=":"new_supporter"},{"temp=":"item_state"},"ev",{"VAR?":"item_state"},{"VAR?":"Supporters"},"LIST_ALL","-",{"temp=":"item_state","re":true},"/ev","\n","ev",{"VAR?":"item_state"},{"VAR?":"new_supporter"},"+",{"temp=":"item_state","re":true},"/ev",null],"reached":[{"temp=":"x"},"ev",{"VAR?":"knowledgeState"},{"VAR?":"x"},"?","/ev","~ret",null],"between":[{"temp=":"y"},{"temp=":"x"},"ev",{"VAR?":"knowledgeState"},{"VAR?":"x"},"?",{"VAR?":"knowledgeState"},{"VAR?":"y"},"L^","!","&&","/ev","~ret",null],"reach":[{"temp=":"statesToSet"},"ev",{"^var":"statesToSet","ci":-1},{"f()":"pop"},"/ev",{"temp=":"x"},"\n",["ev",{"VAR?":"x"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","ev",false,"/ev","~ret",{"->":"reach.10"},null]}],["ev",{"VAR?":"x"},{"f()":"reached"},"!","/ev",{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"x"},"LIST_ALL","/ev",{"temp=":"chain"},"\n","ev",{"VAR?":"chain"},{"VAR?":"chain"},"LIST_MIN",{"VAR?":"x"},"range","/ev",{"temp=":"statesGained"},"\n","ev",{"VAR?":"knowledgeState"},{"VAR?":"statesGained"},"+",{"VAR=":"knowledgeState","re":true},"/ev","ev",{"VAR?":"statesToSet"},{"f()":"reach"},"pop","/ev","\n","ev",true,"/ev","~ret",{"->":"reach.10"},null]}],[{"->":".^.b"},{"b":["\n","ev",false,{"VAR?":"statesToSet"},{"f()":"reach"},"||","/ev","~ret","\n",{"->":"reach.10"},null]}],"nop","\n",null],"murder_scene":[["^The bedroom. This is where it happened. Now to look for clues.","\n",["^CUTSCENE(visited, exit-","ev",{"CNT?":".^"},5,">=","/ev",[{"->":".^.b","c":true},{"b":["^available",{"->":".^.^.^.8"},null]}],[{"->":".^.b"},{"b":["^disabled",{"->":".^.^.^.8"},null]}],"nop","^)","\n","ev",{"CNT?":".^.c-0.9.bedhub.c-5"},{"VAR?":"bedroomLightState"},{"VAR?":"on_floor"},"?","&&",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","&&",{"CNT?":".^.c-1"},"!","&&","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, unvisit-bed)","\n",{"->":".^.^.^.26"},null]}],"nop","\n","ev",{"CNT?":".^.c-0.9.bedhub.c-5"},{"VAR?":"bedroomLightState"},{"VAR?":"on_floor"},"?","&&",{"VAR?":"bedroomLightState"},{"VAR?":"off"},"?","&&","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, visit-bed)","\n",{"->":".^.^.^.40"},null]}],"nop","\n","ev",{"CNT?":".^.c-1.3.reaching"},{"CNT?":".^.c-2"},"!","&&","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, unvisit-bed)","\n",{"->":".^.^.^.49"},null]}],"nop","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"seen"},"?","/ev",[{"->":".^.b","c":true},{"b":["^ ","thread",{"->":".^.^.^.^.^.seen_light"},{"->":".^.^.^.57"},null]}],"nop","\n","ev",{"^->":"murder_scene.0.top"},"/ev","thread",{"->":".^.^.^.compare_prints"},"ev","str","^tag: bed","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^tag: bed","/str",{"CNT?":".^.c-0.9.bedhub.c-5"},{"VAR?":"bedroomLightState"},{"VAR?":"on_floor"},"?","&&",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","&&","/ev",{"*":".^.c-1","flg":21},"ev","str","^tag: bed","/str",{"CNT?":".^.c-1.3.reaching"},{"^->":"murder_scene.0.top.c-1.3.reaching"},"turns",4,">=","&&",{"VAR?":"Inventory"},{"VAR?":"cane"},"?","&&","/ev",{"*":".^.c-2","flg":21},"ev","str","^tag: bed","/str",{"CNT?":".^.c-1.3.reaching"},{"^->":"murder_scene.0.top.c-1.3.reaching"},"turns",4,"<",{"VAR?":"Inventory"},{"VAR?":"cane"},"!?","||","&&","/ev",{"*":".^.c-3","flg":5},"ev","str","^tag: knife","/str",{"VAR?":"knifeState"},{"VAR?":"on_floor"},"?","/ev",{"*":".^.c-4","flg":21},"ev","str","^tag: desk","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^tag: cane","/str",{"VAR?":"Inventory"},{"VAR?":"cane"},"!?","/ev",{"*":".^.c-6","flg":21},"ev","str","^tag: window","/str","/ev",{"*":".^.c-7","flg":20},"ev","str","^tag: exit-room","/str",{"CNT?":".^"},5,">=","/ev",{"*":".^.c-8","flg":21},{"c-0":["\n","^The bed was low to the ground, but not so low something might not roll underneath. It was still neatly made.","\n","ev",{"VAR?":"neatly_made"},{"f()":"reach"},"pop","/ev","\n",[["ev","str","^Lift the bedcover","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Remove the cover","/str",{"VAR?":"crumpled_duvet"},{"f()":"reached"},"/ev",{"*":".^.c-1","flg":21},"ev","str","^ Pull back the duvet ","/str",{"VAR?":"BedState"},{"VAR?":"covers_off"},"==","/ev",{"*":".^.c-2","flg":21},"ev","str","^ Remake the bed ","/str",{"VAR?":"BedState"},{"VAR?":"made_up"},"!?","/ev",{"*":".^.c-3","flg":21},"ev","str","^Test the bed","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Look under the bed","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Something else?","/str",{"^->":"murder_scene.0.top.c-0"},"turns",1,">","/ev",{"*":".^.c-6","flg":21},{"c-0":["\n","^I lifted back the bedcover. The duvet underneath was crumpled.","\n","ev",{"VAR?":"crumpled_duvet"},{"f()":"reach"},"pop","/ev","\n","ev",{"VAR?":"covers_shifted"},"/ev",{"VAR=":"BedState","re":true},{"->":".^.^.^.g-0"},{"#f":5}],"c-1":["\n","^Careful not to disturb anything beneath, I removed the cover entirely. The duvet below was rumpled.","\n","^Not the work of the maid, who was conscientious to a point. Clearly this had been thrown on in a hurry.","\n","ev",{"VAR?":"hastily_remade"},{"f()":"reach"},"pop","/ev","\n","ev",{"VAR?":"covers_off"},"/ev",{"VAR=":"BedState","re":true},{"->":".^.^.^.g-0"},{"#f":5}],"c-2":["\n","^I pulled back the duvet. Beneath it was a sheet, sticky with blood.","\n","ev",{"VAR?":"bloodstain_visible"},"/ev",{"VAR=":"BedState","re":true},"ev",{"VAR?":"body_on_bed"},{"f()":"reach"},"pop","/ev","\n","^Either the body had been moved here before being dragged to the floor - or this is was where the murder had taken place.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-3":["\n","^Carefully, I pulled the bedsheets back into place, trying to make it seem undisturbed.","\n","ev",{"VAR?":"made_up"},"/ev",{"VAR=":"BedState","re":true},{"->":".^.^.^.g-0"},{"#f":5}],"c-4":["\n","^I pushed the bed with spread fingers. It creaked a little, but not so much as to be obnoxious.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-5":["\n","^Lying down, I peered under the bed, but could make nothing out.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-6":["\n","^I took a step back from the bed and looked around.","\n","^CUTSCENE(visited, visit-bed)","\n",{"->":".^.^.^.^.^"},{"->":".^.^.^.g-0"},{"#f":5}],"#n":"bedhub"}],{"g-0":[{"->":".^.^.bedhub"},{"->":".^.^.^.^.^.g-0"},null]}],{"#f":7}],"c-1":["\n","^I peered under the bed. Something glinted back at me.","\n",[["ev","str","^ Reach for it ","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Knock it with the cane","/str",{"VAR?":"Inventory"},{"VAR?":"cane"},"?","/ev",{"*":".^.c-1","flg":21},"ev","str","^ Stand up ","/str",{"CNT?":".^"},1,">","/ev",{"*":".^.c-2","flg":21},{"c-0":["\n","^I fished with one arm under the bed, but whatever it was, it had been kicked far enough back that I couldn't get my fingers on it.","\n",{"->":".^.^"},{"->":".^.^.^.^.^.^.g-0"},{"#f":5}],"c-1":["\n",{"->":".^.^.^.^.^.c-2"},{"->":".^.^.^.^.^.^.g-0"},{"#f":5}],"c-2":["\n","^I stood up once more, and brushed my coat down.","\n","^CUTSCENE(visited, visit-bed)","\n",{"->":".^.^.^.^.^"},{"->":".^.^.^.^.^.^.g-0"},{"#f":5}],"#f":7,"#n":"reaching"}],null],{"#f":5}],"c-2":["\n",["ev","str","^Use the cane to reach under the bed ","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^Positioning the cane above the carpet, I gave the glinting thing a sharp tap. It slid out from under the foot of the bed.","\n","ev",{"^var":"knifeState","ci":-1},{"VAR?":"on_floor"},{"f()":"move_to_supporter"},"pop","/ev","\n","^SPAWN_AT(knife-on-floor, knife)","\n","ev","str","^Stand up","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Look under the bed once more","/str","/ev",{"*":".^.c-2","flg":20},{"c-1":["\n","^Satisfied, I stood up, and saw I had knocked free a bloodied knife.","\n","^CUTSCENE(visited, visit-bed)","\n",{"->":".^.^.^.^.^"},{"->":".^.^.^.^.^.^.g-0"},{"#f":5}],"c-2":["\n","^Moving the cane aside, I looked under the bed once more, but there was nothing more there.","\n",{"->":".^.^.c-1"},{"->":".^.^.^.^.^.^.g-0"},{"#f":5}]}]}],{"#f":5}],"c-3":["\n","^Whatever was under the bed was enough back that I wouldn't be able to reach it without some kind of tool.","\n",{"->":".^.^.^.g-0"},null],"c-4":["\n","^Careful not to touch the handle, I lifted the blade from the carpet.","\n","ev",{"VAR?":"knife"},{"f()":"get"},"pop","/ev","\n","^The blood was dry enough. Dry enough to show up partial prints on the hilt!","\n","ev",{"VAR?":"prints_on_knife"},{"f()":"reach"},"pop","/ev","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-5":["\n","^I turned my attention to the desk. A lamp sat in one corner, a neat, empty in-tray in the other. There was nothing else out.","\n","ev",{"VAR?":"Inventory"},{"VAR?":"cane"},"!?","/ev",[{"->":".^.b","c":true},{"b":["^ Leaning against the desk was a wooden cane.",{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"seen"},"+",{"VAR=":"bedroomLightState","re":true},"/ev",[["ev","str","^Turn on the lamp","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"!?","/ev",{"*":".^.c-0","flg":21},"ev","str","^Look at the in-tray ","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Open a drawer","/str",{"CNT?":".^.c-2"},3,"<","/ev",{"*":".^.c-2","flg":5},"ev","str","^Something else?","/str",{"CNT?":".^"},2,">=","/ev",{"*":".^.c-3","flg":21},{"c-0":["\n",{"->t->":"murder_scene.operate_lamp"},{"->":".^.^.^.g-0"},{"#f":5}],"c-1":["\n","^I regarded the in-tray, but there was nothing to be seen. Either the victim's papers were taken, or his line of work had seriously dried up. Or the in-tray was all for show.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-2":["\n","^I tried ",["ev","visit",2,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"nop",{"s0":["pop","^a drawer at random",{"->":".^.^.23"},null],"s1":["pop","^another drawer",{"->":".^.^.23"},null],"s2":["pop","^a third drawer",{"->":".^.^.23"},null],"#f":5}],"^. ",["ev","visit",2,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"ev","du",2,"==","/ev",{"->":".^.s2","c":true},"nop",{"s0":["pop","^Locked",{"->":".^.^.23"},null],"s1":["pop","^Also locked",{"->":".^.^.23"},null],"s2":["pop","^Unsurprisingly, locked as well",{"->":".^.^.23"},null],"#f":5}],"^.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-3":["\n","^I took a step away from the desk once more.","\n","^CUTSCENE(visited, visit-desk)","\n",{"->":".^.^.^.^.^"},{"->":".^.^.^.g-0"},{"#f":5}],"#f":5,"#n":"deskstate"}],{"g-0":[{"->":".^.^.deskstate"},{"->":".^.^.^.^.^.g-0"},null]}],{"#f":5}],"c-6":["\n","ev",{"VAR?":"cane"},{"f()":"get"},"pop","/ev","\n","^I picked up the wooden cane. It was heavy, and unmarked.","\n",["ev","str","^Swoosh the cane","/str",{"VAR?":"Inventory"},{"VAR?":"cane"},"?",{"^->":"murder_scene.0.top.c-6"},"turns",2,"<=","&&","/ev",{"*":".^.c-0","flg":21},"ev","str","^Something else?","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["\n","^I was still holding the cane: I gave it an experimental swoosh. It was heavy indeed, though not heavy enough to be used as a bludgeon.","\n","^But it might have been useful in self-defence. Why hadn't the victim reached for it? Knocked it over?","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}],"c-1":["\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}]}],{"#f":7}],"c-7":["\n","^I went over to the window and peered out. A dismal view of the little brook that ran down beside the house.","\n",[["ev",{"^->":"murder_scene.0.top.c-7.3.window_opts"},"/ev","thread",{"->":"murder_scene.compare_prints"},"ev","str","^Look down at the brook","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Look at the glass","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^ Look at the steam ","/str",{"VAR?":"GlassState"},{"VAR?":"steamed"},"?",{"CNT?":"murder_scene.see_prints_on_glass"},"!","&&",{"CNT?":".^.c-0"},"&&",{"CNT?":".^.c-1"},"&&","/ev",{"*":".^.c-2","flg":21},"ev","str","^ Breathe on the glass ","/str",{"VAR?":"GlassState"},{"VAR?":"steam_gone"},"?","/ev",{"*":".^.c-3","flg":5},"ev","str","^Something else?","/str","/ev",{"*":".^.c-4","flg":4},{"c-0":["\n","ev",{"VAR?":"GlassState"},{"VAR?":"steamed"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","^Through the steamed glass I couldn't see the brook. ",{"->t->":"murder_scene.see_prints_on_glass"},{"->":".^.^.^.^"},"\n",{"->":".^.^.^.7"},null]}],"nop","\n","^I watched the little stream rush past for a while. The house probably had damp but otherwise, it told me nothing.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-1":["\n","ev",{"VAR?":"GlassState"},{"VAR?":"steamed"},"?","/ev",[{"->":".^.b","c":true},{"b":["^ ",{"->":".^.^.^.^.c-0"},{"->":".^.^.^.7"},null]}],"nop","\n","^The glass in the window was greasy. No one had cleaned it in a while, inside or out.","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-2":["\n","^A cold day outside. Natural my breath should steam. ",{"->t->":"murder_scene.see_prints_on_glass"},"\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-3":["\n","^I breathed gently on the glass once more. ","ev",{"VAR?":"fingerprints_on_glass"},{"f()":"reached"},"/ev",[{"->":".^.b","c":true},{"b":["^ The fingerprints reappeared. ",{"->":".^.^.^.7"},null]}],"nop","\n","ev",{"VAR?":"steamed"},"/ev",{"VAR=":"GlassState","re":true},{"->":".^.^.^.g-0"},null],"c-4":["\n","ev",{"CNT?":".^.^"},2,"<",{"VAR?":"fingerprints_on_glass"},{"f()":"reached"},"||",{"VAR?":"GlassState"},{"VAR?":"steamed"},"?","||","/ev",[{"->":".^.b","c":true},{"b":["\n","^I looked away from the dreary glass.","\n","ev",{"VAR?":"GlassState"},{"VAR?":"steamed"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"steam_gone"},"/ev",{"VAR=":"GlassState","re":true},"<>","^ The steam from my breath faded.","\n",{"->":".^.^.^.9"},null]}],"nop","\n","^CUTSCENE(visited, visit-window)","\n",{"->":".^.^.^.^.^.^.^"},{"->":".^.^.^.14"},null]}],"nop","\n","^I leant back from the glass. My breath had steamed up the pane a little.","\n","ev",{"VAR?":"steamed"},"/ev",{"VAR=":"GlassState","re":true},{"->":".^.^.^.g-0"},null],"#f":7,"#n":"window_opts"}],{"g-0":[{"->":".^.^.window_opts"},{"->":".^.^.^.^.^.g-0"},null]}],{"#f":5}],"c-8":["\n","^I'd seen enough. I ","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",[{"->":".^.b","c":true},{"b":["^switched off the lamp, then",{"->":".^.^.^.8"},null]}],"nop","^ turned and left the room.","\n","^CUTSCENE(visited, switch-light-off)","\n","^SPAWN_AT(lamp-on-desk, lamp)","\n",{"->":"joe_in_hall"},{"->":".^.^.^.g-0"},{"#f":5}],"#f":7,"#n":"top"}],{"g-0":[{"->":".^.^.top"},null]}],{"operate_lamp":["^I flicked the light switch.","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","<>","^ The bulb fell dark.","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"off"},"+",{"VAR=":"bedroomLightState","re":true},"/ev","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"-",{"VAR=":"bedroomLightState","re":true},"/ev","^CUTSCENE(visited, switch-light-off)","\n",{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on_floor"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","<>","^ A little light spilled under the bed.","\n","^CUTSCENE(visited, light-floor)","\n",{"->":".^.^.^.7"},null]}],"nop","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on_desk"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","<>","^ The light gleamed on the polished tabletop.","\n","^CUTSCENE(visited, light-desk)","\n",{"->":".^.^.^.15"},null]}],"nop","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"off"},"-",{"VAR=":"bedroomLightState","re":true},"/ev","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"+",{"VAR=":"bedroomLightState","re":true},"/ev",{"->":".^.^.^.9"},null]}],"nop","\n","ev","void","/ev","->->",null],"compare_prints":[{"temp=":"backto"},["ev","str","^Compare the prints between knife and window ","/str",{"list":{"WindowKnowledge.fingerprints_on_glass":2,"KnifeKnowledge.prints_on_knife":1}},{"VAR?":"fingerprints_on_glass_match_knife"},{"f()":"between"},"/ev",{"*":".^.c-0","flg":21},{"c-0":["\n","^Holding the bloodied knife near the window, I breathed to bring out the prints once more, and compared them as best I could.","\n","^Hardly scientific, but they seemed very similar - very similiar indeed.","\n","ev",{"VAR?":"fingerprints_on_glass_match_knife"},{"f()":"reach"},"pop","/ev","\n",{"->":"backto","var":true},{"#f":5}]}],null],"see_prints_on_glass":["ev",{"VAR?":"fingerprints_on_glass"},{"f()":"reach"},"pop","/ev","\n",["ev","visit",1,"MIN","/ev","ev","du",0,"==","/ev",{"->":".^.s0","c":true},"ev","du",1,"==","/ev",{"->":".^.s1","c":true},"nop",{"s0":["pop","^But I could see a few fingerprints, as though someone had pressed their palm against it.",{"->":".^.^.17"},null],"s1":["pop","^The fingerprints were quite clear and well-formed.",{"->":".^.^.17"},null],"#f":5}],"^ They faded as I watched.","\n","ev",{"VAR?":"steam_gone"},"/ev",{"VAR=":"GlassState","re":true},"ev","void","/ev","->->",{"#f":1}],"seen_light":[["ev","str","^tag: lamp","/str","/ev",{"*":".^.c-0","flg":4},{"c-0":["\n",["ev","str","^ Turn on lamp ","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"!?","/ev",{"*":".^.c-0","flg":5},"ev","str","^ Turn off lamp ","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",{"*":".^.c-1","flg":5},"ev","str","^ Move the light to the bed ","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on_bed"},"!?",{"VAR?":"BedState"},{"VAR?":"bloodstain_visible"},"?","&&","/ev",{"*":".^.c-2","flg":21},"ev","str","^ Move the light back to the desk ","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on_desk"},"!?",{"^->":"murder_scene.seen_light.0.c-0.1.c-4"},"turns",2,">=","&&","/ev",{"*":".^.c-3","flg":21},"ev","str","^Move the light to the floor ","/str",{"VAR?":"bedroomLightState"},{"VAR?":"on_floor"},"!?",{"CNT?":".^.^.^.^.^.0.top.c-0.9.bedhub.c-5"},"&&","/ev",{"*":".^.c-4","flg":21},"ev","str","^Something else?","/str","/ev",{"*":".^.c-5","flg":4},{"c-0":["\n",{"->t->":"murder_scene.operate_lamp"},{"->":".^.^.^.^.g-0"},null],"c-1":["\n",{"->t->":"murder_scene.operate_lamp"},{"->":".^.^.^.^.g-0"},null],"c-2":["\n","^SPAWN_AT(lamp-on-bed, lamp)","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, light-floor)","\n",{"->":".^.^.^.10"},null]}],[{"->":".^.b"},{"b":["\n","^CUTSCENE(visited, switch-light-off)","\n",{"->":".^.^.^.10"},null]}],"nop","\n","ev",{"^var":"bedroomLightState","ci":-1},{"VAR?":"on_bed"},{"f()":"move_to_supporter"},"pop","/ev","\n","^I moved the light over to the bloodstain and peered closely at it. It had soaked deeply into the fibres of the cotton sheet.","\n","^There was no doubt about it. This was where the blow had been struck.","\n","ev",{"VAR?":"murdered_in_bed"},{"f()":"reach"},"pop","/ev","\n",{"->":".^.^.^.^.g-0"},{"#f":5}],"c-3":["\n","^SPAWN_AT(lamp-on-desk, lamp)","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, light-desk)","\n",{"->":".^.^.^.10"},null]}],[{"->":".^.b"},{"b":["\n","^CUTSCENE(visited, switch-light-off)","\n",{"->":".^.^.^.10"},null]}],"nop","\n","ev",{"^var":"bedroomLightState","ci":-1},{"VAR?":"on_desk"},{"f()":"move_to_supporter"},"pop","/ev","\n","^I moved the light back to the desk, setting it down where it had originally been.","\n",{"->":".^.^.^.^.g-0"},{"#f":5}],"c-4":["\n","^SPAWN_AT(lamp-on-floor, lamp)","\n","^CUTSCENE(visited, move-away-from-light-floor)","\n","ev",{"VAR?":"bedroomLightState"},{"VAR?":"on"},"?","/ev",[{"->":".^.b","c":true},{"b":["\n","^CUTSCENE(visited, light-floor)","\n",{"->":".^.^.^.12"},null]}],[{"->":".^.b"},{"b":["\n","^CUTSCENE(visited, switch-light-off)","\n",{"->":".^.^.^.12"},null]}],"nop","\n","ev",{"^var":"bedroomLightState","ci":-1},{"VAR?":"on_floor"},{"f()":"move_to_supporter"},"pop","/ev","\n","^I picked the light up and set it down on the floor.","\n",{"->":".^.^.^.^.g-0"},{"#f":7}],"c-5":["\n",{"->":".^.^.^.^.g-0"},null]}],null],"g-0":[{"->":".^.^.^.^.0.top"},null]}],null]}],"joe_in_hall":[["^My police contact, Joe, was waiting in the hall. ",{"#":"TITLE"},"\n","^SPAWN_AT(player-in-hall)","\n","ev","str","^tag: joe","/str","/ev",{"*":".^.c-0","flg":4},{"c-0":["^ 'So?' he demanded. 'Did you find anything interesting?'","\n",{"->":".^.^.found"},null],"found":["ev","str","^Nothing.","/str",{"CNT?":".^"},1,"==","/ev",{"*":".^.c-1","flg":21},"ev","str","^I found the murder weapon","/str",{"VAR?":"Inventory"},{"VAR?":"knife"},"?","/ev",{"*":".^.c-2","flg":21},"ev","str","^There are prints on the blade","/str",{"VAR?":"prints_on_knife"},{"f()":"reached"},{"VAR?":"knifeState"},{"VAR?":"with_joe"},"?","&&","/ev",{"*":".^.c-3","flg":21},"ev","str","^They match some prints on the window","/str",{"list":{"WindowKnowledge.fingerprints_on_glass_match_knife":3,"KnifeKnowledge.joe_seen_prints_on_knife":2}},{"f()":"reached"},"/ev",{"*":".^.c-4","flg":21},"ev","str","^The body was moved to the bed.","/str",{"VAR?":"body_on_bed"},{"VAR?":"murdered_in_bed"},{"f()":"between"},"/ev",{"*":".^.c-5","flg":21},"ev","str","^The victim was murdered in bed","/str",{"VAR?":"murdered_in_bed"},{"f()":"reached"},"/ev",{"*":".^.c-6","flg":21},"ev","str","^That's it","/str",{"CNT?":".^"},1,">","/ev",{"*":".^.c-7","flg":21},{"c-1":["\n","^He shrugged. 'Shame.'","\n",{"->":".^.^.^.g-0.done"},{"->":".^.^.^.g-0"},{"#f":5}],"c-2":["\n","^'Good going!' Joe replied with a grin. 'We thought the murderer had gotten rid of it. I'll bag that for you now.'","\n","ev",{"^var":"knifeState","ci":-1},{"VAR?":"with_joe"},{"f()":"move_to_supporter"},"pop","/ev","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-3":["\n","^He regarded them carefully.","\n","^'Hrm. Not very complete. It'll be hard to get a match from these.'","\n","ev",{"VAR?":"joe_seen_prints_on_knife"},{"f()":"reach"},"pop","/ev","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-4":["\n","^'Anyone could have touched the window,' Joe replied thoughtfully. 'But if they're more complete, they should help us get a decent match!'","\n","ev",{"VAR?":"joe_wants_better_prints"},{"f()":"reach"},"pop","/ev","\n",{"->":".^.^.^.g-0"},{"#f":5}],"c-5":["\n","^'And then, at some point, moved back to the floor.' I added","\n","^'Why?'","\n",["ev","str","^I don't know","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^To get something from the floor?","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Perhaps he was killed in bed","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["\n","^Joe nods. 'All right.'","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}],"c-1":["\n","^'You wouldn't move a whole body for that.'","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}],"c-2":["\n","^'It's just speculation at this point,' Joe remarks.","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}]}],{"#f":5}],"c-6":["\n","^'And then the body was moved to the floor.' I added","\n","^'Why?'","\n",["ev","str","^I don't know","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^The murderer wanted to mislead us?","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^They hoped to clean up the scene?","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["\n","^Joe nods. 'All right, then.'","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}],"c-1":["\n","^'How so?'","\n","^'They wanted us to think...","\n",[["ev",{"^->":"joe_in_hall.0.found.c-6.5.c-1.5.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^.'","/str","/ev",{"*":".^.^.c-0","flg":22},{"s":["^...the victim was awake",{"->":"$r","var":true},null]}],["ev",{"^->":"joe_in_hall.0.found.c-6.5.c-1.5.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","str","^.'","/str","/ev",{"*":".^.^.c-1","flg":22},{"s":["^...there was some kind of struggle",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"joe_in_hall.0.found.c-6.5.c-1.5.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"^, I replied thoughtfully. 'That they were meeting their attacker, rather than being stabbed in their sleep.'","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"joe_in_hall.0.found.c-6.5.c-1.5.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"^,' I replied. 'That the victim wasn't simply stabbed in their sleep.'","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^'But if they were killed in bed, that's most likely what happened. Stabbed, while sleeping.'","\n","ev",{"VAR?":"murdered_while_asleep"},{"f()":"reach"},"pop","/ev","\n",{"->":"joe_in_hall.0.g-0"},null]}],{"#f":5}],"c-2":["\n","^'But they were disturbed? It's possible.'","\n",{"->":".^.^.^.^.^.g-0"},{"#f":5}]}],{"#f":5}],"c-7":["\n","^'All right. It's a start,' Joe replied.","\n",{"->":".^.^.^.g-0.done"},{"->":".^.^.^.g-0"},{"#f":5}],"#f":5}],"g-0":[{"->":".^.^.found"},[["ev",{"VAR?":"joe_wants_better_prints"},{"VAR?":"joe_got_better_prints"},{"f()":"between"},"/ev",{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"joe_got_better_prints"},{"f()":"reach"},"pop","/ev","\n","<>","^ 'I'll get those prints from the window now.'","\n",{"->":".^.^.^.3"},null]}],["ev",{"VAR?":"joe_seen_prints_on_knife"},{"f()":"reached"},"/ev",{"->":".^.b","c":true},{"b":["\n","<>","^ 'I'll run those prints as best I can.'","\n",{"->":".^.^.^.3"},null]}],[{"->":".^.b"},{"b":["\n","<>","^ 'Not much to go on.'","\n",{"->":".^.^.^.3"},null]}],"nop","\n","^THE END ",{"#":"TITLE"},"\n","^CUTSCENE(visited, ending)","\n","end",{"#n":"done"}],null]}],null],"global decl":["ev",{"list":{},"origins":["OffOn"]},{"VAR=":"OffOn"},{"list":{},"origins":["SeenUnseen"]},{"VAR=":"SeenUnseen"},{"list":{"GlassState.none":1}},{"VAR=":"GlassState"},{"list":{"BedState.made_up":1}},{"VAR=":"BedState"},{"list":{"Inventory.none":1}},{"VAR=":"Inventory"},{"list":{},"origins":["Supporters"]},{"VAR=":"Supporters"},{"list":{}},{"VAR=":"knowledgeState"},{"list":{"OffOn.off":1,"Supporters.on_desk":1}},{"VAR=":"bedroomLightState"},{"list":{"Supporters.under_bed":4}},{"VAR=":"knifeState"},{"list":{},"origins":["BedKnowledge"]},{"VAR=":"BedKnowledge"},{"list":{},"origins":["KnifeKnowledge"]},{"VAR=":"KnifeKnowledge"},{"list":{},"origins":["WindowKnowledge"]},{"VAR=":"WindowKnowledge"},"/ev","end",null]}],"listDefs":{"OffOn":{"off":1,"on":2},"SeenUnseen":{"unseen":1,"seen":2},"GlassState":{"none":1,"steamed":2,"steam_gone":3},"BedState":{"made_up":1,"covers_shifted":2,"covers_off":3,"bloodstain_visible":4},"Inventory":{"none":1,"cane":2,"knife":3},"Supporters":{"on_desk":1,"on_floor":2,"on_bed":3,"under_bed":4,"held":5,"with_joe":6},"BedKnowledge":{"neatly_made":1,"crumpled_duvet":2,"hastily_remade":3,"body_on_bed":4,"murdered_in_bed":5,"murdered_while_asleep":6},"KnifeKnowledge":{"prints_on_knife":1,"joe_seen_prints_on_knife":2,"joe_wants_better_prints":3,"joe_got_better_prints":4},"WindowKnowledge":{"steam_on_glass":1,"fingerprints_on_glass":2,"fingerprints_on_glass_match_knife":3}}}</script>
<script id="story-source" type="text/ink">Crime Scene -- Script by Inkle, adapted by @smwhr for binksi#TITLE
SPAWN_AT(lamp-on-desk, lamp)
-> murder_scene
// Helper function: popping elements from lists
=== function pop(ref list)
~ temp x = LIST_MIN(list)
~ list -= x
~ return x
//
// System: items can have various states
// Some are general, some specific to particular items
//
LIST OffOn = off, on
LIST SeenUnseen = unseen, seen
LIST GlassState = (none), steamed, steam_gone
LIST BedState = (made_up), covers_shifted, covers_off, bloodstain_visible
//
// System: inventory
//
LIST Inventory = (none), cane, knife
=== function get(x)
~ Inventory += x
//
// System: positioning things
// Items can be put in and on places
//
LIST Supporters = on_desk, on_floor, on_bed, under_bed, held, with_joe
=== function move_to_supporter(ref item_state, new_supporter) ===
~ item_state -= LIST_ALL(Supporters)
~ item_state += new_supporter
// System: Incremental knowledge.
// Each list is a chain of facts. Each fact supersedes the fact before
//
VAR knowledgeState = ()
=== function reached (x)
~ return knowledgeState ? x
=== function between(x, y)
~ return knowledgeState? x && not (knowledgeState ^ y)
=== function reach(statesToSet)
~ temp x = pop(statesToSet)
{
- not x:
~ return false
- not reached(x):
~ temp chain = LIST_ALL(x)
~ temp statesGained = LIST_RANGE(chain, LIST_MIN(chain), x)
~ knowledgeState += statesGained
~ reach (statesToSet) // set any other states left to set
~ return true // and we set this state, so true
- else:
~ return false || reach(statesToSet)
}
//
// Set up the game
//
VAR bedroomLightState = (off, on_desk)
VAR knifeState = (under_bed)
//
// Knowledge chains
//
LIST BedKnowledge = neatly_made, crumpled_duvet, hastily_remade, body_on_bed, murdered_in_bed, murdered_while_asleep
LIST KnifeKnowledge = prints_on_knife, joe_seen_prints_on_knife,joe_wants_better_prints, joe_got_better_prints
LIST WindowKnowledge = steam_on_glass, fingerprints_on_glass, fingerprints_on_glass_match_knife
//
// Content
//
=== murder_scene ===
The bedroom. This is where it happened. Now to look for clues.
- (top)
// run some checks to change the colors of the elements
// door is available after 5 loops
CUTSCENE(visited, exit-{top >= 5:available|disabled})
// bed is available if light is on floor
{darkunder && bedroomLightState ? on_floor && bedroomLightState ? on && not peerbed:
- CUTSCENE(visited, unvisit-bed)
}
// bed is not available if lamp is off
{darkunder && bedroomLightState ? on_floor && bedroomLightState ? off:
- CUTSCENE(visited, visit-bed)
}
// bed is always available when trying to reach
{reaching and not knock_with_cane:
- CUTSCENE(visited, unvisit-bed)
}
{ bedroomLightState ? seen: <- seen_light }
<- compare_prints(-> top)
* (dobed) [tag: bed]
The bed was low to the ground, but not so low something might not roll underneath. It was still neatly made.
~ reach (neatly_made)
- - (bedhub)
* * [Lift the bedcover]
I lifted back the bedcover. The duvet underneath was crumpled.
~ reach (crumpled_duvet)
~ BedState = covers_shifted
* * (uncover) {reached(crumpled_duvet)}
[Remove the cover]
Careful not to disturb anything beneath, I removed the cover entirely. The duvet below was rumpled.
Not the work of the maid, who was conscientious to a point. Clearly this had been thrown on in a hurry.
~ reach (hastily_remade)
~ BedState = covers_off
* * (duvet) {BedState == covers_off} [ Pull back the duvet ]
I pulled back the duvet. Beneath it was a sheet, sticky with blood.
~ BedState = bloodstain_visible
~ reach (body_on_bed)
Either the body had been moved here before being dragged to the floor - or this is was where the murder had taken place.
* * {BedState !? made_up} [ Remake the bed ]
Carefully, I pulled the bedsheets back into place, trying to make it seem undisturbed.
~ BedState = made_up
* * [Test the bed]
I pushed the bed with spread fingers. It creaked a little, but not so much as to be obnoxious.
* * (darkunder) [Look under the bed]
Lying down, I peered under the bed, but could make nothing out.
* * {TURNS_SINCE(-> dobed) > 1} [Something else?]
I took a step back from the bed and looked around.
CUTSCENE(visited, visit-bed)
-> top
- - -> bedhub
* (peerbed){darkunder && bedroomLightState ? on_floor && bedroomLightState ? on}
[tag: bed]
I peered under the bed. Something glinted back at me.
- - (reaching)
* * [ Reach for it ]
I fished with one arm under the bed, but whatever it was, it had been kicked far enough back that I couldn't get my fingers on it.
-> reaching
* * {Inventory ? cane} [Knock it with the cane]
-> knock_with_cane
* * {reaching > 1 } [ Stand up ]
I stood up once more, and brushed my coat down.
CUTSCENE(visited, visit-bed)
-> top
* (knock_with_cane) {reaching && TURNS_SINCE(-> reaching) >= 4 && Inventory ? cane } [tag: bed]
* * [Use the cane to reach under the bed ]
- - Positioning the cane above the carpet, I gave the glinting thing a sharp tap. It slid out from under the foot of the bed.
~ move_to_supporter( knifeState, on_floor )
SPAWN_AT(knife-on-floor, knife)
* * (standup) [Stand up]
Satisfied, I stood up, and saw I had knocked free a bloodied knife.
CUTSCENE(visited, visit-bed)
-> top
* * [Look under the bed once more]
Moving the cane aside, I looked under the bed once more, but there was nothing more there.
-> standup
+ (knock_with_what) {reaching && ( TURNS_SINCE(-> reaching) < 4 or Inventory !? cane ) } [tag: bed]
Whatever was under the bed was enough back that I wouldn't be able to reach it without some kind of tool.
* {knifeState ? on_floor} [tag: knife]
Careful not to touch the handle, I lifted the blade from the carpet.
~ get(knife)
The blood was dry enough. Dry enough to show up partial prints on the hilt!
~ reach (prints_on_knife)
* [tag: desk]
I turned my attention to the desk. A lamp sat in one corner, a neat, empty in-tray in the other. There was nothing else out.
{Inventory !? cane: Leaning against the desk was a wooden cane.}
~ bedroomLightState += seen
- - (deskstate)
* * { bedroomLightState !? on } [Turn on the lamp]
-> operate_lamp ->
* * [Look at the in-tray ]
I regarded the in-tray, but there was nothing to be seen. Either the victim's papers were taken, or his line of work had seriously dried up. Or the in-tray was all for show.
+ + (open) {open < 3} [Open a drawer]
I tried {a drawer at random|another drawer|a third drawer}. {Locked|Also locked|Unsurprisingly, locked as well}.
* * {deskstate >= 2} [Something else?]
I took a step away from the desk once more.
CUTSCENE(visited, visit-desk)
-> top
- - -> deskstate
* (pickup_cane) {Inventory !? cane} [tag: cane]
~ get(cane)
I picked up the wooden cane. It was heavy, and unmarked.
* * {(Inventory ? cane) && TURNS_SINCE(-> pickup_cane) <= 2} [Swoosh the cane]
I was still holding the cane: I gave it an experimental swoosh. It was heavy indeed, though not heavy enough to be used as a bludgeon.
But it might have been useful in self-defence. Why hadn't the victim reached for it? Knocked it over?
* * [Something else?]
* [tag: window]
I went over to the window and peered out. A dismal view of the little brook that ran down beside the house.
- - (window_opts)
<- compare_prints(-> window_opts)
* * (downy) [Look down at the brook]
{ GlassState ? steamed:
Through the steamed glass I couldn't see the brook. -> see_prints_on_glass -> window_opts
}
I watched the little stream rush past for a while. The house probably had damp but otherwise, it told me nothing.
* * (greasy) [Look at the glass]
{ GlassState ? steamed: -> downy }
The glass in the window was greasy. No one had cleaned it in a while, inside or out.
* * { GlassState ? steamed && not see_prints_on_glass && downy && greasy }
[ Look at the steam ]
A cold day outside. Natural my breath should steam. -> see_prints_on_glass ->
+ + {GlassState ? steam_gone} [ Breathe on the glass ]
I breathed gently on the glass once more. { reached (fingerprints_on_glass): The fingerprints reappeared. }
~ GlassState = steamed
+ + [Something else?]
{ window_opts < 2 || reached (fingerprints_on_glass) || GlassState ? steamed:
I looked away from the dreary glass.
{GlassState ? steamed:
~ GlassState = steam_gone
<> The steam from my breath faded.
}
CUTSCENE(visited, visit-window)
-> top
}
I leant back from the glass. My breath had steamed up the pane a little.
~ GlassState = steamed
- - -> window_opts
* {top >= 5} [tag: exit-room]
I'd seen enough. I {bedroomLightState ? on:switched off the lamp, then} turned and left the room.
CUTSCENE(visited, switch-light-off)
SPAWN_AT(lamp-on-desk, lamp)
-> joe_in_hall
- -> top
= operate_lamp
I flicked the light switch.
{ bedroomLightState ? on:
<> The bulb fell dark.
~ bedroomLightState += off
~ bedroomLightState -= on
CUTSCENE(visited, switch-light-off)
- else:
{ bedroomLightState ? on_floor:
- <> A little light spilled under the bed.
CUTSCENE(visited, light-floor)
}
{ bedroomLightState ? on_desk :
- <> The light gleamed on the polished tabletop.
CUTSCENE(visited, light-desk)
}
~ bedroomLightState -= off
~ bedroomLightState += on
}
->->
= compare_prints (-> backto)
* { between ((fingerprints_on_glass, prints_on_knife), fingerprints_on_glass_match_knife) }
[Compare the prints between knife and window ]
Holding the bloodied knife near the window, I breathed to bring out the prints once more, and compared them as best I could.
Hardly scientific, but they seemed very similar - very similiar indeed.
~ reach (fingerprints_on_glass_match_knife)
-> backto
= see_prints_on_glass
~ reach (fingerprints_on_glass)
{But I could see a few fingerprints, as though someone had pressed their palm against it.|The fingerprints were quite clear and well-formed.} They faded as I watched.
~ GlassState = steam_gone
->->
= seen_light
+ [tag: lamp]
+ + {bedroomLightState !? on} [ Turn on lamp ]
-> operate_lamp ->
+ + {bedroomLightState ? on} [ Turn off lamp ]
-> operate_lamp ->
* * { bedroomLightState !? on_bed && BedState ? bloodstain_visible }
[ Move the light to the bed ]
SPAWN_AT(lamp-on-bed, lamp)
{bedroomLightState ? on:
- CUTSCENE(visited, light-floor)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_bed)
I moved the light over to the bloodstain and peered closely at it. It had soaked deeply into the fibres of the cotton sheet.
There was no doubt about it. This was where the blow had been struck.
~ reach (murdered_in_bed)
* * { bedroomLightState !? on_desk } {TURNS_SINCE(-> floorit) >= 2 }
[ Move the light back to the desk ]
SPAWN_AT(lamp-on-desk, lamp)
{bedroomLightState ? on:
- CUTSCENE(visited, light-desk)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_desk)
I moved the light back to the desk, setting it down where it had originally been.
* * (floorit) { bedroomLightState !? on_floor && darkunder }
[Move the light to the floor ]
SPAWN_AT(lamp-on-floor, lamp)
CUTSCENE(visited, move-away-from-light-floor)
{bedroomLightState ? on:
- CUTSCENE(visited, light-floor)
- else: CUTSCENE(visited, switch-light-off)
}
~ move_to_supporter(bedroomLightState, on_floor)
I picked the light up and set it down on the floor.
+ + [Something else?]
- -> top
=== joe_in_hall
My police contact, Joe, was waiting in the hall. #TITLE
SPAWN_AT(player-in-hall)
+ [tag: joe] 'So?' he demanded. 'Did you find anything interesting?'
- (found)
* {found == 1} [Nothing.]
He shrugged. 'Shame.'
-> done
* { Inventory ? knife } [I found the murder weapon]
'Good going!' Joe replied with a grin. 'We thought the murderer had gotten rid of it. I'll bag that for you now.'
~ move_to_supporter(knifeState, with_joe)
* {reached(prints_on_knife)} { knifeState ? with_joe } [There are prints on the blade]
He regarded them carefully.
'Hrm. Not very complete. It'll be hard to get a match from these.'
~ reach (joe_seen_prints_on_knife)
* { reached((fingerprints_on_glass_match_knife, joe_seen_prints_on_knife)) }
[They match some prints on the window]
'Anyone could have touched the window,' Joe replied thoughtfully. 'But if they're more complete, they should help us get a decent match!'
~ reach (joe_wants_better_prints)
* { between(body_on_bed, murdered_in_bed)}
[The body was moved to the bed.]
'And then, at some point, moved back to the floor.' I added
'Why?'
* * [I don't know]
Joe nods. 'All right.'
* * [To get something from the floor?]
'You wouldn't move a whole body for that.'
* * [Perhaps he was killed in bed]
'It's just speculation at this point,' Joe remarks.
* { reached(murdered_in_bed) }
[The victim was murdered in bed]
'And then the body was moved to the floor.' I added
'Why?'
* * [I don't know]
Joe nods. 'All right, then.'
* * [The murderer wanted to mislead us?]
'How so?'
'They wanted us to think...
* * * ...the victim was awake[.'], I replied thoughtfully. 'That they were meeting their attacker, rather than being stabbed in their sleep.'
* * * ...there was some kind of struggle[.'],' I replied. 'That the victim wasn't simply stabbed in their sleep.'
- - - 'But if they were killed in bed, that's most likely what happened. Stabbed, while sleeping.'
~ reach (murdered_while_asleep)
* * [They hoped to clean up the scene?]
'But they were disturbed? It's possible.'
* { found > 1} [That's it]
'All right. It's a start,' Joe replied.
-> done
- -> found
- (done)
{
- between(joe_wants_better_prints, joe_got_better_prints):
~ reach (joe_got_better_prints)
<> 'I'll get those prints from the window now.'
- reached(joe_seen_prints_on_knife):
<> 'I'll run those prints as best I can.'
- else:
<> 'Not much to go on.'
}
THE END #TITLE
CUTSCENE(visited, ending)
-> END</script>
<script id="font-embed" type="text" data-char-width="6" data-char-height="8" data-runs="0,9786-9787,9829-9830,9827,9824,8226,9688,9675,9689,9794,9792,9834-9835,9788,9658,9668,8597,8252,182,167,9644,8616,8593,8595,8594,8592,8735,8596,9650,9660,32-126,8962,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196-197,201,230,198,244,246,242,251,249,255,214,220,162-163,165,8359,402,225,237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,9617-9619,9474,9508,9569-9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566-9567,9562,9556,9577,9574,9568,9552,9580,9575-9576,9572-9573,9561,9560,9554-9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAACACAMAAADDApyIAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAABWtJREFUaN7tWkuW2zAMI+5/6S5qSwQIUnYy01XdNi91LEGk+IUVcV0A1iddcgPAeih/X2PXb3UaxDUAaVYe1gAAuGa4Zgbi/rPGpZsZRiW7JsU95/WRAOLvWLA+sgQ3wF77urP+XQu4vl2fAvh30QvgFogBBNICIFiWOElg1l72IKsIsZWJtQWyB6xrqBWVPaDv1/+xBSi2+PzqzbQfQktdUgepKz8K5x9m0m3E2zNuhYO3vVdjAUvGm72EbCYDZHWSRQUtSwF4KcsqVEUhXl1WnSGRFlEAnAQJhyQw+s2GfPucSkl7QM53+0eor8pODACNFcUOAJg3luT75vpuhu3i7MKxYk322MBHq7sAkGPL3ovgjCJWP3vxPV3sLcqS0DyoMQrn+Y03dgpBWD9wW42YAJL1cfJ7LAGmgLnC0vJoC1BSTUr5aOFywMo5rDiMrMt//7ELB/dBrY7AMccFss4mc3jfithlxzIjyFDIM5NN3jPLloCMHzo/A0AdEIC6I+etFLqXiiTYLRUxAHzo2YqAqgJ7K7awOTRj2mTQB8pAWIXor1yl2DrKZzQeQfaQaqtSBnln/E0PsBLw91oOL/tBNdxiY2r7/jPc4GTWkpM4qVz20kwKk4UdQDaQ/Ce0ggMAWW9WV9TC667Ui5RQCcByxCMVwUhQwkn3wxuAaR6yjdaKdiYSC+GxcFb06xcGP8DJiGtuqFm6Gyxabp6xcVI67WZjHQAoT8jc0JxBKuqqaANAtb0JbT7RpfVFtCqClHkwXV4LUKI/59XStRkAX9BsdkTtt9RuRfu9Ff0r+9ceEUPxbdvqyFVlX4qeATClrxNA0rV2zijZGJSwuQNKvS/g9uMUEnLs1MoqKHijult0+SBJ0AIgzgBzPiAVHSSIUYJ5D1gCJPfMd4Si+q5P/ldeBcPZPeOUXlV2ZVeyqu8NLDm5BEFSPYA+XK8KjEsMSBs5AVQzzfuCrkAPtn2oheeBGBJOD8A5AMwCQYqdSUUSfyAxpLbaUSKPadJOvecbw3zMHAgnlMjNqHHR/CodmXCPT9aOB64Pk04gST8Kk1prUPOrYXsQ2tlJ/HOfQ/1cpg5URxOLqp+mJWnYSFu+49grhPQ/vuIyTBgM5+wkMIwMarsMOFLlc+N/OZCzWHq5QS86NAKmaZDaQlsHfSYNxUXK0tTLhxCwRNUMf6NkBYShRJEbubd/Q6kHazKQxPMOQCQAbHRqAZByA1oVsQ6YZVs5GY4LojqsMkW6akm+n9r08xdonemgePjchL1LW7WpRTNad3tmfsM+WrYO+3LECWRBujnEh9WSVjP5Ci3QYoVaRW+g/F7TNMPaRQMiAYwEEA8wb/+HLqylW9jq1ZUstyJ1PeLnuNI3rOo+jWBfN40VCZo78Cj+HWTw+QhkThH9HaY9C9s5RJUzK/lEAlCIjFIEKEPaFgqHPcgSYCxrDi8auz0AEN8BnPcgfleCnwDA9OK0mbT6h/v+BgDE0QfSGRfsdIt6/wMJZlqqJdcypr0jLwJkvZMEfX71XhpjFDqUoP8BDAC+KeKTjVCJRTTAquHxFkBNbQB4KwHq1QGYJ8djMOiuVoKxHHk09fcAeHJ9BoDn11sAvL3GTZYibzYm1JNpOBmc1NI4EUPhmLtSpkaWQPpFaUKZflA+tbJcRBEZDhx85EyLF32jwLQn8q84SKA0LJTjo1VzZXIEoDMvMJQTLDECd7bEq4jCX7eBAThixFjRDxHxH5zAgDAlfPK2nH+Atrd68qYHPQHY52HaLC1YVt01A5S3Qq0E+UivvBg9AxBF1LAO+YD1a4BE3qHQ+2yLeqzkDAACwERJiBYf7UHmTeZoWYL8OyuSuP8H7ZUOIucBHAwAAAAASUVORK5CYII=</script>
</body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment