<!--Saved by Quest 5.8.6836.13983-->
<asl version="580">
  <implied element="object" property="alt" type="simplestringlist" />
  <implied element="command" property="pattern" type="simplepattern" />
  <implied element="command" property="script" type="script" />
  <implied element="command" property="multiple" type="AssociatedScope" />
  <implied element="object" property="displayverbs" type="simplestringlist" />
  <implied element="object" property="inventoryverbs" type="simplestringlist" />
  <implied element="walkthrough" property="steps" type="simplestringlist" />
  <implied element="timer" property="interval" type="int" />
  <implied element="timer" property="script" type="script" />
  <implied element="turnscript" property="script" type="script" />
  <template name="LanguageId">en</template>
  <template name="WantRestartGame">Are you sure you want to restart the game?</template>
  <template name="Again1">again</template>
  <template name="Again2">g</template>
  <template name="NothingToRepeat">There is nothing to repeat.</template>
  <template name="UnresolvedObject">I can't see that.</template>
  <template name="UnresolvedLocation">You can't go there.</template>
  <template name="DefaultObjectDescription">Nothing out of the ordinary.</template>
  <template name="DefaultSelfDescription">Looking good.</template>
  <template name="SeeListHeader">You can see</template>
  <template name="GoListHeader">You can go</template>
  <template name="And">and</template>
  <template name="Nothing">nothing</template>
  <template name="Or">or</template>
  <template name="NothingToUndo">Nothing to undo!</template>
  <template name="NotCarryingAnything">You are not carrying anything.</template>
  <template name="CarryingListHeader">You are carrying</template>
  <template name="UnrecognisedCommand">I don't understand your command.</template>
  <template name="YouAreIn">You are in</template>
  <template name="LookAt">Look at</template>
  <template name="Take">Take</template>
  <template name="SpeakTo">Speak to</template>
  <template name="Use">Use</template>
  <template name="Drop">Drop</template>
  <template name="GoTo">Go to</template>
  <template name="Go">Go</template>
  <template name="SwitchOn">Switch on</template>
  <template name="SwitchOff">Switch off</template>
  <template name="Open">Open</template>
  <template name="Close">Close</template>
  <template name="Eat">Eat</template>
  <template name="NeutralGender">it</template>
  <template name="MaleGender">he</template>
  <template name="FemaleGender">she</template>
  <template name="SelfGender">you</template>
  <template name="NeutralPluralGender">they</template>
  <template name="MalePluralGender">they</template>
  <template name="FemalePluralGender">they</template>
  <template name="NeutralArticle">it</template>
  <template name="MaleArticle">him</template>
  <template name="FemaleArticle">her</template>
  <template name="SelfArticle">yourself</template>
  <template name="NeutralPluralArticle">them</template>
  <template name="MalePluralArticle">them</template>
  <template name="FemalePluralArticle">them</template>
  <template name="NeutralPossessive">its</template>
  <template name="MalePossessive">his</template>
  <template name="FemalePossessive">her</template>
  <template name="SelfPossessive">your</template>
  <template name="NeutralPluralPossessive">their</template>
  <template name="MalePluralPossessive">their</template>
  <template name="FemalePluralPossessive">their</template>
  <template name="SelfAlias">me</template>
  <template name="SelfAlt">me; myself; self</template>
  <template name="AllObjects">all; everything</template>
  <template name="ParserIgnorePrefixes">the; a; an</template>
  <template name="UseDefaultPrefixIfNamed">false</template>
  <template name="Score">Score</template>
  <template name="Health">Health</template>
  <template name="Money">Money</template>
  <template name="CannotDoThat">You can't do that.</template>
  <template name="Done">Done.</template>
  <template name="ContainerContentsPrefix">containing</template>
  <template name="SurfaceContentsPrefix">on which there is</template>
  <template name="LockedExit">That way is locked.</template>
  <template name="NoKey">You do not have the key.</template>
  <template name="UnlockMessage">Unlocked.</template>
  <template name="LockMessage">Locked.</template>
  <template name="DefaultOops">There is nothing to correct.</template>
  <template name="VerbObjectSeparator">with; using</template>
  <template name="DefaultMultiObjectVerb">That doesn't work.</template>
  <template name="MultiObjectVerbMenu">With which object?</template>
  <template name="UseOnMenu">On which object?</template>
  <template name="GiveToMenu">To which object?</template>
  <template name="NoObjectsAvailable">There are no objects available to do that with.</template>
  <template name="Yes">Yes</template>
  <template name="No">No</template>
  <template name="By">by</template>
  <template name="NothingToTake">Nothing here to take.</template>
  <template name="NothingToDrop">You've nothing to drop.</template>
  <template name="NothingToWear">You've nothing to wear.</template>
  <template name="NothingToRemove">You've nothing to take off.</template>
  <template name="NeutralWornModifier">worn</template>
  <template name="MaleWornModifier">worn</template>
  <template name="FemaleWornModifier">worn</template>
  <template name="NeutralPluralWornModifier">worn</template>
  <template name="MalePluralWornModifier">worn</template>
  <template name="FemalePluralWornModifier">worn</template>
  <template name="Wear">Wear</template>
  <template name="wear">put #object# on; wear; put on; don; wear</template>
  <template name="Remove">Remove</template>
  <template name="remove">take #object# off; remove; take off; doff</template>
  <template name="CompassNW">northwest</template>
  <template name="CompassN">north</template>
  <template name="CompassNE">northeast</template>
  <template name="CompassW">west</template>
  <template name="CompassE">east</template>
  <template name="CompassSW">southwest</template>
  <template name="CompassS">south</template>
  <template name="CompassSE">southeast</template>
  <template name="CompassUp">up</template>
  <template name="CompassDown">down</template>
  <template name="CompassIn">in</template>
  <template name="CompassOut">out</template>
  <template name="CompassDirectionPrefix"></template>
  <template name="CompassDirectionSuffix"></template>
  <template name="UpDownDirectionPrefix"></template>
  <template name="UpDownDirectionSuffix"></template>
  <template name="InOutDirectionPrefix"></template>
  <template name="InOutDirectionSuffix"></template>
  <template name="CompassNWShort">nw</template>
  <template name="CompassNShort">n</template>
  <template name="CompassNEShort">ne</template>
  <template name="CompassWShort">w</template>
  <template name="CompassEShort">e</template>
  <template name="CompassSWShort">sw</template>
  <template name="CompassSShort">s</template>
  <template name="CompassSEShort">se</template>
  <template name="CompassUpShort">u</template>
  <template name="CompassDownShort">d</template>
  <template name="CompassInShort"></template>
  <template name="CompassOutShort">o</template>
  <template name="InventoryLabel">Inventory</template>
  <template name="StatusLabel">Status</template>
  <template name="PlacesObjectsLabel">Places and Objects</template>
  <template name="CompassLabel">Compass</template>
  <template name="InButtonLabel">in</template>
  <template name="OutButtonLabel">out</template>
  <template name="EmptyListLabel">(empty)</template>
  <template name="NothingSelectedLabel">(nothing selected)</template>
  <template name="TypeHereLabel">Type here...</template>
  <template name="ContinueLabel">Continue...</template>
  <template name="go"><![CDATA[^go to (?<exit>.*)$|^go (?<exit>.*)$|^(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$]]></template>
  <template name="lookdir"><![CDATA[^look (?<exit>north|east|south|west|northeast|northwest|southeast|southwest|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$]]></template>
  <template name="look">^look$|^l$</template>
  <template name="lookat">look at; look; x; examine; exam; ex</template>
  <template name="take">take; get; pick up</template>
  <template name="undo">^undo$</template>
  <template name="inventory">^i$|^inv$|^inventory$</template>
  <template name="quit">^quit$</template>
  <template name="drop">drop</template>
  <template name="use">use</template>
  <template name="speakto">speak to; speak; talk to; talk</template>
  <template name="open">open</template>
  <template name="close">close</template>
  <template name="put"><![CDATA[^(put|insert|place|drop) (?<object1>.*) (on|in|on to|in to|into) (?<object2>.*)$]]></template>
  <template name="removefrom"><![CDATA[^(remove|take|get|eject) (?<object1>.*) (from|out of|off|out) (?<object2>.*)$]]></template>
  <template name="ask"><![CDATA[^ask (?<object>.*) about (?<text>.*)$]]></template>
  <template name="tell"><![CDATA[^tell (?<object>.*) about (?<text>.*)$]]></template>
  <template name="tellto"><![CDATA[^(tell|ask) (?<object>.*) to (?<text>.*)$]]></template>
  <template name="alttellto"><![CDATA[^(?<object>.*), (?<text>.*)$]]></template>
  <template name="oops"><![CDATA[^oops (?<text>.*)$]]></template>
  <template name="buy">buy; purchase</template>
  <template name="climb">climb</template>
  <template name="drink">drink</template>
  <template name="eat">eat</template>
  <template name="givesingle">give</template>
  <template name="give"><![CDATA[^give (?<object1>.*) to (?<object2>.*)$]]></template>
  <template name="hit">hit</template>
  <template name="kill">kill</template>
  <template name="kiss">kiss</template>
  <template name="knock">knock</template>
  <template name="lick">lick</template>
  <template name="lie">lie on; lie upon; lie down on; lie down upon</template>
  <template name="listento">listen to</template>
  <template name="lock">lock</template>
  <template name="move">move</template>
  <template name="pull">pull</template>
  <template name="push">push</template>
  <template name="read">read</template>
  <template name="search">search</template>
  <template name="show">show</template>
  <template name="sit">sit on; sit upon; sit down on; sit down upon</template>
  <template name="smell">smell; sniff</template>
  <template name="taste">taste</template>
  <template name="throw">throw</template>
  <template name="tie">tie</template>
  <template name="touch">touch</template>
  <template name="turnon">turn on; turn #object# on; switch on; switch #object# on</template>
  <template name="turnoff">turn off; turn #object# off; switch off; switch #object# off</template>
  <template name="turn">turn</template>
  <template name="unlock">unlock</template>
  <template name="untie">untie</template>
  <template name="useon"><![CDATA[^use (?<object1>.*) (on|with) (?<object2>.*)$]]></template>
  <template name="listen">^listen$</template>
  <template name="DefaultListen">You can't hear much.</template>
  <template name="jump">^jump$</template>
  <template name="DefaultJump">You jump, but nothing happens.</template>
  <template name="sitdown">^sit$|^sit down$</template>
  <template name="DefaultSitDown">No time for lounging about now.</template>
  <template name="liedown">^lie$|^lie down$</template>
  <template name="DefaultLieDown">No time for lounging about now.</template>
  <template name="sleep">^sleep$|^rest$</template>
  <template name="DefaultSleep">No time for lounging about now.</template>
  <template name="wait">^wait$|^z$</template>
  <template name="DefaultWait">Time passes.</template>
  <template name="xyzzy">^xyzzy$</template>
  <template name="DefaultXyzzy">Surprisingly, absolutely nothing happens.</template>
  <template name="help">^help$|^\?$</template>
  <template name="save">^save$</template>
  <template name="DefaultHelp"><![CDATA[<u>Quick Help</u><br/><br/>
<b>- Objects:</b>  Try LOOK AT..., SPEAK TO..., TAKE..., DROP..., OPEN..., GIVE... TO..., USE... ON/WITH...<br/>
<b>- Inventory:</b>  See which items you are carrying by typing I, INV or INVENTORY.<br/>
<b>- Moving around:</b>  Press the compass buttons, or type GO NORTH, SOUTH, E, GO TO...<br/>
<b>- Shortcuts:</b>  Press the up arrow and down arrow to scroll through commands you have already typed in. Try X... as a shortcut for LOOK AT...]]></template>
  <template name="LanguageSpecificObjectTypes"></template>
  <template name="EditorVerbDefaultExpression">"You can't #verb# " + object.article + "."</template>
  <template name="log_cmd">^log$|^view log$|^display log$</template>
  <template name="transcript_on_cmd">^(transcript|script)( on|)$|^enable (script|transcript)$</template>
  <template name="transcript_off_cmd">^(transcript|script) off$|^disable (script|transcript)$</template>
  <template name="view_transcript_cmd">^(view|display|show) (the |)(script|transcript)$</template>
  <template name="version_cmd">^(version|info|about)$</template>
  <template name="DevModeErrorWrongFormat">That's the wrong format.</template>
  <template name="DevModeErrorObjectNotRecognised">The object was not found.</template>
  <template name="DevModeErrorWrongTyp">That's the wrong type.</template>
  <template name="DevModeErrorWrongKey">The key was not found.</template>
  <template name="DevModeExecuteCommand">The command was executed.</template>
  <template name="DevModeNotActive">DevMode is not active!</template>
  <template name="DevModeDescriptionCommands"><![CDATA[<h3>FlyScript - Help</h3><b><u>Object-Commends</u></b><br/>#take object<br/>#drop object<br/>#put object1 in object2<br/>#open object<br/>#close object<br/>#on object<br/>#off object<br/>#to player<br/>#go room<br/><br/><i>Unlike the commands in the game, they are executed directly and without detours via intercept scripts.</i><br/><br/><b><u>Single-Commands</u></b><br/>#clr (clear screen)<br/>#? (help)<br/># (close game)<br/><br/><b><u>Object-Attributes</u></b><br/>#object1.attribute=object2.attribute (attribute assignment of another object)<br/>#object.attribute=true / false (set true / false)<br/>#object.attribute=? / ! (set true / false)<br/>#~object.attribute (toggle true or false)<br/>#object.attribute="value" (string)<br/>#object.attribute=15 (integer)<br/>#object.attribute=25.55 (double)<br/>#object.attribute=[item1,item2,item3] (list)<br/>#object.attribute[]=element (add element to list)<br/>#object.attribute[key]=element (add or overwrite element to list)<br/>#object.attribute=[] (create new list)<br/>#object.attribute={key1:item1,key2:item2,key3:item3} (dictionary)<br/>#object.attribute{key}=element (add or overwrite element to dictionary)<br/>#object.attribute={} (create new dictionary)<br/>#object.attribute (read attribute)<br/>]]></template>
  <template name="DevModeActive"><![CDATA[<b>DevMode: Active</b>]]></template>
  <template name="DevModeInitDegugTable">Debug table initialized.</template>
  <template name="DevModeStartScript">Initialization script started.</template>
  <template name="DevModeSetVerbs">Verbs assigned.</template>
  <template name="DevModeComExecute">Command executed.</template>
  <template name="DevModeComSetAttribute">Set Attribute: </template>
  <template name="DevModeComGetAttribute">Get Attribute: </template>
  <template name="DevModeComSelfTestFailed">The assignment as it should be after the command is incorrect.</template>
  <dynamictemplate name="TakeSuccessful">"You pick " + object.article + " up."</dynamictemplate>
  <dynamictemplate name="TakeUnsuccessful">"You can't take " + object.article + "."</dynamictemplate>
  <dynamictemplate name="FullInventory">WriteVerb(object, "be") + " too heavy to be taken."</dynamictemplate>
  <dynamictemplate name="MaxObjectsInInventory">"You can't carry any more items."</dynamictemplate>
  <dynamictemplate name="MaxObjectsInContainer">"You can't put more items in " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DropSuccessful">"You drop " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DropUnsuccessful">"You can't drop " + object.article + "."</dynamictemplate>
  <dynamictemplate name="ObjectCannotBeStored">"You can't put " + object.article + " there."</dynamictemplate>
  <dynamictemplate name="AlreadyTaken">"You are already carrying " + object.article + "."</dynamictemplate>
  <dynamictemplate name="NotCarrying">"You are not carrying " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CantUse">"You can't use " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CantGive">"You can't give " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultSpeakTo">WriteVerb(object, "say") + " nothing."</dynamictemplate>
  <dynamictemplate name="ObjectNotOpen">CapFirst(GetDefiniteName(object)) + " " + Conjugate(object, "be") + " not open."</dynamictemplate>
  <dynamictemplate name="AlreadyOpen">WriteVerb(object, "be") + " already open."</dynamictemplate>
  <dynamictemplate name="AlreadyClosed">WriteVerb(object, "be") + " already closed."</dynamictemplate>
  <dynamictemplate name="CantOpen">"You can't open " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CantClose">"You can't close " + object.article + "."</dynamictemplate>
  <dynamictemplate name="OpenSuccessful">"You open " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CloseSuccessful">"You close " + object.article + "."</dynamictemplate>
  <dynamictemplate name="AlreadyThere">WriteVerb(object, "be") + " already there."</dynamictemplate>
  <dynamictemplate name="ObjectContains">WriteVerb(object, "contain")</dynamictemplate>
  <dynamictemplate name="ContainerFull">WriteVerb(object, "be") + " full."</dynamictemplate>
  <dynamictemplate name="DisambiguateMenu">"Please choose which '" + text + "' you mean:"</dynamictemplate>
  <dynamictemplate name="UndoTurn">"Undo: " + text</dynamictemplate>
  <dynamictemplate name="DefaultAsk">WriteVerb(object, "do") + " not reply."</dynamictemplate>
  <dynamictemplate name="DefaultTell">WriteVerb(object, "do") + " not reply."</dynamictemplate>
  <dynamictemplate name="LockedObject">WriteVerb(object, "be") + " locked."</dynamictemplate>
  <dynamictemplate name="AlreadyLocked">WriteVerb(object, "be") + " already locked."</dynamictemplate>
  <dynamictemplate name="AlreadyUnlocked">WriteVerb(object, "be") + " already unlocked."</dynamictemplate>
  <dynamictemplate name="CannotLockOpen">"You cannot lock " + object.article + " when " + object.gender + " " + Conjugate(object, "be") + " open."</dynamictemplate>
  <dynamictemplate name="AlreadySwitchedOn">WriteVerb(object, "be") + " already switched on."</dynamictemplate>
  <dynamictemplate name="AlreadySwitchedOff">WriteVerb(object, "be") + " already switched off."</dynamictemplate>
  <dynamictemplate name="SwitchedOn">"You switch " + object.article + " on."</dynamictemplate>
  <dynamictemplate name="SwitchedOff">"You switch " + object.article + " off."</dynamictemplate>
  <dynamictemplate name="Eaten">"You eat " + object.article + "."</dynamictemplate>
  <dynamictemplate name="ObjectDoesNotContain">CapFirst(GetDisplayAlias(object1)) + " " + Conjugate(object1, "do") + " not contain " + GetDisplayAlias(object2) + "."</dynamictemplate>
  <dynamictemplate name="YouLooking">"You are looking " + text +"."</dynamictemplate>
  <dynamictemplate name="LookAtDarkness">"It is too dark to make anything out."</dynamictemplate>
  <dynamictemplate name="WearSuccessful">"You put " + object.article + " on."</dynamictemplate>
  <dynamictemplate name="WearUnsuccessful">"You can't wear " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CannotWearIfNotHeld">"You would need to get " + object.article + " before you can put " + object.article + " on."</dynamictemplate>
  <dynamictemplate name="CannotRemoveIfNotHeld">"You would need to get " + object.article + " before you can take " + object.article + " off."</dynamictemplate>
  <dynamictemplate name="AlreadyWearing">"You are already wearing " + object.article + "."</dynamictemplate>
  <dynamictemplate name="CannotRemoveIfNotWearing">"You are not wearing " + object.article + "."</dynamictemplate>
  <dynamictemplate name="NotRemovable">"You cannot remove " + object.article + "!"</dynamictemplate>
  <dynamictemplate name="CannotWearOver">"You cannot wear that over " + GetDisplayGarment(object) + "."</dynamictemplate>
  <dynamictemplate name="CannotWearWith">"You cannot wear that while wearing " + GetDisplayGarment(object) + "."</dynamictemplate>
  <dynamictemplate name="RemoveSuccessful">"You take " + object.article + " off."</dynamictemplate>
  <dynamictemplate name="RemoveFirst">"You can't remove that while wearing " + GetDisplayGarment(object) + "."</dynamictemplate>
  <dynamictemplate name="DefaultBuy">"You can't buy " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultClimb">"You can't climb " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultDrink">"You can't drink " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultEat">"You can't eat " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultGive">WriteVerb(object1, "do") + " not want " + object2.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultHit">"You can't hit " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultKill">"You can't kill " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultKiss">"You can't kiss " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultKnock">"You can't knock " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultLick">"You can't lick " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultLie">"You can't lie on " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultListenTo">"You listen, but " + object.gender + " makes no sound."</dynamictemplate>
  <dynamictemplate name="DefaultLock">"You can't lock " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultMove">"You can't move " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultPull">"You can't pull " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultPush">"You can't push " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultRead">"You can't read " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultSearch">"You can't search " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultShow">"You can't show " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultSit">"You can't sit on " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultSmell">"You sniff, but " + object.gender + " doesn't smell of much."</dynamictemplate>
  <dynamictemplate name="DefaultTaste">"You can't taste " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultThrow">"You can't throw " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultTie">"You can't tie " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultTouch">"You can't touch " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultTurnOn">"You can't turn " + object.article + " on."</dynamictemplate>
  <dynamictemplate name="DefaultTurnOff">"You can't turn " + object.article + " off."</dynamictemplate>
  <dynamictemplate name="DefaultTurn">"You can't turn " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultUnlock">"You can't unlock " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultUntie">"You can't untie " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultUseOn">"You can't use " + object2.article + " that way."</dynamictemplate>
  <dynamictemplate name="DefaultWear">"You can't wear " + object.article + "."</dynamictemplate>
  <dynamictemplate name="DefaultTellTo">WriteVerb(object, "do") + " nothing."</dynamictemplate>
  <dynamictemplate name="DevModeErrorCantFindObject">"The object with the name '" + text + "' cannot be found."</dynamictemplate>
  <dynamictemplate name="DevModeErrorCantFindAttribute">"The attribute with the name '" + text + "' cannot be found."</dynamictemplate>
  <delegate name="AddScript" parameters="object" type="" />
  <delegate name="AssociatedScope" parameters="" type="objectlist" />
  <game name="ARC II">
    <inherit name="theme_novella" />
    <gameid>75b4906c-1edd-4f8b-a5fe-76b3194dc05d</gameid>
    <version>1.0</version>
    <firstpublished>2019</firstpublished>
    <menufont>Georgia, serif</menufont>
    <appendobjectdescription />
    <allowlookdirections />
    <attr name="autodescription_youarein_useprefix" type="boolean">false</attr>
    <feature_asktell />
    <attr name="autodescription_youcansee" type="int">3</attr>
    <attr name="autodescription_youcango" type="int">4</attr>
    <attr name="autodescription_description" type="int">2</attr>
    <autodescription_youarein_newline />
    <attr name="autodescription_youcansee_newline" type="boolean">false</attr>
    <attr name="autodescription_youcango_newline" type="boolean">false</attr>
    <autodescription_description_newline />
    <autodisplayverbs />
    <author>Daniel Gao</author>
    <showpanes type="boolean">false</showpanes>
    <gridmap type="boolean">false</gridmap>
    <enablehyperlinks />
    <clearscreenonroomenter type="boolean">false</clearscreenonroomenter>
    <pov type="object">Conor Chase</pov>
    <start type="script">
    </start>
  </game>
  <command name="lookat">
    <pattern>look at #object#; look #object#; x #object#; examine #object#; exam #object#; ex #object#</pattern>
    <script>
      if (GetBoolean(object, "hidechildren")) {
        object.hidechildren = false
      }
      if (TypeOf(object, "look") = "script") {
        if (not HasAttribute(object,"timesexamined")) {
          object.timesexamined = 0
        }
        do (object, "look")
        object.timesexamined = object.timesexamined + 1
      }
      else {
        lookdesc = ""
        if (HasString(object, "look")) {
          lookdesc = object.look
        }
        if (LengthOf(lookdesc) = 0) {
          lookdesc = Template("DefaultObjectDescription")
        }
        if (GetBoolean(object, "switchedon")) {
          if (HasString(object, "switchedondesc")) {
            lookdesc = lookdesc + " " + object.switchedondesc
          }
        }
        else {
          if (HasString(object, "switchedoffdesc")) {
            lookdesc = lookdesc + " " + object.switchedoffdesc
          }
        }
        isDark = CheckDarkness()
        if (isDark and not GetBoolean(object, "lightsource")) {
          lookdesc = DynamicTemplate("LookAtDarkness", object)
        }
        else {
          if (not HasAttribute(object,"timesexamined")) {
            object.timesexamined = 0
          }
          object.timesexamined = object.timesexamined + 1
        }
        msg (lookdesc)
      }
      ListObjectContents (object)
    </script>
  </command>
  <command name="take">
    <pattern>take #object#; get #object#; pick up #object#</pattern>
    <allow_all />
    <scope>notheld</scope>
    <script>
      took_something = false
      foreach (obj, object) {
        // if this is multiple then we should skip anything in a container that has already been taken
        // (always earlier in the list) and anything held by an NPC.
        // Scenery and anything flagged "not_all" will already be excluded
        if (not multiple or (not Contains(game.pov, obj.parent) and not DoesInherit(obj.parent, "npc_type"))) {
          DoTake (obj, multiple)
          took_something = true
        }
      }
      if (multiple and not took_something) {
        msg ("Nothing here to take.")
      }
    </script>
  </command>
  <command name="drop">
    <pattern>drop #object#</pattern>
    <allow_all />
    <scope>inventory</scope>
    <script>
      if (multiple and ListCount(object) = 0) {
        msg ("You are not carrying anything.")
      }
      else {
        foreach (obj, object) {
          if (not multiple or Contains(game.pov, obj)) {
            DoDrop (obj, multiple)
          }
        }
      }
    </script>
  </command>
  <command name="use">
    <pattern>use #object#</pattern>
    <script><![CDATA[
      if (HasScript(object, "use")) {
        do (object, "use")
      }
      else {
        if (GetBoolean(object, "use")) {
          candidates = CreateUseMenuList (object)
          if (ListCount(candidates) = 0) {
            msg (Template("NoObjectsAvailable"))
          }
          else {
            game.pov.usemenuobject = object
            if (HasString(object, "usemenuprompt")) {
              menucaption = object.usemenuprompt
            }
            else {
              menucaption = Template("UseOnMenu")
            }
            ShowMenu (menucaption, candidates, true) {
              if (result <> null) {
                HandleUseOn (game.pov.usemenuobject, GetObject(result))
                game.pov.usemenuobject = null
              }
            }
          }
        }
        else {
          msg (DynamicTemplate("CantUse", object))
        }
      }
    ]]></script>
  </command>
  <command name="undo">
    <pattern type="string">^undo$</pattern>
    <isundo />
    <script>
      undo
      game.suppressturnscripts = true
      if (GetBoolean (game, "gridmap")) {
        Grid_DrawPlayerInRoom (game.pov.parent)
      }
    </script>
  </command>
  <command name="inventory">
    <pattern type="string">^i$|^inv$|^inventory$</pattern>
    <script>
      list = FormatObjectList(Template("CarryingListHeader"), game.pov, Template("And"), ".")
      if (list = "") {
        msg (Template("NotCarryingAnything"))
      }
      else {
        msg (list)
      }
    </script>
  </command>
  <command name="look">
    <pattern type="string">^look$|^l$</pattern>
    <script>
      ShowRoomDescription
    </script>
  </command>
  <command name="lookdir">
    <pattern type="string"><![CDATA[^look (?<exit>north|east|south|west|northeast|northwest|southeast|southwest|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$]]></pattern>
    <script><![CDATA[
      if (HasScript(exit, "look")) {
        do (exit, "look")
      }
      else {
        message = DynamicTemplate("YouLooking",exit.alias)
        if (HasString(exit, "look")) {
          if (exit.look <> "") {
            message = exit.look
          }
        }
        if (exit.locked) {
          if (HasString(exit,"lockmessage")) {
            lockmessage = exit.lockmessage
          }
          else {
            lockmessage = Template("LockedExit")
          }
          msg (message+" "+lockmessage)
        }
        else {
          msg (message)
        }
      }
    ]]></script>
  </command>
  <command name="quit">
    <pattern type="string">^quit$</pattern>
    <script>
      finish
    </script>
  </command>
  <command name="go">
    <pattern type="string"><![CDATA[^go to (?<exit>.*)$|^go (?<exit>.*)$|^(?<exit>north|east|south|west|northeast|northwest|southeast|southwest|in|out|up|down|n|e|s|w|ne|nw|se|sw|o|u|d)$]]></pattern>
    <unresolved>You can't go there.</unresolved>
    <script>
      if (exit.visible) {
        if (exit.locked) {
          msg (exit.lockmessage)
        }
        else if (exit.runscript) {
          if (HasScript(exit, "script")) {
            do (exit, "script")
          }
        }
        else if (exit.lookonly) {
          msg ("You can't go there.")
        }
        else {
          if (HasString(exit, "message")) {
            if (not exit.message = "") {
              if (game.clearscreenonroomenter) {
                game.currentexitmessage = exit.message
              }
              else {
                msg (exit.message)
              }
            }
          }
          game.pov.parent = exit.to
        }
      }
      else {
        msg ("You can't go there.")
      }
    </script>
  </command>
  <command name="open">
    <pattern>open #object#</pattern>
    <script>
      TryOpenClose (true, object)
    </script>
  </command>
  <command name="close">
    <pattern>close #object#</pattern>
    <script>
      TryOpenClose (false, object)
    </script>
  </command>
  <command name="put">
    <pattern type="string"><![CDATA[^(put|insert|place|drop) (?<object1>.*) (on|in|on to|in to|into) (?<object2>.*)$]]></pattern>
    <scope>object1=inventory|object2=container</scope>
    <script>
      // put object1 in/on object 2
      canbedropped = true
      if (HasBoolean(object1, "drop")) {
        if (not object1.drop) {
          canbedropped = false
        }
      }
      if (object1.parent = object2) {
        msg (DynamicTemplate("AlreadyThere", object1))
      }
      else if (not ListContains(ScopeInventory(), object1)) {
        msg (DynamicTemplate("NotCarrying", object1))
      }
      else if (not canbedropped) {
        msg (DynamicTemplate("ObjectCannotBeStored", object1))
      }
      else if (not ListContains(ScopeReachable(), object1)) {
        msg (BlockingMessage(object1, ""))
      }
      else if (not ListContains(ScopeReachable(), object2)) {
        msg (BlockingMessage(object2, ""))
      }
      else if (not object2.container) {
        msg (Template("CannotDoThat"))
      }
      else if (not object2.isopen) {
        msg (DynamicTemplate("ObjectNotOpen", object2))
      }
      else if (ListContains(ListParents(object2), object1)) {
        msg (Template("CannotDoThat"))
      }
      else {
        if (GetBoolean(object2, "hidechildren")) {
          object2.hidechildren = false
        }
        params = NewDictionary()
        dictionary add (params, "object", object1)
        dictionary add (params, "destination", object2)
        if (HasScript(object2, "addscript")) {
          do (object2, "addscript", params)
        }
        else if (HasScript(object1, "drop")) {
          do (object1, "drop", params)
        }
        else {
          object1.parent = object2
          msg (Template("Done"))
        }
      }
      // must be carrying object1
      // item cannot be dropped
      // object1 must not be inside a closed container
      // object2 must not be inside a closed container
      // object2 must be an open container or surface
      // object1 is inside object 2
    </script>
  </command>
  <command name="removefrom">
    <pattern type="string"><![CDATA[^(remove|take|get|eject) (?<object1>.*) (from|out of|off|out) (?<object2>.*)$]]></pattern>
    <scope>object1=contents|object2=container</scope>
    <script>
      // remove object1 from object2
      // if object2 does indeed contain object1, this is a synonym for "take object1"
      if (not Contains(object2, object1)) {
        msg (DynamicTemplate("ObjectDoesNotContain", object2, object1))
      }
      else {
        DoTake (object1, false)
      }
    </script>
  </command>
  <command name="givesingle">
    <pattern>give #object#</pattern>
    <script><![CDATA[
      if (HasScript(object, "givesingle")) {
        do (object, "givesingle")
      }
      else {
        if (GetBoolean(object, "givesingle")) {
          candidates = CreateGiveMenuList (object)
          if (ListCount(candidates) = 0) {
            msg (Template("NoObjectsAvailable"))
          }
          else {
            game.pov.givemenuobject = object
            if (HasString(object, "givemenuprompt")) {
              menucaption = object.givemenuprompt
            }
            else {
              menucaption = Template("GiveToMenu")
            }
            ShowMenu (menucaption, candidates, true) {
              if (result <> null) {
                HandleGiveTo (game.pov.givemenuobject, GetObject(result))
                game.pov.givemenuobject = null
              }
            }
          }
        }
        else {
          msg (DynamicTemplate("CantGive", object))
        }
      }
    ]]></script>
  </command>
  <command name="give">
    <pattern type="string"><![CDATA[^give (?<object1>.*) to (?<object2>.*)$]]></pattern>
    <script>
      HandleGiveTo (object1, object2)
    </script>
  </command>
  <command name="useon">
    <pattern type="string"><![CDATA[^use (?<object1>.*) (on|with) (?<object2>.*)$]]></pattern>
    <script>
      HandleUseOn (object1, object2)
    </script>
  </command>
  <command name="ask">
    <pattern type="string"><![CDATA[^ask (?<object>.*) about (?<text>.*)$]]></pattern>
    <script>
      DoAskTell (object, text, "ask", "askdefault", "DefaultAsk")
    </script>
  </command>
  <command name="tell">
    <pattern type="string"><![CDATA[^tell (?<object>.*) about (?<text>.*)$]]></pattern>
    <script>
      DoAskTell (object, text, "tell", "telldefault", "DefaultTell")
    </script>
  </command>
  <command name="tellto">
    <pattern type="string"><![CDATA[^(tell|ask) (?<object>.*) to (?<text>.*)$]]></pattern>
    <script>
      DoAskTell (object, text, "tellto", "telltodefault", "DefaultTellTo")
    </script>
  </command>
  <command name="alttellto">
    <pattern type="string"><![CDATA[^(?<object>.*), (?<text>.*)$]]></pattern>
    <script>
      DoAskTell (object, text, "tellto", "telltodefault", "DefaultTellTo")
    </script>
  </command>
  <command name="oops">
    <pattern type="string"><![CDATA[^oops (?<text>.*)$]]></pattern>
    <isoops />
    <script><![CDATA[
      hasoops = false
      if (HasAttribute(game, "unresolvedcommand")) {
        if (game.unresolvedcommand <> null) {
          hasoops = true
        }
      }
      if (not hasoops) {
        msg (Template("DefaultOops"))
      }
      else {
        dictionary remove (game.unresolvedcommandvarlist, game.unresolvedcommandkey)
        dictionary add (game.unresolvedcommandvarlist, game.unresolvedcommandkey, text)
        HandleSingleCommandPattern ("", game.unresolvedcommand, game.unresolvedcommandvarlist)
      }
      game.suppressturnscripts = true
    ]]></script>
  </command>
  <verb name="speak">
    <pattern>speak to #object#; speak #object#; talk to #object#; talk #object#</pattern>
    <property>speak</property>
    <defaulttemplate>DefaultSpeakTo</defaulttemplate>
  </verb>
  <verb name="buy">
    <pattern>buy #object#; purchase #object#</pattern>
    <property>buy</property>
    <defaulttemplate>DefaultBuy</defaulttemplate>
  </verb>
  <verb name="climb">
    <pattern>climb #object#</pattern>
    <property>climb</property>
    <defaulttemplate>DefaultClimb</defaulttemplate>
  </verb>
  <verb name="drink">
    <pattern>drink #object#</pattern>
    <property>drink</property>
    <defaulttemplate>DefaultDrink</defaulttemplate>
  </verb>
  <verb name="eat">
    <pattern>eat #object#</pattern>
    <property>eat</property>
    <defaulttemplate>DefaultEat</defaulttemplate>
  </verb>
  <verb name="hit">
    <pattern>hit #object#</pattern>
    <property>hit</property>
    <defaulttemplate>DefaultHit</defaulttemplate>
  </verb>
  <verb name="kill">
    <pattern>kill #object#</pattern>
    <property>kill</property>
    <defaulttemplate>DefaultKill</defaulttemplate>
  </verb>
  <verb name="kiss">
    <pattern>kiss #object#</pattern>
    <property>kiss</property>
    <defaulttemplate>DefaultKiss</defaulttemplate>
  </verb>
  <verb name="knock">
    <pattern>knock #object#</pattern>
    <property>knock</property>
    <defaulttemplate>DefaultKnock</defaulttemplate>
  </verb>
  <verb name="lick">
    <pattern>lick #object#</pattern>
    <property>lick</property>
    <defaulttemplate>DefaultLick</defaulttemplate>
  </verb>
  <verb name="lieon">
    <pattern>lie on #object#; lie upon #object#; lie down on #object#; lie down upon #object#</pattern>
    <property>lie</property>
    <defaulttemplate>DefaultLie</defaulttemplate>
  </verb>
  <verb name="listento">
    <pattern>listen to #object#</pattern>
    <property>listen</property>
    <defaulttemplate>DefaultListenTo</defaulttemplate>
  </verb>
  <verb name="lock">
    <pattern>lock #object#</pattern>
    <property>lock</property>
    <defaulttemplate>DefaultLock</defaulttemplate>
  </verb>
  <verb name="move">
    <pattern>move #object#</pattern>
    <property>move</property>
    <defaulttemplate>DefaultMove</defaulttemplate>
  </verb>
  <verb name="pull">
    <pattern>pull #object#</pattern>
    <property>pull</property>
    <defaulttemplate>DefaultPull</defaulttemplate>
  </verb>
  <verb name="push">
    <pattern>push #object#</pattern>
    <property>push</property>
    <defaulttemplate>DefaultPush</defaulttemplate>
  </verb>
  <verb name="read">
    <pattern>read #object#</pattern>
    <property>read</property>
    <defaulttemplate>DefaultRead</defaulttemplate>
  </verb>
  <verb name="search">
    <pattern>search #object#</pattern>
    <property>search</property>
    <defaulttemplate>DefaultSearch</defaulttemplate>
  </verb>
  <verb name="show">
    <pattern>show #object#</pattern>
    <property>show</property>
    <defaulttemplate>DefaultShow</defaulttemplate>
  </verb>
  <verb name="siton">
    <pattern>sit on #object#; sit upon #object#; sit down on #object#; sit down upon #object#</pattern>
    <property>sit</property>
    <defaulttemplate>DefaultSit</defaulttemplate>
  </verb>
  <verb name="smell">
    <pattern>smell #object#; sniff #object#</pattern>
    <property>smell</property>
    <defaulttemplate>DefaultSmell</defaulttemplate>
  </verb>
  <verb name="taste">
    <pattern>taste #object#</pattern>
    <property>taste</property>
    <defaulttemplate>DefaultTaste</defaulttemplate>
  </verb>
  <verb name="throw">
    <pattern>throw #object#</pattern>
    <property>throw</property>
    <defaulttemplate>DefaultThrow</defaulttemplate>
  </verb>
  <verb name="tie">
    <pattern>tie #object#</pattern>
    <property>tie</property>
    <defaulttemplate>DefaultTie</defaulttemplate>
  </verb>
  <verb name="touch">
    <pattern>touch #object#</pattern>
    <property>touch</property>
    <defaulttemplate>DefaultTouch</defaulttemplate>
  </verb>
  <verb name="turnon">
    <pattern>turn on #object#; turn #object# on; switch on #object#; switch #object# on</pattern>
    <property>turnon</property>
    <defaulttemplate>DefaultTurnOn</defaulttemplate>
  </verb>
  <verb name="turnoff">
    <pattern>turn off #object#; turn #object# off; switch off #object#; switch #object# off</pattern>
    <property>turnoff</property>
    <defaulttemplate>DefaultTurnOff</defaulttemplate>
  </verb>
  <verb name="turn">
    <pattern>turn #object#</pattern>
    <property>turn</property>
    <defaulttemplate>DefaultTurn</defaulttemplate>
  </verb>
  <verb name="unlock">
    <pattern>unlock #object#</pattern>
    <property>unlock</property>
    <defaulttemplate>DefaultUnlock</defaulttemplate>
  </verb>
  <verb name="untie">
    <pattern>untie #object#</pattern>
    <property>untie</property>
    <defaulttemplate>DefaultUntie</defaulttemplate>
  </verb>
  <command name="listen">
    <pattern type="string">^listen$</pattern>
    <script>
      msg (Template("DefaultListen"))
    </script>
  </command>
  <command name="jump">
    <pattern type="string">^jump$</pattern>
    <script>
      msg (Template("DefaultJump"))
    </script>
  </command>
  <command name="sit">
    <pattern type="string">^sit$|^sit down$</pattern>
    <script>
      msg (Template("DefaultSitDown"))
    </script>
  </command>
  <command name="lie">
    <pattern type="string">^lie$|^lie down$</pattern>
    <script>
      msg (Template("DefaultLieDown"))
    </script>
  </command>
  <command name="sleep">
    <pattern type="string">^sleep$|^rest$</pattern>
    <script>
      msg (Template("DefaultSleep"))
    </script>
  </command>
  <command name="wait">
    <pattern type="string">^wait$|^z$</pattern>
    <script>
      msg (Template("DefaultWait"))
    </script>
  </command>
  <command name="xyzzy">
    <pattern type="string">^xyzzy$</pattern>
    <script>
      msg (Template("DefaultXyzzy"))
    </script>
  </command>
  <command name="help">
    <pattern type="string">^help$|^\?$</pattern>
    <script>
      msg (Template("DefaultHelp"))
      game.suppressturnscripts = true
    </script>
  </command>
  <command name="save">
    <pattern type="string">^save$</pattern>
    <script>
      if (HasAttribute(game, "questplatform")) {
        if (game.questplatform = "desktop") {
          request (RequestSave, "")
        }
        else {
          JS.saveGame ()
        }
      }
      else {
        request (RequestSave, "")
      }
      game.suppressturnscripts = true
    </script>
  </command>
  <command name="version_cmd">
    <pattern type="string">^(version|info|about)$</pattern>
    <script><![CDATA[
      s = "<b>TITLE: </b>" + game.gamename + "<br/>"
      if (HasAttribute (game, "author")) {
        s = s + "<b>AUTHOR: </b>" + game.author + "<br/>"
      }
      s = s + "<b>VERSION: </b>" + game.version + "<br/>"
      s = s + "<b>IFID: </b>" + game.gameid + "<br/>"
      s = s + "<br/>"
      msg (s)
      game.suppressturnscripts = true
    ]]></script>
  </command>
  <command name="log_cmd">
    <pattern type="string">^log$|^view log$|^display log$</pattern>
    <script>
      if (not GetBoolean(game, "nohtmllog")) {
        JS.showLog ()
      }
      else {
        msg ("This game has no in-game log.")
      }
      game.suppressturnscripts = true
    </script>
  </command>
  <command name="view_transcript_cmd">
    <pattern type="string">^(view|display|show) (the |)(script|transcript)$</pattern>
    <script>
      if (not GetBoolean(game, "notranscript")) {
        JS.showTranscript ()
      }
      else {
        msg ("This game has no transcript feature.")
      }
      game.suppressturnscripts = true
    </script>
  </command>
  <command name="transcript_on_cmd">
    <pattern type="string">^(transcript|script)( on|)$|^enable (script|transcript)$</pattern>
    <script><![CDATA[
      if (not GetBoolean(game, "notranscript")) {
        if (not GetBoolean(game,"savetranscript")) {
          msg ("Please enter a filename.  (<b>  \"-transcript.html\" will be appended to this filename.)<br/>  <i>(The file will be saved in \"Documents\\Quest Transcripts\".)</i></b>")
          JS.eval ("$('input#txtCommand').val(transcriptName);")
          get input {
            filename = Trim(result)
            if (not filename = "") {
              JS.eval ("transcriptName = '"+filename+"';")
            }
            JS.eval ("savingTranscript = true;")
            game.savetranscript = true
            pre = "<hr/>Transcript enabled for:<br/>"
            s = "<b>TITLE: </b>" + game.gamename + "<br/>"
            if (HasAttribute (game, "author")) {
              s = s + "<b>AUTHOR: </b>" + game.author + "<br/>"
            }
            s = s + "<b>VERSION: </b>" + game.version + "<br/>"
            s = s + "<b>IFID: </b>" + game.gameid + "<br/>"
            s = s + "<br/>"
            s = pre + s
            msg ("")
            msg (s)
            msg ("<br/><b><i>[  Enter </i>SCRIPT OFF<i> to disable the transcript.  ]</i></b>")
          }
        }
        else {
          msg ("The transcript is already enabled.")
        }
      }
      else {
        msg ("This game has no transcript feature.")
      }
      game.suppressturnscripts = true
    ]]></script>
  </command>
  <command name="transcript_off_cmd">
    <pattern type="string">^(transcript|script) off$|^disable (script|transcript)$</pattern>
    <script>
      if (not GetBoolean(game, "notranscript")) {
        if (GetBoolean(game,"savetranscript")) {
          game.savetranscript = false
          JS.eval ("var savingTranscript = false;")
          msg ("Transcript disabled.")
        }
        else {
          msg ("The transcript is already disabled.")
        }
      }
      else {
        msg ("This game has no transcript feature.")
      }
      game.suppressturnscripts = true
    </script>
  </command>
  <command name="restart">
    <pattern type="string">^restart$</pattern>
    <script>
      Ask (Template("WantRestartGame")) {
        if (result) {
          JS.eval ("if(webPlayer){window.location.reload();}else if (typeof(RestartGame) != 'undefined'){RestartGame();}else{addTextAndScroll('Try pressing CTRL+R.')};")
        }
        else {
          game.suppressturnscripts = true
        }
      }
    </script>
  </command>
  <command name="wear">
    <pattern>put #object# on; wear #object#; put on #object#; don #object#; wear #object#</pattern>
    <allow_all />
    <scope>inventory</scope>
    <script>
      if (multiple and ListCount(object) = 0) {
        msg ("You've nothing to wear.")
      }
      else {
        foreach (obj, object) {
          if (multiple) {
            OutputTextNoBr (GetDisplayAlias(obj) + ": ")
          }
          f = _DoWear(obj)
        }
        UpdateArmour
      }
    </script>
  </command>
  <command name="remove">
    <pattern>take #object# off; remove #object#; take off #object#; doff #object#</pattern>
    <allow_all />
    <scope>inventory</scope>
    <script>
      if (multiple and ListCount(object) = 0) {
        msg ("You've nothing to take off.")
      }
      else {
        foreach (obj, object) {
          if (multiple) {
            OutputTextNoBr (GetDisplayAlias(obj) + ": ")
          }
          f = _DoRemove(obj)
        }
      }
      UpdateArmour
    </script>
  </command>
  <command name="devmode_commands">
    <pattern type="string"><![CDATA[^#(?<text>.*)]]></pattern>
    <script><![CDATA[
      if (HasAttribute(game, "devmode_active")) {
        if (game.devmode_active) {
          if (IsDefined("text")) {
            regex = "^(?<command2>put) (?<object1>.+) (in|on) (?<object2>.+)$|^(?<command1>drop|take|to|go|open|close|on|off) (?<object>.+)$|^(?<command0>selftest|clr|\\?)$"
            if (IsRegexMatch (regex, text)) {
              result = populate (regex, text)
              com0 = ToString(DictionaryItem(result, "command0"))
              com1 = ToString(DictionaryItem(result, "command1"))
              com2 = ToString(DictionaryItem(result, "command2"))
              // Commands
              if (not com0 = "") {
                switch (LCase(com0)) {
                  case ("selftest") {
                    selfTest
                  }
                  case ("clr") {
                    ClearScreen
                  }
                  case ("?") {
                    DevModeOutput (Template("DevModeDescriptionCommands"))
                  }
                }
              }
              else if (not com1 = "") {
                objstr = ToString(DictionaryItem(result, "object"))
                obj = getObjectExt(objstr)
                if (obj = null) {
                  error (DynamicTemplate("DevModeErrorCantFindObject", objstr))
                }
                switch (LCase(com1)) {
                  case ("drop") {
                    setWithoutChange (obj, "parent", game.pov.parent)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("take") {
                    setWithoutChange (obj, "parent", game.pov)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("to") {
                    setWithoutChange (game, "pov", obj)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("go") {
                    setWithoutChange (game.pov, "parent", obj)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("open") {
                    setWithoutChange (obj, "isopen", true)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("close") {
                    setWithoutChange (obj, "isopen", false)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("on") {
                    setWithoutChange (obj, "switchedon", true)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                  case ("off") {
                    setWithoutChange (obj, "switchedon", false)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                }
              }
              else if (not com2 = "") {
                obj1str = ToString(DictionaryItem(result, "object1"))
                obj2str = ToString(DictionaryItem(result, "object2"))
                obj1 = getObjectExt(obj1str)
                obj2 = getObjectExt(obj2str)
                if (obj1 = null) {
                  error (DynamicTemplate("DevModeErrorCantFindObject", obj1str))
                }
                if (obj2 = null) {
                  error (DynamicTemplate("DevModeErrorCantFindObject", obj2str))
                }
                switch (LCase(ToString(DictionaryItem(result, "command2")))) {
                  case ("put") {
                    setWithoutChange (obj1, "parent", obj2)
                    DevModeOutput (Template("DevModeComExecute"))
                  }
                }
              }
            }
            else {
              ParseToQuestCode (text)
            }
            // Expressions
          }
          else {
            request (Quit, "")
          }
        }
        else {
          error (Template("DevModeNotActive"))
        }
      }
      else {
        error (Template("DevModeNotActive"))
      }
    ]]></script>
  </command>
  <object name="Waiting Room">
    <isroom />
    <descprefix>You are in the Waiting Room</descprefix>
    <objectslistprefix>You can see</objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a small waiting room with no windows. Across from you there is a small coffee table and a single chair.  A high-resolution poster of a stretching polar bear completes the look of the small dentist office waiting room, but something about it feels artificial. The coffee table is too tidy, and the chair looks stiff and uncomfortable. </description>
    <enter type="script"><![CDATA[
      if (not ListContains(ScopeVisible(), Sharon)) {
        msg ("<br/>Sharon is nowhere to be seen. Where could she have gone? You realize she didn't tell you where to go, but the door on the left looks slightly ajar.")
      }
    ]]></enter>
    <firstenter type="script"><![CDATA[
      ClearScreen
      SetFontSize (20)
      PrintCentered ("PART ONE: Afternoon Nap<br/><br/>")
      SetFontSize (12)
      msg ("<b>Type \"look\" to toggle room description.</b>")
    ]]></firstenter>
    <beforefirstenter type="script">
    </beforefirstenter>
    <beforeenter type="script">
    </beforeenter>
    <object name="plant">
      <inroomdescription type="string"></inroomdescription>
      <look>You have no idea what type of plant it is; after all, you got your degree in astrophysics, not botany. You touch the leaf and find that it's hard and made of plastic. Of course.</look>
      <takemsg>The plant looks like it could be a nice companion but you decide it would be happier on the table.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="lamp">
      <inroomdescription type="string"></inroomdescription>
      <look>You're sure the lamp is from Ikea; you have one at home in your bedroom. Who furnished this room, anyway?</look>
      <takemsg>The lamp doesn't seem that heavy but you're not as strong as you used to be. You don't want to make a fool out of yourself.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="table">
      <inherit name="surface" />
      <alt type="stringlist" />
      <look>Just the type of coffee table you might find in any waiting room. </look>
      <takemsg>Somebody clearly spent a lot of time furnishing the room, even if they have really bad taste. You don't want to screw things up.</takemsg>
      <feature_container />
      <contentsprefix>on which there is</contentsprefix>
      <hidechildren type="boolean">false</hidechildren>
      <listchildren />
      <listchildrenprefix>On the table there is</listchildrenprefix>
      <displayverbs type="stringlist">
        <value>Look at</value>
        <value>Move</value>
      </displayverbs>
      <move>Somebody clearly spent a lot of time furnishing the room, even if they have really bad taste. You don't want to screw things up.</move>
      <object name="Stack of Newspapers">
        <look><![CDATA[The papers are the <i>San Francisco Chronicles</i>, sorted in order of recency. You pick up the issue on the top. A feature article on the front page catches your eye.<br/><br/>September 13, 2018<br/><b>Berkeley Protesters Clash With Armed Police</b><br/><br/><i>On Wednesday, a violent altercation took place between members of the social activism group Health Equity For All (HEFA), and the California State Police. The incident took place on Sproul Plaza, a major center of student activity at Berkeley, just after sunset. It is unclear which side initiated the violence, but video footage which has since gone viral shows protesters throwing bricks at police officers and the officers spraying large quantities of tear gas into the crowd in response. Out of a total of around 500 protestors, it has been confirmed that at least 30 protesters are being held in custody, and further charges are being filed. The group, which was formed just over a year ago in response to the rising epidemic of the Grey Death, asserts that viable treatment for the new illness is only available through the private sector at a cost that is unattainable for the lower class . . . </i>]]></look>
        <take type="boolean">false</take>
        <takemsg>You won't be needing this where you're going.</takemsg>
      </object>
    </object>
    <object name="Chair1">
      <alias>chair</alias>
      <inroomdescription type="string"></inroomdescription>
      <look>The chair looks slightly stiff and uncomfortable. It was clearly not matched with the table; its height makes you feel that it would be awkward to try to read something on the table while sitting in it. Looking at the chair reminds you of just how tired your legs are.</look>
      <sit>You legs feel heavy but sitting down while the woman is still standing would be rude. Why is there only one chair?</sit>
      <displayverbs type="stringlist">
        <value>Look at</value>
        <value>Sit on</value>
        <value>Move</value>
      </displayverbs>
      <takemsg>You shift the chair by a couple of inches. Ahh, so much better.</takemsg>
      <move>You shift the chair by a couple of inches. Ahh, so much better.</move>
    </object>
    <exit name="hallway" alias="west" to="limbo">
      <inherit name="westdirection" />
      <locked />
      <lockmessage>You feel like you should talk to the woman first; she seems eager enough to talk to you. Besides, you have no idea where these doors lead.</lockmessage>
      <runscript />
      <script type="script">
        if (ListContains(ScopeVisible(), Sharon)) {
          firsttime {
            msg ("Sharon turns to you, looking slightly concerned for the first time. \"Mr. Chase, if you go through that door, you won't be able to come back. You won't be able to say goodbye to your daughter. Are you sure?\"")
          }
          otherwise {
            msg ("Sharon looks sad, her effusive demeanor all but gone. \"Of course, Mr. Chase. I understand how difficult it can be to say goodbye. No, I won't judge you at all. Of course I will give Chloe your best regards.\" She holds the door open for you and you step through.")
            MoveObject (Conor Chase, Hallway)
          }
        }
        else {
          MoveObject (Conor Chase, Hallway)
        }
      </script>
    </exit>
    <exit name="meeting" alias="east" to="Meeting Room">
      <inherit name="eastdirection" />
      <locked />
      <lockmessage>You feel like you should talk to the woman first; she seems eager enough to talk to you. Besides, you have no idea where these doors lead.</lockmessage>
      <runscript />
      <script type="script">
        firsttime {
          msg ("As you place your hand on the doorknob, you feel your heartbeat pulsing on the cold metal. Are you ready to say goodbye to your daughter? What should you say? You take your hand back. Better to take a couple of deep breaths and try again in a couple of minutes.")
        }
        otherwise {
          MoveObject (Conor Chase, Meeting Room)
          MoveObject (Sharon, limbo)
        }
      </script>
    </exit>
    <exit name="Door to Physical Examination" alias="south" to="Waiting Room">
      <inherit name="southdirection" />
      <lookonly type="boolean">false</lookonly>
      <look>You just came out of there for your physical exam. You have to keep going. You promised your daughter.</look>
      <locked />
      <lockmessage>You just came out of there for your physical exam. You have to keep going. You promised your daughter.</lockmessage>
    </exit>
    <object name="Sharon">
      <inherit name="female" />
      <look><![CDATA[The woman looks to be in her early thirties, pretty with a head of flowing black hair. She reminds you of a younger Isabelle when you first met her at Stanford. You are relieved to find that the thought of your late wife brings you no grief, only a fuzzy sense of longing.  A white sticker on the woman's jacket screams out at you, <b>"Hi, my name is Sharon!" </b> Is she a receptionist? A nurse? You have no idea. She gives you an eager glance, obviously wanting you to speak first. You look past her longingly at the chair, but she shows no willingness to move aside. Besides, there's only one chair; it would probably be awkward if you sat down. ]]></look>
      <inroomdescription> A woman in formal attire is standing in the middle of the room, looking in your direction with such an intense smile that you want to look away.</inroomdescription>
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <alias>woman</alias>
      <prefix>a</prefix>
      <alt type="stringlist">
        <value>girl</value>
        <value>lady</value>
        <value>sharon</value>
      </alt>
      <speak type="script"><![CDATA[
        firsttime {
          msg ("You walk up to the woman. \"Hello,\" you say.<br/><br/>She turns to you with her beaming smile. \"Hello, Dr. Chase! My name is Sharon. I hope you found the physical examination pleasant. Your daughter is waiting behind that door.\" She points to the door on the right. \"I just need you to answer some questions to confirm your identity and that you fully understand the situation. Is that okay with you, Dr. Chase?\" She was holding a clipboard now, seemingly procured out of thin air. \"Okay, let's begin. What is your full name?\"<br/><br/>\"Conor Cabot Chase,\" you reply.<br/><br/>\"Date and location of birth?\"<br/><br/>\"August 17th, 1969, in San Francisco.\"<br/><br/>\"Profession?\"<br/><br/>\"I am - was - a professor of astrophysics at Stanford University. For the last 20 years of my life.\"<br/><br/>\"Next of kin.\"<br/><br/>\"One daughter, Chloe Claire Chase, age 24.\"<br/><br/>Sharon's smile widened, something you had not thought was possible. \"Sounds like your family really likes the C's. Well, it seems clear to me that you are indeed you. Let's move on. Here, take this. Please read the underlined text out loud and then sign your name on the dotted line.\" She passes you the clipboard.<br/><br/><b> Press any key to read and sign clipboard </b>")
          wait {
            msg ("<br/>\"I, Conor Cabot Chase, am of sound mind and understand that I have been diagnosed with a terminal illness, the cure of which is beyond the reaches of modern medicine. I hereby give Cryptec Inc. permission to put my body into cryonic sleep, and to revive me only at a time when the technology to cure me becomes available. I understand that this is a brand new state-of-the-art procedure, and that there are inherent risks that cannot be avoided. I understand that Cryptec Inc. will not be responsible for any damage that is caused to me in the duration of the operation.\"<br/><br/>You sign your name and Sharon takes the clipboard back. \"Great! That was easy, wasn't it? Now, I won't hold you back any longer. Your daughter is waiting for you!\" She points to the door on the right.<br/>")
            SetFontSize (12)
            msg ("<b>Type \"look\" any time to re-toggle room description and hyperlinks.</b>")
          }
          UnlockExit (hallway)
          UnlockExit (meeting)
        }
        otherwise {
          msg ("\"Yes, Mr. Chase? You'll be wanting to go through the door on your right. Your daughter is waiting for you. She's a very nice young lady - I see that she takes after her father.\" She smiles at you sweetly.")
        }
      ]]></speak>
      <ask type="scriptdictionary">
        <item key="corgis">
          MoveObject (Conor Chase, Bedroom)
          MoveObject (button, Bedroom)
        </item>
        <item key="pog">
          MoveObject (Conor Chase, New Bedroom)
        </item>
        <item key="TL">
          msg ("My disappointment is immense and my day is ruined.")
          MoveObject (Conor Chase, South Greenhouse)
        </item>
        <item key="bear">
          msg ("Yay bear")
          MoveObject (Conor Chase, Star Room)
          MoveObject (badge, Conor Chase)
        </item>
        <item key="burnaby north">
          msg ("I hear that's a pretty good school.")
          MoveObject (Conor Chase, North Greenhouse)
        </item>
      </ask>
    </object>
    <object name="Conor Chase">
      <inherit name="male" />
      <alt type="stringlist">
        <value>Conor</value>
        <value>Chase</value>
      </alt>
      <feature_player />
      <attr name="pov_look">If you could just look at yourself then mirrors would be useless.</attr>
    </object>
  </object>
  <object name="Meeting Room">
    <description>This room is slightly larger than the one you just stepped out of, and it looks as if someone had put in an effort to make it seem cozy. The floor is carpeted and there is a black couch facing yet another coffee table. To your left is a bookcase, empty except for a couple of hardcovers strewn across the top row. </description>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <firstenter type="script">
      SetObjectFlagOn (Conor Chase, "met_chloe")
      MoveObject (memo, Waiting Room)
    </firstenter>
    <object name="bookshelf">
      <inherit name="surface" />
      <feature_container />
      <listchildren />
      <hidechildren />
      <listchildrenprefix>On the bookshelf there is</listchildrenprefix>
      <look>What kind of bookshelf has only two books on it? </look>
      <takemsg>You feel like you would have a hard time fitting the bookshelf through the doorway.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <object name="The Dangers of the New Epidemic">
        <look><![CDATA[The book is <i>The New Dangers of the New Epidemic</i>, by Dr. Carl Schneider, published in 2010. You turn it over and read the back cover.<br/><br/><i>The acclaimed Dr. Schneider, a specialist in infectious diseases, issues a warning about the dangers of the "New Epidemic". Dr. Schneider argues that the increased use of powerful antibiotics to treat disease, along with the increasing consumption of GMO foods and lab-grown meats, puts us all at risk for a new type of disease, one that modern science will be powerless to treat. Dr. Schneider's research is widely influential and has had a large impact on health policy.</i><br/><br/><i>Dr. Schneider received his Bachelor's Degree from Duke University and his M.D. from Harvard Medical School. After practicing as a cardiologist in the state of California for 20 years, Dr. Schneider became a lecturer at the University of California, San Francisco, where he was known for his research on HIV. In 2016, Dr. Schneider joined the biotech startup Cryptec Inc., where he was named Chief Scientist.</i>]]></look>
        <usedefaultprefix type="boolean">false</usedefaultprefix>
        <takemsg>You could just take it, but you don't want the bookshelf to look even barer than it already is.</takemsg>
      </object>
      <object name="From Rags to Riches">
        <look><![CDATA[The book is <i>From Rags to Riches: The Story of Cryptec Inc.</i> by Cameron Stone, published in 2014. You turn it over and read the back cover.<br/><br/><i>Award winning journalist Cameron Stone gives us a never-before-seen look at the hugely successful biotech company Cryptec Inc.. Stone covers in fastidious detail the story of how one small startup company operated from a garage transformed into a cutting-edge leader of health care and research over a mere 10 years. This book features exclusive interviews with founder and CEO John Roakes, who previously founded and sold the nanotech company Prototype, as well as other high-level executives in the company like Marcy Adams and Dr. Carl Schneider.</i>]]></look>
        <usedefaultprefix type="boolean">false</usedefaultprefix>
        <takemsg>You could just take it, but you don't want the bookshelf to look even barer than it already is.</takemsg>
      </object>
    </object>
    <exit alias="west" to="Waiting Room">
      <inherit name="westdirection" />
      <runscript />
      <script type="script">
        if (ListContains(ScopeVisible(), Chloe Chase)) {
          msg ("You've already come inside. What if Chloe heard you enter? You have to talk to her before you leave.")
        }
        else {
          MoveObject (Conor Chase, Waiting Room)
        }
      </script>
    </exit>
    <object name="couch">
      <look>The couch looks expensive but uncomfortable.</look>
      <takemsg>The couches look pretty expensive but you would probably have a hard time getting away with it.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
        <value>Sit on</value>
      </displayverbs>
      <sit type="script"><![CDATA[
        if (ListContains(ScopeVisible(), Chloe Chase)) {
          msg ("\"Chloe?\" Your voice is barely more than a whisper.<br/><br/>The young woman on the sofa suddenly sits up straight. She stands and turns to look at you, her eyes red but her lips spread out in a huge smile. \"Dad!\" she says, and runs into your arms. You hold her there, steadying yourself against her body. She is so warm, so tough, so strong. You don't want to let go, don't want to look into her eyes and acknowledge, to the both of you, that you might never see her again.<br/><br/>\"Dad, you will be okay. I promise. Dr. Schneider is a brilliant man, and I have the utmost trust in him. I have a feeling that I will see you again very soon. Great things are happening at Cryptec, you know. Oh, I almost forgot.\" She takes off the necklace that she is wearing, a golden turtle on a silver chain. \"You gave this to me for my twenty-first birthday. I want you to keep this, to wear it when you . . . sleep. It would mean a lot to me.\" She drapes it around your neck, and when her fingers touch your skin you feel shivers up your spine. \"There,\" she says. \"I think it looks much better on you anyway.\"<br/><br/>\"Chloe,\" you say, \"there's something you're not telling me. Don't give me that look; I've known you for all your life, I know what you're like when you're trying to keep something from me. Is it bad news? Go on, I can handle it.\"<br/><br/>Chloe looks down at her feet, frowning. \"I didn't want to alarm you. It's probably nothing. It's just . . . something seems off about this disease, the Grey Death. It's not just that it's fatal . . . we've eliminated so many fatal diseases in the past, like yellow fever and smallpox. The way that the Grey Death spreads makes no sense. It doesn't pass from person to person, and yet more cases are being diagnosed every day. It's just not right. I'm sure that I'm just being paranoid - after all, I am new to this kind of stuff. I don't have Dr. Schneider's experience.\" Before you can answer, she hugs you again, squeezing all the wind out of you. \"If I don't go soon, I'll never go,\" she mumbles, her face still in your chest. She tiptoes and kisses you on the cheek. \"Until we see again,\" she said. Then, she turns to the northern door, which opens with a beep as she swipes her employee card on the reader. Before you know it, she is gone.<br/><br/><b>The necklace has been added to your inventory. Type \"inventory\" to see what you are carrying with you.</b>")
          MoveObject (Chloe Chase, limbo)
          AddToInventory (necklace)
        }
        else {
          msg ("You should probably get going.")
        }
      ]]></sit>
    </object>
    <object name="table1">
      <alias>table</alias>
      <look>You could swear that this was the same table as the one in the living room</look>
      <takemsg>If you wanted a table like that you would just go to Ikea.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="Chloe Chase">
      <inherit name="female" />
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <look><![CDATA[You look at her, the woman you watched grow up before your eyes, from a screaming toddler to the brilliant scientist that she is today. The thought of her crying breaks your heart. <i>I'm not worth it,</i> you want to tell her, <i>your future is so strong and bright. Forget about me</i>. For a moment you regret that you came here at all, to torture her one last time with the sight of your weakened body. You came because you were selfish. Because you wanted to see her one last time.]]></look>
      <inroomdescription>There is a woman sitting on the couch with her back towards you, her shoulders moving up and down in short bursts, as if she were sobbing. It's your daughter, Chloe. She doesn't seem to have heard you come in.</inroomdescription>
      <speak type="script"><![CDATA[
        msg ("\"Chloe?\" Your voice is barely more than a whisper.<br/><br/>The young woman on the sofa suddenly sits up straight. She stands and turns to look at you, her eyes red but her lips spread out in a huge smile. \"Dad!\" she says, and runs into your arms. You hold her there, steadying yourself against her body. She is so warm, so tough, so strong. You don't want to let go, don't want to look into her eyes and acknowledge, to the both of you, that you might never see her again.<br/><br/>\"Dad, you will be okay. I promise. Dr. Schneider is a brilliant man, and I have the utmost trust in him. I have a feeling that I will see you again very soon. Great things are happening at Cryptec, you know. Oh, I almost forgot.\" She takes off the necklace that she is wearing, a golden turtle on a silver chain. \"You gave this to me for my twenty-first birthday. I want you to keep this, to wear it when you . . . sleep. It would mean a lot to me.\" She drapes it around your neck, and when her fingers touch your skin you feel shivers up your spine. \"There,\" she says. \"I think it looks much better on you anyway.\"<br/><br/>\"Chloe,\" you say, \"there's something you're not telling me. Don't give me that look; I've known you for all your life, I know what you're like when you're trying to keep something from me. Is it bad news? Go on, I can handle it.\"<br/><br/>Chloe looks down at her feet, frowning. \"I didn't want to alarm you. It's probably nothing. It's just . . . something seems off about this disease, the Grey Death. It's not just that it's fatal . . . we've eliminated so many fatal diseases in the past, like yellow fever and smallpox. The way that the Grey Death spreads makes no sense. It doesn't pass from person to person, and yet more cases are being diagnosed every day. It's just not right. I'm sure that I'm just being paranoid - after all, I am new to this kind of stuff. I don't have Dr. Schneider's experience.\" Before you can answer, she hugs you again, squeezing all the wind out of you. \"If I don't go soon, I'll never go,\" she mumbles, her face still in your chest. She tiptoes and kisses you on the cheek. <br/><br/>\"Have a good time,\" you say. \"And you have the best time,\" she replies, and you both smile at the inside joke. Then, she turns to the northern door, which opens with a beep as she swipes her employee card on the reader. Before you know it, she is gone.<br/><br/><b>The necklace has been added to your inventory. Type \"inventory\" to see what you are carrying with you.</b>")
        MoveObject (Chloe Chase, limbo)
        AddToInventory (necklace)
      ]]></speak>
    </object>
    <exit alias="north" to="Hallway">
      <inherit name="northdirection" />
      <runscript />
      <script type="script">
        msg ("A sign on the door says \"Employees Only\". You're pretty sure you're not an employee.")
      </script>
    </exit>
  </object>
  <object name="Hallway">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a long, white hallway, stretching out before you, seemingly without end. The floor is tiled and so clean that you can see your blurred reflection in it. The walls are empty and bare. </description>
    <firstenter type="script"><![CDATA[
      msg ("The door closes behind you with a click. You stand there, not sure if you are expected to walk forward, when you hear footsteps coming toward you. A clean-shaven man, around seventy years of age and wearing a white lab coat, appears from the depths of the hallway, like a chameleon emerging from camouflage. He holds out his hand. His manner is gentle and polite.<br/>")
      MoveObject (Dr Schneider, Hallway)
      if (GetBoolean(Conor Chase, "met_chloe")) {
        msg ("\"Hi, Dr. Chase. My name is Dr. Carl Schneider. It is a pleasure to finally meet you.\"<br/><br/>\"A pleasure to meet you too,\" you say. \"My daughter has told me so much about you.\"<br/>")
      }
      else {
        msg ("\"Hi, Dr. Chase. My name is Dr. Carl Schneider. It is a pleasure to finally meet you.\"<br/><br/>\"A pleasure to meet you too,\" you say. \"My daughter has told me so much about you.\" At the mention of Chloe your stomach clenches up in guilt. \"It is such,\" you say again, awkwardly, \"a pleasure.\"<br/>")
      }
      msg ("Dr. Schneider coughs lightly into his elbow. He looks at you over his glasses, and you feel as if he is talking down to you, like a parent trying to comfort a crying child. \"I don't want you to worry at all, Dr. Chase. You are, of course, aware that you are about to be the first person to undergo cryogenic sleep. Naturally there will be some risk. But I want to assure you, Dr. Chase, that we will do everything in our power to keep you safe, alive, and healthy.\" He starts to move down the hallway and you follow behind. \"Your daughter, by the way, has an extraordinary medical mind; she is without doubt the most brilliant researcher in my lab. You should be proud. Not to mention anything about her stubbornness and determination: from the first day she heard about the project, she insisted on the possibility of having you as our first trial subject. I told her about the risks, the conflict of interest . . . but she just wouldn't let up. She is a headstrong woman.\" He smiles. \"My daugher is very much the same. I tried my best to get her to go to medical school, but she just wouldn't give up on her childhood dream.\"<br/><br/>\"And what dream was that?\" you ask.<br/><br/>\"She wanted to be an astronaut.\"<br/><br/><b> Press any key to follow Dr. Schneider </b><br/>")
      wait {
        msg ("The doctor offers you his arm, but you tell him you can walk on your own. \"Right now, I'm taking you to the sleep chamber. Dr. Chase, have you ever been under general anesthesia before? Well, this is going to be just like that. No pain, no disorientation whatsoever. You're going to close your eyes, and then open then again. Easy as that. It will just be like an afternoon nap.\" You finally reach the end of the hallway. A small, wooden door blocks the way. The doctor opens it and you follow him in.<br/>")
        MoveObject (Dr Schneider, Bedroom)
        MoveObject (Conor Chase, Bedroom)
      }
    ]]></firstenter>
  </object>
  <object name="Bedroom">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>The room is small and tidy. A twin-sized bed with grey covers occupies one corner, and a working desk occupies another. A tall, sturdy wardrobe stands at the foot of the bed, open just wide enough for you to see the suits hanging inside. An upright lamp illuminates the windowless bedroom. The walls are bare, except for a single poster, a colorized photograph of the Milky Way. A luscious carpet covers the floor.</description>
    <beforeenter type="script">
    </beforeenter>
    <beforefirstenter type="script">
    </beforefirstenter>
    <firstenter type="script"><![CDATA[
      msg ("<br/>You rub your eyes to make sure you aren't dreaming. The bedroom is a spitting copy of the one in your apartment, minus the window over the Stanford campus. You plop down on the bed, glad to finally give your legs some rest. Dr. Schneider is smiling at you.<br/><br/>\"It was Chloe's idea; she thought it would make you feel more comfortable. We even took your actual suits to make it seem more realistic.\"<br/><br/>\"But where are the machinery? The tubes? The capsules?\"<br/><br/>Dr. Schneider laughed. \"We have all that, of course. But we thought it would be scary for you to see. All you have to do is fall asleep, in your own bed, and we'll handle the rest. When you wake up, you will be in your own bed too, so you won't feel disoriented. I'll give you a moment to take it all in.\"")
    ]]></firstenter>
    <object name="bed">
      <look>The bed is the perfect size for one person. You switched out your queen bed for this when your wife died.</look>
      <takemsg>There's no way you can lift this bed.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="desk">
      <inherit name="surface" />
      <feature_container />
      <listchildren />
      <hidechildren type="boolean">false</hidechildren>
      <listchildrenprefix>On the table there is </listchildrenprefix>
      <look>Clean and tidy, just the way you like to keep it when you're trying to do work.</look>
      <takemsg>Now is not the time for lifting.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <object name="letter_zach">
        <inroomdescription>There is a folded letter on the table.</inroomdescription>
        <look><![CDATA[You open up the letter and flatten it on the table. It's printed on heavy paper, embossed with the Stanford logo. <br/><br/><i><b>Dearest Conor</b>:<br/><br/>You didn't think I was going to let you go without saying goodbye, did you? Please, don't blame Chloe for telling me. I was being very persistent, and you know how I get when I am persistent. I started to suspect when I called at your house last week and Chloe told me that you were too sick to see anybody; I knew that you would always have time for me, no matter what.<br/><br/>Well, how does it feel to be cheating death? I really couldn't believe that they were going to stage a funeral for you, with a fake cadaver and all. The crazy thing is, you're probably going to get away with it too; people are dropping likes flies. It only seems like yesterday that the President was on television telling us not to worry, and now what? Ten thousand people dead and we still don't know the first thing about curing it. You know, I'm glad you're getting out now, because everything is really falling to shit. Mass protests on the streets, talks of revolution, of "seizing access to proper health care". Conor Chase, you are one lucky son of a bitch. You may just be the only one to get out of this unscathed.<br/><br/>What else is there left to say? I can't believe you're about to do this. It's like something straight out of a science fiction novel. You just close your eyes, and when you wake up, it could be fifty years in the future, a hundred years, maybe even a thousand. What will be there to greet you? Flying cars, cure-all machines, sentient robots? Or maybe just a nuclear wasteland? I have to admit, I am a little bit jealous of you. Just a little, because I know that disease can't be fun. <br/><br/>I have already rambled on for too long. Chloe said she wouldn't deliver this letter if it was over a page. So I'll just say this, Conor: you will be missed, as a professor, as a colleague, and as a friend. I hope that we will see each other again one day. Bon Voyage.<br/><br/><b>Your friend for now and always,<br/>Zach Lee</b></i>]]></look>
        <take />
        <takemsg>You put the letter in your pocket. </takemsg>
        <inventoryverbs type="stringlist">
          <value>Look at</value>
          <value>Drop</value>
        </inventoryverbs>
        <alias>letter from Zach</alias>
        <alt type="stringlist">
          <value>letter (Zach)</value>
        </alt>
        <usedefaultprefix />
        <scenery type="boolean">false</scenery>
      </object>
    </object>
    <object name="wardrobe">
      <look>The wardrobe is sturdy and reliable. Your best suits are dangling inside.</look>
      <takemsg>Maybe if you move the wardrobe aside there will be a passage to Narnia?</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="chair">
      <look>It's a solid chair. Nothing fancy, but good for your back.</look>
      <takemsg>The chair is right where you like it.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <exit alias="east" to="Hallway">
      <inherit name="eastdirection" />
      <runscript />
      <script type="script"><![CDATA[
        if (ListContains(ScopeVisible(), Dr Schneider)) {
          msg ("Dr. Schneider coughs gently. \"I know it can be a lot,\" he says, \"but I want you to know that it will always be your decision, up until the end. You are free to walk out if that's what you choose. But I want you to take some time in this room, on your own, and think about it. Think about the future. Think about your daughter.\"")
        }
        else {
          firsttime {
            msg ("You've come too far to back out now. You remember the nights that Chloe would spend sobbing in her room, when she thought that you couldn't hear her, the way that she tried to be upbeat and optimistic about your diagnosis even though you both knew it was fatal. She's done so much for you, tried so hard . . . <br/><br/>And yet, you can't forget the doctor's words. <i>Thousands would kill to be in your position.</i> Why should you live, and others die? Do you really deserve this? Do you want to live that badly? <br/><br/>It might not feel like it, but you have a choice. You might lose your ability to walk, to eat, to breathe, but you will always have your ability to choose as long as you live. You could walk out of this room right now and tell them that you've changed your mind. ")
          }
          otherwise {
            msg ("You turn the doorknob. The door creaks open. You step into the white hallway. You are suddenly aware of how weak your body is, the effort it takes to lift your legs, the way your lungs struggle to fill themselves with every breath. You've never been more conscious of your own mortality.<br/><br/>This is the path you choose, and you do not feel regret. You will never wake up in a fantastic new world, full of flying cars and teleportation machines and miraculous cures, and you are okay with that. You feel as if a huge weight has been lifted from your shoulders.<br/><br/>You start walking back up the hallway. You still have things to do, people to see, a life to live.<br/><br/><b>THE END </b>")
            finish
          }
        }
      ]]></script>
    </exit>
    <object name="lamp1">
      <alias>lamp</alias>
      <look>You bought this lamp from Ikea for $19.99.</look>
      <takemsg>The lamp is fine where it is.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="envelope">
      <inherit name="container_open" />
      <takemsg><![CDATA[You put the envelope into your pocket. You don't feel like opening it just yet. <br /> <br /> <b>An envelope has been added to your inventory. Type "inventory" to see what you are carrying. </b>]]></takemsg>
      <look><![CDATA[It is a standard-sized envelope. Neat handwriting on the front reads <br/><br/><b>To Dad, From Chloe</b>.]]></look>
      <inroomdescription>There is a white envelope sitting on the table.</inroomdescription>
      <feature_container />
      <hidechildren />
      <close type="boolean">false</close>
      <isopen type="boolean">false</isopen>
      <listchildren type="boolean">false</listchildren>
      <take />
      <displayverbs type="stringlist">
        <value>Look at</value>
        <value>Take</value>
        <value>Open</value>
      </displayverbs>
      <inventoryverbs type="stringlist">
        <value>Look at</value>
        <value>Drop</value>
        <value>Open</value>
      </inventoryverbs>
      <onopen type="script"><![CDATA[
        msg ("You rip open the top of the envelope, taking care not to damage the paper inside. You dump the contents out onto your hand. There is a letter and a ring.<br/><br/><b>A letter and a ring have been added to your inventory. Type \"inventory\" to see what you are carrying. </b>")
        AddToInventory (letter_chloe)
        AddToInventory (ring)
      ]]></onopen>
      <object name="letter_chloe">
        <alias>letter from Chloe</alias>
        <inventoryverbs type="stringlist">
          <value>Look at</value>
          <value>Drop</value>
        </inventoryverbs>
        <alt type="stringlist">
          <value>letter from Chloe</value>
        </alt>
        <look><![CDATA[The letter is handwritten on lined paper. A cute corgi waves at you from the bottom of each page.<br/><br/><i><b>Hey Dad:</b><br/><br/>I knew there was a good chance you would chicken out and not see me, so I took the precaution of writing this letter. It's okay, I don't blame you; it's probably better this way. Maybe I shouldn't have come at all, but I was selfish. I wanted to see you one last time.<br/><br/>Dad, you will be okay. I promise. Dr. Schneider is a brilliant man, and I have the utmost trust in him. I have a feeling that I will see you again very soon. Great things are happening at Cryptec, you know.<br/><br/>In this envelope you will find a Stanford Class of 1990 ring. Mom gave it to me on her deathbed; she told me that as long as I wore it, she would always be a part of me. Now, I'm giving it to you. Even if you wake up hundreds of years in the future, and we are all but just a distant memory, just put on the ring and we will be with you, mom and I. <br/><br/>I love you. I love you. I love you. I hope with all my heart that we will see each other again. <br/><br/><b>Your Loving Daughter,<br/>Chloe Chase</b><br/></i>]]></look>
      </object>
      <object name="ring">
        <inventoryverbs type="stringlist">
          <value>Look at</value>
          <value>Drop</value>
        </inventoryverbs>
        <look><![CDATA[It's a heavy, golden ring. The words <b>Stanford, The Great Class of 1990</b> are engraved on it.]]></look>
      </object>
    </object>
  </object>
  <object name="limbo">
    <object name="Dr Schneider">
      <inherit name="namedmale" />
      <alt type="stringlist">
        <value>doctor</value>
        <value>schneider</value>
        <value>dr</value>
      </alt>
      <look>The doctor is a clean-shaven man around seventy years of age. He is wearing a white lab coat that's slightly too large for him. Highly intelligent eyes look out at you from behind round spectacles. You get the impression that he is a careful man, powerful but aware of exactly what he can do. He reminds you of your late father and you find yourself automatically trusting him.</look>
      <speak type="script"><![CDATA[
        msg ("\"I'm ready,\" you say.<br/><br/>Dr. Schneider hands you a small red button on a black cube. \"When you're ready to sleep, just press this button. We've already injected anesthetic into your veins, and this activates it.\"<br/><br/>You shake your head. \"I didn't know we could do this already.\"<br/><br/>Dr. Schneider's eyes are shining through his glasses. \"This is nothing compared to the technology that you'll see. Fifty years, a hundred, two hundred . . . it will make what we have now seem like rocks and clubs. We'll be able to go wherever we want, whenever we want, do whatever we want. Maybe even death will be eliminated.\" He puts a hand on your shoulder. \"I won't be able to see all of that, but you will. Enjoy it for me.\"<br/><br/><b>Press any key to voice your concerns.</b><br/>")
        wait {
          msg ("\"Wait,\" you say. \"Chloe was worried about something. She said there was something off about the disease, about the way it spreads . . .\"<br/><br/>Dr. Schneider coughs again. His expression doesn't change. \"You leave the worrying to the experts, Dr. Chase. Cryptec employs some of the best doctors and scientists in the world. You won't get better care anywhere else. Thousands of people would kill to be in your position right now.\" <br/><br/>You nod reluctantly. \"Actually, I was wondering about that too. Why all the secrecy? Why do I have to fake my own death? Wouldn't it comfort the public to know that you guys are working on a cure?\"<br/><br/>\"Dr. Chase,\" he says slowly. \"Hope can be a dangerous thing. Do you know how much it's going to cost to keep you in cryonic sleep? The unit we have prepared for you is the only one of its kind in the world. We have to observe its effects on you and then make more. That could take years and billions of dollars. Not everyone can afford to hope.<br/><br/>\"Let me speak frankly, Dr. Chase. I saw the report from your physical examination, and you are not in good shape. In about two weeks you will lose the ability to walk, and in a month you won't be able to breathe without a tube sticking into your lungs. It is a painful way to die; trust me, I've seen it. This is your only chance to survive.\"<br/><br/>He sees the look on your face. \"If you can't do this for yourself, then do it for Chloe. Do it for science. Don't think too much about questions that you can't answer, Dr. Chase.\" With that, he turns and walks out of the room. The door shuts with a soft click.<br/><br/><b>A button has been added to your inventory. Type \"inventory\" to see what you are carrying. </b><br/>")
        }
        MoveObject (Dr Schneider, limbo)
        AddToInventory (button)
      ]]></speak>
      <object name="button">
        <inventoryverbs type="stringlist">
          <value>Look at</value>
          <value>Drop</value>
          <value>Press</value>
        </inventoryverbs>
        <look>It's just a small, red button on a black box, but somehow it looks ominous and dangerous, as if it were the detonator to a nuclear bomb.</look>
        <dropmsg>The button drops onto the ground.</dropmsg>
        <take />
        <takemsg>You pick up the button. It feels heavy in your hand.</takemsg>
        <displayverbs type="stringlist">
          <value>Look at</value>
          <value>Take</value>
          <value>Press</value>
        </displayverbs>
        <press type="script"><![CDATA[
          firsttime {
            msg ("You look at the button, staring back at you with its single red eye. If you press it, you may never wake up again. Are you ready? You tell yourself that you've lived a full life, but the truth is you're afraid of death. A simple, quick press of the button, and then . . . nothingness for eternity. You want so badly to imagine it but you can't. You try to bring up the faces of your late wife and daughter, but you are surprised at how difficult it is. Maybe you should sit here for a while longer. There's no rush, after all.")
          }
          otherwise {
            firsttime {
              msg ("You finger brushes the top of the button. Why did you agree to do this? If you had just died, you would have been out of Chloe's life forever. But now, the thought of you will torment her for the rest of her life, taunt her inability to find a cure for your disease. What if something happens to you? How will she handle the guilt?<br/><br/>You give yourself a mental slap on the cheek. You made Chloe a promise and you are going to follow it through. The time for changing minds has long since passed. Isabelle's death hit her harder than it hit you, and it will be a comfort for her to know that she will never be alone. And what about that bright future that everybody talks about? Perhaps you would like to see it too.<br/><br/>You make up your mind. You are going to press the button.")
            }
            otherwise {
              msg ("You hold the black box in your hand. It's weight and coldness are somehow comforting. Your life flashes before your eyes; childhood in San Francisco, high school prom, first day at University, meeting Isabelle for the first time . . . holding a crying infant Chloe, receiving your offer of tenure, looking at the stars from the roof of your apartment building and asking it to reveal its mysteries . . . you suppose you've lived as good as a life as anybody could ask for. <br/><br/>You fixate an image in your mind, a picture of Chloe and Isabelle smiling across the table of your favorite restaurant, on your 40th birthday. It's the picture you want to see as you make your leap into eternity. You're thankful that you are able to visualize the image so clearly.<br/><br/>You press the button.<br/>")
              SetFontSize (20)
              PrintCentered ("The End of Part One<br/><br/>")
              SetFontSize (12)
              msg ("<b>Press any key.</b><br/>")
              wait {
                ClearScreen
                SetFontSize (20)
                PrintCentered ("PART TWO: The Warden<br/><br/>")
                SetFontSize (12)
                msg ("<b>Press any key to wake up.</b><br/>")
                wait {
                  msg ("From out of the darkness, you hear a voice.<br/><br/><i>It's my fault, all my fault . . . I couldn't see, I couldn't see . . . my cataracts . . . I'm so sorry . . . </i><br/><br/><b>Press any key to wake up.</b><br/>")
                  wait {
                    msg ("<i>Wake up. Wake up. Wake up! Conor Chase, Dr. Chase, please wake up! Please . . . </i><br/><br/><b>Press any key to wake up.</b>")
                    wait {
                      MoveObject (Conor Chase, New Bedroom)
                      MoveObject (button, limbo)
                    }
                  }
                }
              }
            }
          }
        ]]></press>
      </object>
    </object>
    <exit alias="south" to="Meeting Room">
      <inherit name="southdirection" />
    </exit>
    <object name="necklace">
      <takemsg>The heavy necklace makes you feel safe.</takemsg>
      <drop />
      <dropmsg>This necklace means a lot to Chloe. You probably shouldn't leave it lying around.</dropmsg>
      <look>It's a golden turtle on a silver chain. You gave it to Chloe for her twenty-first birthday.</look>
      <inventoryverbs type="stringlist">
        <value>Look at</value>
        <value>Drop</value>
      </inventoryverbs>
    </object>
    <object name="memo">
      <inroomdescription>There is a memo lying on the ground. It looks like it fell from the receptionist's pocket.</inroomdescription>
      <look><![CDATA[You see neat, cursive writing on a pink post-it note.<br/><br/><i>2:45pm -- tidy up waiting room<br/>3:00pm -- welcome Dr. Chase, obtain signature<br/>4:00pm -- confirm physical therapy appointment for Dr. Schneider<br/>5:30pm -- prepare medication for Dr. Schneider<br/>6:00 -- lock up offices </i><br/>{once: <br/>Does Dr. Schneider do physical therapy? You had the impression he wasn't that kind of doctor. And who is the medication for?}]]></look>
      <take />
      <takemsg>You fold up the memo carefully and put it inside your pocket.</takemsg>
    </object>
    <object name="Wardens Body">
      <look>It's a tall man, with a handlebar mustache. As you look at the motionless body, you feel your stomach twist with guilt. Would this have happened if you had just forgiven him? You don't know, you will never know.</look>
      <inroomdescription>A body is hanging from the chandelier, a dirty white apron wrapped tightly around his neck.</inroomdescription>
      <alias>body</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
  </object>
  <verb>
    <property>press</property>
    <pattern>press</pattern>
    <defaultexpression>"You can't press " + object.article + "."</defaultexpression>
  </verb>
  <object name="New Bedroom">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>The room is small and tidy. A twin-sized bed with grey covers occupies one corner, and a working desk occupies another. A tall, sturdy wardrobe stands at the foot of the bed, open just wide enough for you to see the suits hanging inside. An upright lamp illuminates the windowless bedroom. The walls are bare, except for a single poster, a colorized photograph of the Milky Way. A luscious carpet covers the floor.</description>
    <alias>Bedroom (Dr. Conor Chase)</alias>
    <beforeenter type="script">
    </beforeenter>
    <beforefirstenter type="script">
      if (GetBoolean(Conor Chase, "met_chloe")) {
      }
      else {
        MoveObject (envelope, desk)
      }
    </beforefirstenter>
    <firstenter type="script"><![CDATA[
      msg ("<br/>You open your eyes slowly to the familiar yellow tint of your ceiling. You sit up in bed. You have never felt so good before. You had a bad dream, something about diseases and forms on clipboards and long hallways, but now everything is just fine. <br/><br/>You look around. Everything is where it should be, and yet something is not quite right. You've just woken up from an afternoon nap, but there is no sunlight, only the glow of the lamp. <br/><br/>There is no window.<br/><br/>Could it be? Have you arrived at the destination of an undeterminable journey through time? You touch your face, then your hands, then your chest. You feel like yourself, but better. You stand up. You are still wearing same clothes, black jeans and button-down shirt, but all of your lethargy and soreness is gone. <br/><br/>You examine the room again. If the cryonic sleep worked, then why is there nobody here to welcome you into the future? You must have woken up too early. Maybe only a couple of hours have passed. You should go find Dr. Schneider and tell him to give you the anesthetic again.")
    ]]></firstenter>
    <object name="bed1">
      <look>The bed is the perfect size for one person. You switched out your queen bed for this when your wife died.</look>
      <takemsg>There's no way you can lift this bed.</takemsg>
      <alias>bed</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="desk1">
      <inherit name="surface" />
      <feature_container />
      <listchildren />
      <hidechildren type="boolean">false</hidechildren>
      <listchildrenprefix>On the table there is </listchildrenprefix>
      <look>Clean and tidy, just the way you like to keep it when you're trying to do work.</look>
      <takemsg>Now is not the time for lifting.</takemsg>
      <alias>desk</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <object name="letter_zach2">
        <look><![CDATA[{once: You pick up the familiar embossed paper, and you immediately realize that this is a different letter; it is much shorter than the one you read before your nap.<br/>}<br/>It reads:<br/><br/><i><b>Dearest Conor:</b><br/><br/>I just wanted to say goodbye. I'm afraid I won't be there to greet you. They offered me a spot, you know, but just one. I couldn't leave Jessica behind. I expected they knew that, and besides, I had made my views on the Selection very public. It was like some kind of sick joke, that even until the end they wanted to prove that I was a hypocrite after all. I told them no. I'm so very sorry that I won't be able to see you again. I hope you understand.<br/><br/><b>Your dearest friend,<br/>Zach Lee</b></i><br/>{once: <br/>You read the letter again, then again. Your mind is sharp but it doesn't want to think about what this letter could mean. How long have you been asleep? Who is "they"? Maybe it's just another one of Zach's "pranks". Don't panic, you tell yourself. Wait until you find someone to get answers from.}]]></look>
        <usedefaultprefix />
        <alias>letter </alias>
        <take />
        <takemsg>You put the letter in your pocket.</takemsg>
        <scenery type="boolean">false</scenery>
        <visible />
        <isroom type="boolean">false</isroom>
      </object>
    </object>
    <object name="wardrobe1">
      <look>The wardrobe is sturdy and reliable. Your best suits are dangling inside.</look>
      <takemsg>Maybe if you move the wardrobe aside there will be a passage to Narnia?</takemsg>
      <alias>wardrobe</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="chair1">
      <look>It's a solid chair. Nothing fancy, but good for your back.</look>
      <takemsg>The chair is right where you like it.</takemsg>
      <alias>chair</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="lamp2">
      <alias>lamp</alias>
      <look>You bought this lamp from Ikea for $19.99.</look>
      <takemsg>The lamp is fine where it is.</takemsg>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <exit alias="east" to="South Hallway">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="South Greenhouse">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>The hallway opens into a large, cylindrical space, longer and wider than the Stanford football stadium. Along the ceiling is a strip of light, burning into your eyes with the intensity of a small sun. All around you are racks upon racks of plants, rotating silently on unseen tracks, taking their turn to bathe in the light. There are blueberries the size of cherries, and tomatoes so round and perfect and impossibly plump that you can taste their sweetness simply by looking at them. And then there are vegetables and fruits that you don't recognize: yellow triangular prisms covered with hair, orange cubic shapes sticking out of the soil. A single, winding path leads onward, but you cannot see where it ends. </description>
    <beforefirstenter type="script">
    </beforefirstenter>
    <firstenter type="script"><![CDATA[
      msg ("<br/>You don't know what you expected when you saw the word \"Greenhouse\", but it was not this. You feel yourself trembling. Whatever hope you may have had is gone. This is something of the future, something unimaginable by an astrophysics professor born in the 1960s. How many years has it been? How many? Zach is surely dead. Chloe probably is, too. What have you done? What have you gotten yourself into?")
    ]]></firstenter>
    <exit alias="south" to="North Hallway">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="Central Greenhouse">
      <inherit name="northdirection" />
    </exit>
    <object name="footprints1">
      <alias>footprints</alias>
      <look>Footprints, again, undoubtedly left by the same person who had made his mark in the hallway, but more confusing. Some lead forward, some back, and all of them are smudged as if by a heavy object.</look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="The ABC Murders">
      <look>It's a bit grubby but still readable. </look>
      <take />
      <takemsg>When you finally build your own library, you're going to have a whole shelf dedicated to Agatha Christie.</takemsg>
      <inroomdescription>There is a book is lying face-down on the dirt, partially hidden from view by the leaves of a grapevine. </inroomdescription>
    </object>
    <object name="sticker">
      <look>A spot of black amidst a sea of green catches your eye. It is a sticker, sticking comfortably to a large cabbage leaf. On the sticker, a black ship sails on a white sea. The word "ARC" is written into its hull.</look>
      <attr name="not_all" type="boolean">false</attr>
      <takemsg>The sticker is surprisingly difficult to peel off, and you don't want to destroy the plant. You give up.</takemsg>
    </object>
  </object>
  <object name="Star Room">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description><![CDATA[You step onto a black walkway and the door closes behind you. You are engulfed by a complete and total darkness. A familiar voice speaks to you from out of this darkness, and for a second you think that it's Isabelle, but it can't be. Isabelle is long dead. <br/><br/>"Welcome to the Star Observation Room of the ARC Two. To give you an immersive experience, the gravity generator in this chamber will be temporarily switched off. We hope you have the best time." As the voice fades, you feel a lightness spread throughout your body, and all the worries and fears you've been carrying suddenly seem to weigh nothing. You take a step forward and you find yourself sailing slowly through the air. Your eyes adjust and you see that you are not alone; you are surrounded by millions of stars, more than you've ever seen before, too many to even imagine counting. You feel as if you are one of them.]]></description>
    <firstenter type="script"><![CDATA[
      msg ("<br/>Finally, you feel at peace . . .<br/>")
      SetFontSize (20)
      PrintCentered ("The End of Part Two<br/><br/>")
      SetFontSize (12)
      msg ("<b>Press any key.</b><br/>")
      wait {
        ClearScreen
        SetFontSize (20)
        PrintCentered ("PART THREE: ARC <br/><br/>")
        SetFontSize (12)
        msg ("<b>Press any key to wake up.</b><br/>")
        wait {
          msg ("You didn't even realize that you had dozed off. What did you dream about? You strain to remember but you can't. Perhaps the same stars that surround you now followed you into the other realm. The thought of it fills you with comfort.<br/><br/>You want to just stay here forever, but you know you can't. There are still so many questions to be answered. You went to sleep underneath the ground, and now you are in space; what happened? And where was Chloe? Speaking of Chloe . . . there was something here that reminded you of her, something recent, but you can't remember what it is . . .<br/><br/>You flail your arms and legs, but you don't seem to move. How can you get to the door? Then, you remember the voice that spoke to you.<br/><br/>\"Let me down,\" you say. \"Gravity will now be switched back on,\" the voice replies, and you find yourself dropping slowly to the walkway. You walk forward and the door slides open.")
          MoveObject (Conor Chase, Archive)
        }
      }
    ]]></firstenter>
    <exit alias="north" to="Archive">
      <inherit name="northdirection" />
      <runscript />
      <script type="script"><![CDATA[
        firsttime {
          msg ("You flail your arms and legs, but you don't seem to move. How can you get to the door? Then, you remember the voice that spoke to you.<br/>")
        }
        if (Got(badge)) {
          msg ("\"Let me down,\" you say. \"Gravity will now be switched back on,\" the voice replies, and you find yourself dropping slowly to the walkway. You walk forward and the door slides open.")
          MoveObject (Conor Chase, Archive)
        }
        else {
          msg ("\"Let me down,\" you say, but nothing happens. Maybe voice commands only work when you have the badge?")
        }
      ]]></script>
    </exit>
    <exit alias="south" to="North Greenhouse">
      <inherit name="southdirection" />
      <runscript />
      <script type="script"><![CDATA[
        firsttime {
          msg ("You flail your arms and legs, but you don't seem to move. How can you get to the door? Then, you remember the voice that spoke to you.<br/>")
        }
        if (Got(badge)) {
          msg ("\"Let me down,\" you say. \"Gravity will now be switched back on,\" the voice replies, and you find yourself dropping slowly to the walkway. You walk forward and the door slides open.")
          MoveObject (Conor Chase, North Greenhouse)
        }
        else {
          msg ("\"Let me down,\" you say, but nothing happens. Maybe voice commands only work when you have the badge?")
        }
      ]]></script>
    </exit>
  </object>
  <object name="Archive">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a dimly lit, narrow walkway, hemmed in by glass cases that stretch on to your left and right. Inside each case are books of different colors and sizes, packed tightly according to some three-dimensional algorithm, so that not even an inch of empty space is left. Ahead of you, in the center of the walkway, is a wide, black, cylinder. Above it, blue words hang in the air, unsupported by anything that you can see. It reads: "Terminal".</description>
    <exit alias="south" to="Star Room">
      <inherit name="southdirection" />
      <runscript />
      <script type="script">
        if (Got(badge)) {
          msg ("You wave the badge in front of you, and the door slides open on silent tracks. Beyond the doorway, all you see is darkness. ")
          MoveObject (Conor Chase, Star Room)
        }
        else {
          msg ("There is something strange about this door; it doesn't seem to have a doorknob or any hinges. A golden placard above the door reads \"Star Room\".")
        }
      </script>
    </exit>
    <exit alias="north" to="Museum">
      <inherit name="northdirection" />
      <runscript type="boolean">false</runscript>
      <script type="script">
        if (Got(badge)) {
          msg ("You wave the badge in front of you, and the door slides open on silent tracks. Beyond the doorway, all you see is darkness. ")
          MoveObject (Conor Chase, Star Room)
        }
        else {
          msg ("There is something strange about this door; it doesn't seem to have a doorknob or any hinges. A golden placard above the door reads \"Star Room\".")
        }
      </script>
    </exit>
    <object name="Terminal">
      <displayverbs type="stringlist">
        <value>Use</value>
      </displayverbs>
      <feature_usegive />
      <look> Above a wide, black, cylinder, blue words hang in the air, unsupported by anything that you can see. It reads: "Terminal".</look>
      <use type="script"><![CDATA[
        msg ("The terminal beeps, and its blue text splinters into holographic options. \"What would you like to learn about?\" asks the familiar voice.<br/>")
        terminal_options = NewStringList()
        list add (terminal_options, "The Selection")
        list add (terminal_options, "The Origin of the Grey Death")
        list add (terminal_options, "ARC Program")
        list add (terminal_options, "Transmission of the Grey Death")
        ShowMenu ("", terminal_options, false) {
          msg ("You try to touch the option, but your hand just goes through. \"Preparing sources,\" the voice says. The contents of the cases start moving, shuffling along unseen tracks. A mechanical arm reaches out from above, plucks some books out from behind the cases, and holds them up, open, behind the terminal display. New words appear on the hologram. <br/>")
          switch (result) {
            case ("The Selection") {
              msg ("<i>The first formulation of the Selection is attributed to Dr. Carl Schneider, who published his controversial paper \"The Principles of the Selection for the Continuation of the Human Species\" in the Stanford Medical Journal in 2021. These principles can be concisely summarized by quoting the paper: \"Our goal now must be, and can only be, the survival of humankind as a species. We cannot consider the fate of the individual, lest the fate of all individuals be lost. Therefore, we must select individuals with the sole aim of maximizing the probability of the continuation of the species.\"<br/><br/>The publication of the paper resulted in public outrage, which was spurred on by the Health Equity For All (HEFA) international non-profit organization and by the Russian and Chinese governments. Under enormous pressure, the United States government was forced to publicly sanction Cryptec Inc., but it still supported and cooperated with the company in secret. <br/><br/>One thousand and four hundred individuals were identified for Selection, with an additional five hundred labled as backup; amongst this number were government leaders and experts in scientific fields. Out of these initially selected, a hundred and thirty-five were unable to receive the summons or died before they could reach the ships, and two hundred and fifteen refused the summons for moral reasons.<br/> </i>")
            }
            case ("The Origin of the Grey Death") {
              msg ("<i>To this date, there is no conclusive, widely accepted theory on the origin of the Grey Death. Multiple hypotheses have been put forward by prominent scientists, each with varying amounts of evidence. I have compiled the most popular ones:<br/><br/>1) The virus mutated to its final form long ago, and has been dormant for many years. This theory explains the sudden onset of the Grey Death and the lack of similar virus strains observed in modern times. Some proponents believe that the very same strain wiped out the dinosaurs; evidence for this includes similar patterns in the carbon structure of dinosaur fossils as compared to humans who died of the disease. It is unclear how the virus has stayed dormant for so long, and what suddenly caused it to resurface. Some have pointed to an archaeological find in Alaska that coincides with the timing of the initial breakout, but there is insufficient evidence to link the two events.<br/><br/>2) The virus was a biological weapon designed by the Russian government. Some have cited the location of the \"patient zero\", in Simferopol, Crimea, as evidence, as the timing coincided with armed conflict between Russian and Ukranian forces. The pandemic decimated the Ukranian army and the Russians were able to march into Crimea and annex it with minimal casualties. The apparent immunity of the Russian forces indicated a possible antidote for its own people. The Russian government continued to behave erratically during the Grey War by attacking China and attempting to further increase its territory. However, as Moscow was destroyed by a nuclear bomb in 2023, it may be impossible to retrieve any evidence to support this theory.<br/><br/>3) The virus was created as a botched attempt at immortality by a private U.S. corporation. In the early 2000s, the nanotech company Prototype announced a project to extend the human lifespan through the manipulation of telomeres, but early tests on animals caused them to \"turn into stonelike beings, resulting in decreased range of motion, and eventually death\". In 2004, the New York Times published a piece alleging that Prototype used a human test subject without adhering to federal ethical guidelines. Despite the media outrage, the scandal died down due to lack of evidence and Prototype was acquired by Gilead Sciences. The CEO of Prototype, John Roakes, then went on to found the biotech company Cryptec Inc..<br/></i>")
            }
            case ("ARC Program") {
              msg ("<i>The Auto-Restorative Cryonics procedure, or ARC for short, was developed and patented by Cryptec Inc. It was initially conceived as a way to keep subjects alive until a time in the future when a cure for the Grey Death was discovered, but monitoring of subjects revealed that the number of infected cells were reducing without any additional treatment. Cryptec Inc. made the discovery that the virus had a lifespan that was independent of the human host, but that it was much longer than the natural human lifespan. To put it another way, infected humans died faster than the Grey Death did. Freezing the human in a cryonic chamber would extend the lifespan of the human but not that of the virus. <br/><br/>Due to the high cost of cryonic technology and the chaos brought about by World War Three, the ARC program was initiated by Cryptec Inc. in secret, in collaboration with the United States government. The government had begun constructing extra-solar spaceships without the knowledge of the public ten years prior, and the program consisted of accelerating this construction and loading them with ARC units. <br/><br/>A total of five ships were built as part of the ARC fleet. The first one was the biggest, and contained one thousand occupants, while each subsequent ship housed one hundred occupants each. The occupants of each ship were selected according to the principles outlined by Dr. Carl Schneider in his paper \"The Principles of the Selection for the Continuation of the Human Species\". While the other occupants slept, the Captain of the ARC I maintained the operation of the ship; the other ships were each assigned a \"Warden\" for this role. These individuals were selected for their natural immunity to the disease, a rare quality estimated to be possessed by no more than 0.01% of the population.<br/></i>")
            }
            case ("Transmission of the Grey Death") {
              msg ("<i>One of the biggest mysteries of the pandemic was the method of transmission. When the locations of new cases were mapped out, the pattern did not fit with that of any known diseases. An initial outbreak in one country would come to a complete halt, and new cases would pop up in another country on the opposite side of the globe, even though air travel had been shut down for months. Caretakers and family members would stay healthy while someone who had minimal contact with the patient would get sick. <br/><br/>Multiple hypotheses were put forward and proven false: transmission through animals, airborne transmission, transmission through water reservoirs. If information had been freely shared between countries, perhaps the solution would have been found faster, but as it was, there was still deep mistrust between the nations. Many governments suspected others of developing a biological weapon and harboring its secrets. <br/><br/>The answer was finally discovered by Cryptec Inc.; the hint came from their work on the ARC program. Just as the virus had a long life span, it had a very long incubation period, far surpassing that of any known disease. This period, defined as the time between initial contraction and symptom development, ranges between 1-10 years. This meant that it was already too late to stop the spread of the virus; it lay in the bodies of people all over the globe, biding its time.<br/></i>")
            }
          }
        }
      ]]></use>
    </object>
  </object>
  <object name="Wardens Room">
    <alias>Bedroom (Dr. Carl Schneider)</alias>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>The room is simple and bare. A single mattress sits atop a derelict frame; the frayed comforter is folded in a perfect, military cube. A solitary bulb reluctantly shines upon a small, wooden desk and a larger chair. There is no window in this room either.</description>
    <exit alias="west" to="South Hallway">
      <inherit name="westdirection" />
    </exit>
    <object name="bed2">
      <alias>bed</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <look>It's not much to look at, but the sheets are white and the pillow seems soft. Something about the simplicity gives you a sense of comfort. </look>
    </object>
    <object name="desk2">
      <inherit name="surface" />
      <alias>desk</alias>
      <feature_container />
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <look>The desk is cracked but clean. </look>
      <object name="picture frame">
        <look><![CDATA[It's a faded photograph of a young couple. The man is tall, mustached, serious. The woman is blonde, freckled, laughing. A beautiful garden fills the background, framed by leaning palm trees. <br/>{once:<br/>Neither of the people in the photo look like Dr. Schneider.}<br/>]]></look>
        <take type="boolean">false</take>
        <takemsg>You feel that moving the picture would disturb something precious, something you have no right to touch. You slowly draw your hand away. </takemsg>
      </object>
      <object name="And Then There Were None">
        <usedefaultprefix type="boolean">false</usedefaultprefix>
        <look>It's a classic Agatha Christie novel. You remember reading it in 10th grade English class. The pages are yellow and the thickness is uneven from all the dog ears. </look>
        <take />
        <takemsg>You've always wanted to start your own library. </takemsg>
      </object>
      <object name="glasses">
        <look>You try them on, and you are immediately blind. The lenses are very thick.</look>
        <usedefaultprefix type="boolean">false</usedefaultprefix>
        <prefix>a pair of</prefix>
        <take />
        <takemsg>You take the glasses, but you have no idea what they might be used for. You just like collecting stuff, you guess.</takemsg>
      </object>
    </object>
    <object name="chair2">
      <alias>chair</alias>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <look>The chair feels disproportionately large compared to the desk.</look>
    </object>
    <object name="rake">
      <inroomdescription>There is a garden rake leaning against the corner, its teeth choked with dark soil.</inroomdescription>
      <look>It's obvious that the rake has been used many times. The label of the manufacturing company has long been scraped off, the wood is pock-marked, and several of the teeth are missing. You've never seen a rake like this before. It speaks of hard work, of quiet satisfaction, of a tender love. </look>
      <take />
      <takemsg>You pick up the rake. It feels heavier than you thought it would be.</takemsg>
    </object>
  </object>
  <object name="South Hallway">
    <alias>South Hallway</alias>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a long, white hallway, stretching out before you, seemingly without end. The floor is tiled and so clean that you can see your blurred reflection in it. The walls are empty and bare. There are doors to your west, east, and south. A golden placard above the south door reads "Sleep Chamber". Similar placards above the west and east doors read "Dr. Conor Chase" and "Dr. Carl Schneider" respectively. The hallway stretches away to the north.</description>
    <firstenter type="script"><![CDATA[
      msg ("<br/>The hallway looks exactly like it did before, but you don't remember seeing these other entryways with their placards; perhaps you were too occupied with your own thoughts. Is the \"Sleep Chamber\" where Cryptec employees sleep when they stay late at work? You look at the entryway to your east: at least this one is clear. It must be Dr. Schneider's office. You will go in and ask him what's going on.")
    ]]></firstenter>
    <exit alias="north" to="North Hallway">
      <inherit name="northdirection" />
    </exit>
    <exit name="Sleep Chamber Entrance" alias="south" to="Sleep Chamber">
      <inherit name="southdirection" />
      <locked />
      <lockmessage>There is something strange about this door; it doesn't seem to have a doorknob or any hinges. You have no idea how to open it. A golden placard above the door reads "Sleep Chamber".</lockmessage>
    </exit>
    <exit alias="east" to="Wardens Room">
      <inherit name="eastdirection" />
    </exit>
    <exit alias="west" to="New Bedroom">
      <inherit name="westdirection" />
      <locked type="boolean">false</locked>
      <lockmessage type="string"></lockmessage>
    </exit>
    <object name="footprints">
      <look>There are muddy footprints on the floor, leading away from the room labeled "Sleep Chamber". You place your foot next to them. Whoever made these prints has slightly bigger feet than you do. Maybe size 11? The footprints are smudged along the direction of the corridor, as if the person with big feet had been dragging something behind them.</look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <usedefaultprefix type="boolean">false</usedefaultprefix>
    </object>
  </object>
  <object name="Unused Single Room">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <exit alias="east" to="South Hallway">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="North Hallway">
    <alias>North Hallway</alias>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a long, white hallway, stretching out before you, seemingly without end. The floor is tiled and so clean that you can see your blurred reflection in it. There are doors to your west, east, and north. A golden placard above the north door reads "Greenhouse". Golden placards above the west and east doors read "Warden's Quarters" and "John and Mary Roakes" respectively. The hallway stretches away to the south.</description>
    <firstenter type="script"><![CDATA[
      SetTurnTimeout (8) {
        UnlockExit (Greenhouse Entrance)
        UnlockExit (Bathroom Exit)
        msg ("<br/>Suddenly, you find yourself face-to-face with the floor. The ground is shaking and turning, rumbling like an angry beast. Earthquake! A childhood in California has familiarized you with this particular natural disaster, but you've never felt one this powerful before. Just when it feels like the earth might split open, everything stops. You rise shakily to your feet.")
        SetObjectFlagOn (North Hallway, "greenhouse_unlocked")
        if (game.pov.parent = North Hallway) {
          msg ("<br/>The door to the north has disappeared. It must have slid into the doorway somehow, but you can't see anything except for smooth, white wall. Maybe the earthquake somehow shook the door loose.")
        }
      }
    ]]></firstenter>
    <enter type="script"><![CDATA[
      if (GetBoolean(North Hallway, "greenhouse_unlocked")) {
        msg ("<br/>The door to the north has disappeared. It must have slid into the doorway somehow, but you can't see anything except for smooth, white wall. Maybe the earthquake somehow shook the door loose.")
      }
    ]]></enter>
    <beforefirstenter type="script">
    </beforefirstenter>
    <exit alias="south" to="South Hallway">
      <inherit name="southdirection" />
    </exit>
    <exit alias="west" to="Couples Room">
      <inherit name="westdirection" />
    </exit>
    <exit alias="east" to="Unused Couples Room">
      <inherit name="eastdirection" />
      <locked />
      <lockmessage>You try the handle but the door won't open. It's locked.</lockmessage>
    </exit>
    <exit name="Greenhouse Entrance" alias="north" to="South Greenhouse">
      <inherit name="northdirection" />
      <lookonly type="boolean">false</lookonly>
      <locked />
      <lockmessage>There is something strange about this door; it doesn't seem to have a doorknob or any hinges. You have no idea how to open it. A golden placard above the door reads "Greenhouse".</lockmessage>
    </exit>
    <object name="poster">
      <look>A single poster hangs on the wall, breaking the perfect illusion of the white walls. White letters on a red background read: "KEEP CALM AND SLEEP ON". A small black logo of a ship sits at the top of the poster, with the word ARC written into its hull.</look>
      <takemsg>You remember a story about a student who got sentenced to ten years of hard labor for stealing a poster in North Korea. You're probably not in North Korea right now, but you decide you'd rather not take the risk.</takemsg>
    </object>
  </object>
  <object name="Couples Room">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Warden's Quarters</alias>
    <description>The room is large and spacious, the walls a comforting shade of lavender. A crystal chandelier hangs from the ceiling, and lush pillows sit atop a queen-sized mattress. An electric fireplace at the foot of the bed reminds you of the lodge in Colorado where you and Isabelle spent your honeymoon. A large wedding portait hangs above the fireplace, but your attention is immediately caught by what looks to be a colorful mural spanning across the walls of the bedroom. Flowers of every shade and shape, golden, cinder, magenta, swaying gently to an unseen wind, filling the air with an undetectable fragrance . . . A sliding door opens onto a walk-in bathroom to the west.</description>
    <exit alias="east" to="North Hallway">
      <inherit name="eastdirection" />
    </exit>
    <object name="bed3">
      <alias>bed</alias>
      <lie>You plop yourself down on the bed, and are delighted to find that it is every bit as comfortable as you thought it would be. You close your eyes and try to remember the past: the cracking sound of the fireplace, the giant snowflakes falling against the morning sky, the soft scent of your wife . . . You bring yourself back to the room with the sheer force of effort. Now is not the time to lose yourself in the past. There are too many questions you need to answer, right here, right now.</lie>
      <displayverbs type="stringlist">
        <value>Look at</value>
        <value>Lie on</value>
      </displayverbs>
      <look>A thick mattress on a luxurious frame, the bed looks like the one you used to share with Isabelle. The bed is made so neatly it looks like it could have been done by a hotel maid. The sheets are a deep, relaxing blue. </look>
    </object>
    <object name="nightstand">
      <inherit name="surface" />
      <feature_container />
      <hidechildren />
      <listchildren />
      <look>The nightstand is mahogany colored with ornate legs and wide, generous curves. </look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <object name="picture frame1">
        <alias>picture frame</alias>
        <look>It is a picture of a couple kneeling on the ground, the man's arm around the woman's shoulders. The woman's blonde hair is streaked with dirt, and you can see sweat on the man's brows. Two pairs of gloves lie on the ground in front of them in the freshly turned soil. The woman is saying something to the man. The man is smiling.</look>
        <takemsg>Taking the photo would disturb the atmosphere of domestic bliss. You leave it as it is. </takemsg>
      </object>
      <object name="Murder on the Orient Express">
        <look><![CDATA[Many critics consider this the best mystery story of all time. The book looks like it's been read and re-read; the cover was torn off at some time in the past but was taped back together carefully. You flip open to the first page and you see it's been written in: <br/><br/>"<i>Dear Nicky, I hope that our love will always be as exciting as murder. Love, Jake.</i>"]]></look>
        <take />
        <takemsg>You pick up the book. You already know the ending, but it's such a great book that you still wouldn't mind re-reading it.</takemsg>
      </object>
      <object name="gardening gloves">
        <look>The gloves are so stained that's it's hard to tell if they were once white. </look>
        <take />
        <takemsg>You fold up the gloves and put then in your pocket, careful not to get any dirt on your clothing.</takemsg>
      </object>
    </object>
    <object name="bookshelf1">
      <alias>bookshelf</alias>
      <look>The shelf is built into the wall, two rows filled to the brim with books. You scan the top row and find Agatha Christie novels that you've never heard of. Gardening handbooks fill the bottom row; you never knew there were so many books about gardening in the world.</look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <exit name="Bathroom Exit" alias="west" to="Bathroom">
      <inherit name="westdirection" />
      <locked />
      <lockmessage>You try sliding the door but it seems to be stuck. After a couple of tries, you give up. You don't really need to go anyways.</lockmessage>
    </exit>
    <object name="Wedding Portrait">
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <look>It is a portrait of a young, handsome couple, the type you might see hung with pride on the wall of a photographer's studio. The man is tall and dark, his eyes looking straight at the camera. A small handlebar mustache gives him an air of silliness which clashes with his serious expression. The woman is blonde and lightly freckled, her smiling face turned towards her new husband. There is no date anywhere on the photo.</look>
    </object>
    <object name="mural">
      <look>You've never seen a bedroom like this before. You lean in closer and feel the uneven texture of the flowers with your fingers; every single one was drawn with paint and brush, with a painstaking care for detail. Almost without realizing it you begin to count the flowers. There are fifty-one in total. </look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
  </object>
  <object name="Unused Couples Room">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Bedroom (John and Mary Roakes)</alias>
    <exit alias="west" to="North Hallway">
      <inherit name="westdirection" />
    </exit>
  </object>
  <object name="Central Greenhouse">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>The winding path continues. The greenhouse is so impossibly vast, the ceiling so high, that you forget you are indoors. To your left is a large reservoir, a square of piercing blue, with channels running through the greenhouse in intricate grids. To your amazement, you follow the channels with your eyes and see them run onto the walls and ceiling, unhindered by gravity. </description>
    <exit alias="south" to="South Greenhouse">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="North Greenhouse">
      <inherit name="northdirection" />
    </exit>
    <object name="Tombstone">
      <inroomdescription>To your right is a small path cut through the plants, leading to a circular clearing. In the middle of the clearing is what appears to be a black tombstone, surrounded by rings of flowers.</inroomdescription>
      <look><![CDATA[You see yourself in the shiny surface of the stone: an old man, hair halfway grey, crow's feet beginning to grow from the corners of your eyes. And yet you see a vitality in that familiar face, the determination of a man who has been given a second chance at life. There are no words on the smooth stone, no name to indicate who lay beneath your feet, no dates to delineate their short stay upon this earth. The flowers, though, are beautiful, each one a different shade from the next. You wish you could name them, but you were never a flower person. You count them. There are exactly fifty-one.<br/>{once: <br/>There is a sound coming from further up the path, to the north, a dull kind of thudding, like metal hitting dirt. You stiffen; this is the first sound you've heard since waking up. If there is another person in the greenhouse, they could explain everything, they could take you to see Chloe, if . . . you let that thought drift away unfinished.}]]></look>
      <visible />
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <scenery type="boolean">false</scenery>
    </object>
  </object>
  <object name="North Greenhouse">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description><![CDATA[The greenhouse ends the same way it began. Far in the distance, you see the open space close back onto a single door, where the winding path terminates. Just off the left of the path, in between the blue channels and rotating tracks, is a square plot of earth cut geometrically from its surroundings. The soil in this patch has a lighter shade than the dark, rich soil of the greenhouse. <br/><br/>You are reminded of the garden that you once had, in the backyard of your Palo Alto home. Every weekend, Isabelle would wake up at the crack of dawn to clear the leaves, pull the weeds, and lay mulch around the plants. Sometimes you helped her, but you both knew that it was Isabelle's garden. After she passed, it was neglected and overgrown; you could not bear to admit to yourself that she was gone, that she would never bend over again in that garden, never sweat and smile and wave at you through the window . . . <br/><br/>Despite the advanced technology all around you, the small patch of soil looks as if it has been tended to manually. Modestly-sized tomatoes hang meekly from wooden racks, and pudgy pumpkins are lined up in neat but imperfect rows.]]></description>
    <exit alias="south" to="Central Greenhouse">
      <inherit name="southdirection" />
    </exit>
    <exit name="Star Room Entrance" alias="north" to="Star Room">
      <inherit name="northdirection" />
      <locked type="boolean">false</locked>
      <lockmessage type="string"></lockmessage>
      <runscript />
      <visible />
      <script type="script">
        if (Got(badge)) {
          msg ("You wave the badge in front of you, and the door slides open on silent tracks. Beyond the doorway, all you see is darkness. ")
          MoveObject (Conor Chase, Star Room)
        }
        else {
          msg ("There is something strange about this door; it doesn't seem to have a doorknob or any hinges. A golden placard above the door reads \"Star Room\".")
        }
      </script>
    </exit>
    <object name="Warden">
      <inherit name="male" />
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <prefix>the</prefix>
      <inroomdescription>There is an old man standing with his back to you, his hair ashen white, his back bent over, clutching a shovel and working furiously on the light soil of the garden. Beside him are a dozen mounds of freshly turned dirt. </inroomdescription>
      <look>Although his back is bent to almost a right angle, you can tell that he is very tall, at least six feet. He is dressed in gardener's clothes: a stained apron and muddied work boots. A thick, white handlebar mustache contrasts with his tired expression. He seems not to have seen you; his eyes are fixed on his task.</look>
      <speak type="script"><![CDATA[
        firsttime {
          msg ("\"Who's that?\" the old man squints at you. \"Nicky? Is that you, Nicky? Where have you been all this time? Look at our garden, look at what I've done. Do you like the pumkpins? We could never get them to grow this big . . .\"<br/><br/>\"My name is Conor,\" you say. \"Conor Chase. Please, I fell asleep, and when I woke up, I found myself here. . . it was an experiment, part of some trial . . . Dr. Carl Schneider told me that everything woudl be okay . . . do you know Dr. Schneider?\" You know that you are jabbering but you can't help it. <br/><br/>The old man squints his eyes. They look milky and grey. \"Dr. Chase . . .\"<br/><br/>\"Please, I need to know. What year is it? Where am I? I need to know if my daughter is okay. Please tell me!\"<br/><br/>The old man says nothing. Big, fat teardrops squeeze themselves out from his unseeing eyes, leaving jagged trails down his withered face. His whole body is shaking. \"I'm so sorry, so sorry . . . I tried my best. I did everything I could, but I couldn't see, couldn't see . . . my cataracts got worse after Nicky left, but I couldn't tell the captain . . . I couldn't risk losing my job. By the time the power systems came back online, they were all . . . oh God, Nicky, forgive me . . .\"<br/><br/>You grasp him by the shoulders, hold him so that his eyes are staring forward into your face. \"Calm down,\" you say, even though your heart is beating at a hundred miles a minute. \"Slow down and tell me what happened.\"<br/><br/>\"It was an asteroid that hit us, it must have been. All the sirens were going off and I didn't know what to do . . . oh God . . . I failed everyone. You're the only one left, Dr. Chase. You were the first one, so you were on a different support system . . . I did the best I could.<br/>")
          options = NewStringList()
          list add (options, "Yes")
          list add (options, "No")
          ShowMenu ("\"Would you forgive me, Dr. Chase? Could you do that for me? \"", options, false) {
            switch (result) {
              case ("Yes") {
                msg ("\"Of course,\" you say. \"There are many things outside of our control. I'm sure that whatever happened here, it wasn't your fault.\"<br/><br/>The Warden grasps your hands in his and holds you tightly. His hands are rough and course from a lifetime of gardenwork. \"Oh, thank you, thank you. You have no idea what that means to me. You have a big heart, Dr. Chase, to forgive me. But I'm not sure that I can forgive myself. I've served ARC Two faithfully . . . one momentary lapse in fifty-one years, and yet, I let down those who put their lives in my hands.\"<br/><br/>\"Please, if you can just answer some of my questions . . .\"<br/><br/>But the Warden has already picked up shovel again. He resumes his work, attacking the earth with less violence this time but the same determination. ")
              }
              case ("No") {
                msg ("\"I'm afraid I can't do that,\" you say. \"I don't even know who you are, or what you've done . . .\"<br/><br/>The Warden grasps your hands in his and holds you tightly, like a drowning man holding a tree branch. His hands are rough and course from a lifetime of gardenwork. \"Please, Nicky, please forgive me. All these years, I've served ARC Two to the best of my ability. Fifty-one years . . . you know, Nicky, you were with me. One momentary lapse in fifty-one years, and yet, I let down those who put their lives in my hands. I don't deserve forgiveness, I know, but I still hold on to the hope that I might just hear it from your lips, that you forgive me . . .\"<br/><br/>You try to speak but there is a huge lump in your throat.<br/><br/>The Warden nods. \"I understand. Not even you can forgive me, Nicky.\" He starts to walk slowly down the path, towards the south, using the shovel as a blind man uses a cane. <br/><br/>\"Hey!\" you shout. \"Wait!\"<br/><br/>He pays you no heed. Soon, he is just a speck of grey in a sea of green.")
                MoveObject (Warden, limbo)
                SetObjectFlagOn (Conor Chase, "does_not_forgive_warden")
                MoveObject (Wardens Body, Couples Room)
              }
            }
          }
        }
        otherwise {
          msg ("You try to ask a question, but the Warden pays no attention to you. His glazed eyes are fixed on the hypnotic movement of the shovel against the ground.")
        }
      ]]></speak>
      <object name="Shovel" />
    </object>
    <object name="corpse">
      <inroomdescription>Lying on the ground is a body. It's eyes are closed and although you look at it for a while, it does not move.</inroomdescription>
      <attr name="feature_container" type="boolean">false</attr>
      <look>It's a woman, or at least it used to be. She's wearing striped pajamas, blue and white. Her eyes are closed and she has a slight smile on her face.</look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <usestandardverblist />
    </object>
    <object name="badge">
      <look>On the badge is a picture of a pretty woman, looking seriously at the camera. Beneath the portrait, black text reads "Captain Flora Schneider". </look>
      <take />
      <takemsg>You pick up the badge and clip it to your pants. You have a feeling it will come in handy.</takemsg>
      <dropmsg>You drop the badge unceremoniously onto the ground. </dropmsg>
    </object>
  </object>
  <object name="Museum">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You are in a small, circular room. A couple of objects lie around the room, with golden plaques beneath each. You are reminded of the small, hipster galleries you and Isabelle used to go to whenever you travelled to Europe. </description>
    <exit alias="south" to="Archive">
      <inherit name="southdirection" />
    </exit>
    <object name="Display Case">
      <look><![CDATA[The large, glass case appears to be empty at first, but as you step closer a holographic display flickers on inside. You see five great spaceships sailing in a tight formation across the empty galaxy, with the largest in the vanguard and the other four on the flanks, two to each side. No science fiction show has prepared you for these ships: they are things of beauty, with smooth, cylindrical bodies, and not a single seam or imperfection on their glossy surfaces. On the bow of each monolith is a circular logo of a black ship on a white sea, the word "ARC" carved into its hull. <br/><br/>The irony of a ship bearing the logo of another ship is not lost on you.]]></look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="Statue">
      <look><![CDATA[It's in the style of a Roman bust. Intelligent eyes, round spectacles . . . with a shock you realize the face is that of Dr. Schneider. You read the plaque below:<br/><br/><i>Dr. Carl Schneider 1955-2024<br/>Dr. Carl Schneider was born in Rotterdam, Netherlands, and immigrated to the United States with his parents when he was ten. Throughout his life, Dr. Schneider was a cardiologist, university lecturer, and an infectious diseases expert, but he was best known for his role as Chief Scientist at Cryptec Inc., and as the mastermind behind the Selection. When the grey death pandemic broke out in 2020, he lead Cryptec Inc. as the first private entity to create and test cryonic chambers on infected patients. His widely controversial paper, "Principles of the Selection for the Continuation of the Human Race", eventually lead to government sanctions on Cryptec Inc. and the ensuing world war. Despite being infected himself, he delayed treatment, instead prolonging his life through medication and therapy. When the ARC program took off to the cosmos, Dr. Carl Schneider chose to stay behind to supervise the manufacturing of cryonic units for the remaining human population. On August 5th, 2024, members of the HEFA militant group broke into his bunker, and he passed away in the ensuing shootout.<br/></i><br/>]]></look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="Art Piece">
      <look><![CDATA[It's a sculpture cast in bronze, and a disturbing one at that. A lone man stands atop a cliff, his eyes turned to the sky, while countless other faces writhe in a raging sea below, their bodies and limbs molded together. The inscription simply reads:<br/><br/><i>The Selection</i>]]></look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
    </object>
    <object name="Painting">
      <look><![CDATA[It's a watercolor of a field, filled to the brim with flowers. The golden plaque below reads:<br/><br/><i>The Garden at Home is Better, by Nicole Johnson, 2034 </i>]]></look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <usestandardverblist type="boolean">false</usestandardverblist>
    </object>
    <exit alias="north" to="Command Room">
      <inherit name="northdirection" />
      <runscript />
      <script type="script">
        if (Got(badge)) {
          msg ("You wave the badge in front of you, and the door slides open on silent tracks. Beyond the doorway, all you see is darkness. ")
          MoveObject (Conor Chase, Command Room)
        }
        else {
          msg ("There is something strange about this door; it doesn't seem to have a doorknob or any hinges. A golden placard above the door reads \"Command Room\".")
        }
      </script>
    </exit>
  </object>
  <object name="Sleep Chamber">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <exit alias="north" to="South Hallway">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="Bathroom">
    <description>The bathroom is small but still luxurious. It reminds you of the Four Seasons you and Isabelle stayed in on one of your spontaenous trips to Paris. You look at yourself in the mirror: you look the same as you ever did. Surely, not much time has passed. </description>
    <object name="toilet">
      <displayverbs type="stringlist">
        <value>use</value>
      </displayverbs>
      <feature_usegive />
      <use type="script">
        firsttime {
          msg ("You breathe a sign of relief as you urinate into the bowl. You hadn't realized how much you needed to go. When you finish, you push the lever, but nothing happens. Uh-oh. You close the toilet lid. Hopefully nobody will know it was you.")
        }
        otherwise {
          msg ("You should probably leave it alone. You don't want to clog the toilet as well; that would be embarrasing. ")
        }
      </use>
    </object>
    <object name="note">
      <inroomdescription>There is a yellow post-it note taped to the bottom right corner of the mirror. It looks like it's been there for a while.</inroomdescription>
      <look><![CDATA[It's a to-do list. It reads:<br/><br/><i>-weed the garden<br/>-inspect acquifer system for impurities<br/>-sweep the museum and archive<br/>-respond to Captain Chase's message</i>]]></look>
      <displayverbs type="stringlist">
        <value>Look at</value>
      </displayverbs>
      <useindividualverblist type="boolean">false</useindividualverblist>
    </object>
    <exit alias="east" to="Couples Room">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="Command Room">
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description>You've reached the front of the spaceship. You feel as if you've just entered the Star Room again, but instead of being spherical, this room is shaped like a cone. Sandwiched between a white floor and ceiling is a strip of star-speckled darkness, stretching from left to right across the peripheries of your vision. As you step up, holographic displays flare up all around you, turning the observation glass into a giant display. </description>
    <firstenter type="script">
    </firstenter>
    <enter type="script"><![CDATA[
      if (GetBoolean(Conor Chase, "does_not_forgive_warden")) {
        msg ("<br/>The holographic display to your left shows a grid of square photos, each labelled with a name. As you look at them longer you realize that they are live video footage of each of the rooms on the ship. In the square labelled \"Greenhouse\", you see the vegetables rotate slowly on the mechanical racks, the sparkling water flowing freely on the walls. In the square labelled \"Sleep Chamber\", you see rows upon rows of transparent pods, lined up neatly, their occupants frozen in eternal sleep. In the square labelled \"Warden's Quarters\", you see . . . the figure of a tall man dangling from the chandelier, a dirty white apron wrapped around his neck. ")
      }
      else {
        msg ("<br/>The holographic display to your left shows a grid of square photos, each labelled with a name. As you look at them longer you realize that they are live video footage of each of the rooms on the ship. In the square labelled \"Dr. Conor Chase\", you see your cozy bedroom, just waiting for you to return and take your well-deserved rest. In the square labelled \"Greenhouse\", you see the Warden still obstinately shovelling at the hard earth.\"In the square labelled \"Sleep Chamber\", you see rows upon rows of transparent pods, lined up neatly, their occupants frozen in eternal sleep.")
      }
    ]]></enter>
    <exit alias="south" to="Museum">
      <inherit name="southdirection" />
      <runscript />
      <script type="script">
        if (Got(badge)) {
          msg ("You wave the badge in front of you, and the door slides open on silent tracks. Beyond the doorway, all you see is darkness. ")
          MoveObject (Conor Chase, Museum)
        }
        else {
          msg ("There is something strange about this door; it doesn't seem to have a doorknob or any hinges. A golden placard above the door reads \"Museum\".")
        }
      </script>
    </exit>
    <object name="Display">
      <displayverbs type="stringlist" />
      <inroomdescription>Directly in front of you, the black-and-white logo of the ARC flashes impatiently. "You have an incoming message," says the voice that sounds so like Isabelle. "Urgent message incoming. Please receive."</inroomdescription>
      <receivemessage type="script"><![CDATA[
        msg ("You raise your hand and point at the flashing icon. The display in front of you dissipates into the face of an old woman, so familiar and yet so strange to you. She opens her mouth, and you realize that her voice is the voice of the ship.<br/><br/>\"This is Captain Chloe Chase of the ARC One. I am hailing the ARC Two because I haven't received any communications from you in seventy-two hours. We are aware that the ARC Two was hit when we passed through the asteroid field, but our analyses tell us that the hull was not breached. Please respond as soon as possible with your status. If we do not hear from you in twenty-four hours, we will assume the worst and begin emergency measures. Please be advised that it can take up to a week for us to reach you and begin the proper boarding procedures. Captain Chase out.\"<br/><br/>The display stops. \"Auto-playing older messages,\" Chloe says. \"Say anything to cancel.\"<br/><br/>It's the same face again, but less serious, less stern. This is the playful, sensitive Chloe that you once knew. This is your Chloe.<br/><br/>\"Hello, Jake. I hope you are doing well. I know it's been a difficult time for you, ever since Nicole passed away. I should have been there for you more, and I'm truly sorry about that. But today, I want to discuss something happier. I want to talk about the future, not the past. As you know, we've just passed the fifty year mark of our journey, and there is a decision that needs to be made. I have already reached out to the other wardens, just to prepare you before we have any official discussions. I know that all of us have been pondering this for all these long years. <br/><br/>\"Shall we go back, or shall we continue? Shall we return to our birthplace, a place we have had no contact with for half a century, and which we now know nothing about? Shall we attempt to clean up the mess we find there, to fix our mistakes of the past? Or shall we continue into the cosmos? Shall we finally let go of our mistakes and start anew? This is the most difficult question I have ever faced, and for now I am undecided. I would not hold it against the other wardens if we were to disagree and diverge in our paths. Please think on this, Jake. I would love to hear your thoughts.\"<br/>")
        if (Got(necklace)) {
          msg ("You reach into your pocket and pull out the necklace that you had given Chloe on her twenty-first birthday, and that she had given back to you fifty years ago. The turtle, a symbol for Mother Earth. A symbol for longevity, and for perseverance and stubbornness. Whatever the world was like now, you will not have to face it alone; you will have your daughter beside you. You know what your answer will be.<br/>")
        }
        else if (not GetBoolean(Conor Chase, "met_chloe")) {
          msg ("You think back to the events that felt like they took place this morning, but which you now know was fifty years ago. You remember how you chose not to meet with your daughter one last time, how you wanted to spare her the agony of a goodbye. Perseverance and survival are at the heart of human nature, as is the ability to adapt and move forward. You are not afraid of the emptiness of the cosmos, because you will not have to face it alone; you will have your daughter at your side. You know what your answer will be. <br/>")
        }
        msg ("\"But for now, I hope you have the best time.\" She smiles. \"Inbox empty\", Chloe says. \"Start speaking to respond.\"<br/><br/>You do.")
        SetFontSize (20)
        PrintCentered ("The End<br/><br/>")
        finish
      ]]></receivemessage>
    </object>
  </object>
  <verb>
    <property>receivemessage</property>
    <pattern>receive message</pattern>
    <defaultexpression>"You can't receive message " + object.article + "."</defaultexpression>
  </verb>
  <type name="defaultgame">
    <enablehyperlinks />
    <echocommand />
    <echohyperlinks />
    <showdescriptiononenter />
    <autodescription />
    <defaultfont>Georgia, serif</defaultfont>
    <defaultfontsize type="int">12</defaultfontsize>
    <defaultbackground>White</defaultbackground>
    <defaultforeground>Black</defaultforeground>
    <defaultlinkforeground>Blue</defaultlinkforeground>
    <backgroundimage type="string"></backgroundimage>
    <setbackgroundopacity type="boolean">false</setbackgroundopacity>
    <backgroundopacity type="double">0.5</backgroundopacity>
    <menufont>Arial</menufont>
    <menufontsize type="int">9</menufontsize>
    <menubackground>White</menubackground>
    <menuforeground>Black</menuforeground>
    <menuhoverbackground>LightGrey</menuhoverbackground>
    <menuhoverforeground>Black</menuhoverforeground>
    <underlinehyperlinks />
    <compassdirections type="stringlist">
      <value>northwest</value>
      <value>north</value>
      <value>northeast</value>
      <value>west</value>
      <value>east</value>
      <value>southwest</value>
      <value>south</value>
      <value>southeast</value>
      <value>up</value>
      <value>down</value>
      <value>in</value>
      <value>out</value>
    </compassdirections>
    <clearframe />
    <timeelapsed type="int">0</timeelapsed>
    <appendobjectdescription type="boolean">false</appendobjectdescription>
    <allobjects type="stringlist">
      <value>all</value>
      <value>everything</value>
    </allobjects>
    <parserignoreprefixes type="stringlist">
      <value>the</value>
      <value>a</value>
      <value>an</value>
    </parserignoreprefixes>
    <displayroomdescriptiononstart />
    <showpanes />
    <showcommandbar />
    <showlocation />
    <statusandcompassattop type="boolean">false</statusandcompassattop>
    <turnoffcompass type="boolean">false</turnoffcompass>
    <turnoffinventory type="boolean">false</turnoffinventory>
    <turnoffplacesandobjects type="boolean">false</turnoffplacesandobjects>
    <borderlesscursor type="boolean">false</borderlesscursor>
    <colourblend type="boolean">false</colourblend>
    <commandpane type="boolean">false</commandpane>
    <customstatuspane type="boolean">false</customstatuspane>
    <panestheme>Classic</panestheme>
    <shadowbox type="boolean">false</shadowbox>
    <respondtogridclicks type="boolean">false</respondtogridclicks>
    <commandcursor><![CDATA[>]]></commandcursor>
    <moneyformat>$!</moneyformat>
    <classiclocation />
    <turnoffsavebutton type="boolean">false</turnoffsavebutton>
    <mapexitwidth type="int">1</mapexitwidth>
    <mapexitcolour>Black</mapexitcolour>
    <setcustomwidth type="boolean">false</setcustomwidth>
    <customwidth type="int">950</customwidth>
    <setcustompadding type="boolean">false</setcustompadding>
    <custompaddingtop type="int">30</custompaddingtop>
    <custompaddingbottom type="int">0</custompaddingbottom>
    <custompaddingleft type="int">20</custompaddingleft>
    <custompaddingright type="int">20</custompaddingright>
    <showborder />
    <showscore type="boolean">false</showscore>
    <showhealth type="boolean">false</showhealth>
    <showmoney type="boolean">false</showmoney>
    <showtitle />
    <autodisplayverbs />
    <clearscreenonroomenter type="boolean">false</clearscreenonroomenter>
    <attr name="autodescription_youarein" type="int">1</attr>
    <attr name="autodescription_youcansee" type="int">2</attr>
    <attr name="autodescription_youcango" type="int">3</attr>
    <attr name="autodescription_description" type="int">4</attr>
    <autodescription_youarein_useprefix />
    <attr name="autodescription_youarein_newline" type="boolean">false</attr>
    <attr name="autodescription_youcansee_newline" type="boolean">false</attr>
    <attr name="autodescription_youcango_newline" type="boolean">false</attr>
    <attr name="autodescription_description_newline" type="boolean">false</attr>
    <changeroom_newline />
    <attr name="command_newline" type="boolean">false</attr>
    <description type="string"></description>
    <languageid>en</languageid>
    <gridmap type="boolean">false</gridmap>
    <mapscale type="int">30</mapscale>
    <mapsize type="int">300</mapsize>
    <attr name="feature_lightdark" type="boolean">false</attr>
    <attr name="feature_pictureframe" type="boolean">false</attr>
    <attr name="feature_limitinventory" type="boolean">false</attr>
    <attr name="feature_asktell" type="boolean">false</attr>
    <attr name="feature_annotations" type="boolean">false</attr>
    <attr name="feature_advancedwearables" type="boolean">false</attr>
    <attr name="feature_advancedscripts" type="boolean">false</attr>
    <deactivatecommandlinks type="boolean">false</deactivatecommandlinks>
    <multiplecommands type="boolean">false</multiplecommands>
    <publishfileextensions>*.jpg;*.jpeg;*.png;*.gif;*.js;*.wav;*.mp3;*.htm;*.html;*.svg;*.ogg;*.ogv</publishfileextensions>
    <nohtmllog type="boolean">false</nohtmllog>
    <notranscript type="boolean">false</notranscript>
    <suppressturnscripts />
    <attr name="feature_devmode" type="boolean">false</attr>
    <changedpov type="script">
      InitPOV (oldvalue, game.pov)
    </changedpov>
    <textprocessorcommands type="scriptdictionary">
      <item key="if ">
        game.textprocessorcommandresult = ProcessTextCommand_If (section, data)
      </item>
      <item key="either ">
        game.textprocessorcommandresult = ProcessTextCommand_Either (section, data)
      </item>
      <item key="here ">
        game.textprocessorcommandresult = ProcessTextCommand_Here (section, data)
      </item>
      <item key="nothere ">
        game.textprocessorcommandresult = ProcessTextCommand_Here (section, data)
      </item>
      <item key="popup:">
        game.textprocessorcommandresult = ProcessTextCommand_Popup (section, data)
      </item>
      <item key="i:">
        game.textprocessorcommandresult = ProcessTextCommand_Format (section, data)
      </item>
      <item key="b:">
        game.textprocessorcommandresult = ProcessTextCommand_Format (section, data)
      </item>
      <item key="s:">
        game.textprocessorcommandresult = ProcessTextCommand_Format (section, data)
      </item>
      <item key="u:">
        game.textprocessorcommandresult = ProcessTextCommand_Format (section, data)
      </item>
      <item key="colour:">
        game.textprocessorcommandresult = ProcessTextCommand_Colour (section, data)
      </item>
      <item key="color:">
        game.textprocessorcommandresult = ProcessTextCommand_Colour (section, data)
      </item>
      <item key="back:">
        game.textprocessorcommandresult = ProcessTextCommand_Colour (section, data)
      </item>
      <item key="object:">
        game.textprocessorcommandresult = ProcessTextCommand_Object (section, data)
      </item>
      <item key="command:">
        game.textprocessorcommandresult = ProcessTextCommand_Command (section, data)
      </item>
      <item key="page:">
        game.textprocessorcommandresult = ProcessTextCommand_Command (section, data)
      </item>
      <item key="exit:">
        game.textprocessorcommandresult = ProcessTextCommand_Exit (section, data)
      </item>
      <item key="once:">
        game.textprocessorcommandresult = ProcessTextCommand_Once (section, data)
      </item>
      <item key="notfirst:">
        game.textprocessorcommandresult = ProcessTextCommand_NotFirst (section, data)
      </item>
      <item key="random:">
        game.textprocessorcommandresult = ProcessTextCommand_Random (section, data)
      </item>
      <item key="rndalt:">
        game.textprocessorcommandresult = ProcessTextCommand_RandomAlias (section, data)
      </item>
      <item key="img:">
        game.textprocessorcommandresult = ProcessTextCommand_Img (section, data)
      </item>
      <item key="counter:">
        game.textprocessorcommandresult = ProcessTextCommand_Counter (section, data)
      </item>
      <item key="select:">
        game.textprocessorcommandresult = ProcessTextCommand_Select (section, data)
      </item>
      <item key="eval:">
        game.textprocessorcommandresult = ProcessTextCommand_Eval (section, data)
      </item>
      <item key="=">
        game.textprocessorcommandresult = ProcessTextCommand_Eval (section, data)
      </item>
    </textprocessorcommands>
  </type>
  <type name="theme_novella">
    <setcustompadding />
    <showborder type="boolean">false</showborder>
    <showpanes type="boolean">false</showpanes>
    <showlocation type="boolean">false</showlocation>
    <setcustomwidth />
    <customwidth type="int">650</customwidth>
    <custompaddingtop type="int">60</custompaddingtop>
  </type>
  <type name="theme_retro">
    <defaultbackground>Black</defaultbackground>
    <defaultforeground>White</defaultforeground>
    <defaultlinkforeground>White</defaultlinkforeground>
    <defaultfont>'Lucida Console', Monaco, monospace</defaultfont>
    <defaultwebfont>Press Start 2P</defaultwebfont>
    <menufontsize type="int">14</menufontsize>
    <menufont>'Lucida Console', Monaco, monospace</menufont>
    <menubackground>Black</menubackground>
    <menuforeground>White</menuforeground>
    <menuhoverbackground>GreenYellow</menuhoverbackground>
  </type>
  <type name="theme_typewriter">
    <setcustompadding />
    <showborder type="boolean">false</showborder>
    <showpanes type="boolean">false</showpanes>
    <showlocation type="boolean">false</showlocation>
    <setcustomwidth />
    <customwidth type="int">650</customwidth>
    <custompaddingtop type="int">60</custompaddingtop>
    <defaultfont>'Courier New', Courier, monospace</defaultfont>
    <defaultwebfont>Special Elite</defaultwebfont>
  </type>
  <type name="theme_hotdogstand">
    <defaultbackground>Red</defaultbackground>
    <defaultforeground>Yellow</defaultforeground>
    <defaultlinkforeground>Yellow</defaultlinkforeground>
    <defaultfont>'Comic Sans MS', cursive, sans-serif</defaultfont>
    <menufontsize type="int">14</menufontsize>
    <menufont>Impact, Charcoal, sans-serif</menufont>
    <menubackground>Red</menubackground>
    <menuforeground>Yellow</menuforeground>
    <menuhoverbackground>Black</menuhoverbackground>
    <menuhoverforeground>Yellow</menuhoverforeground>
  </type>
  <type name="defaultobject">
    <visible />
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Take</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Look at</value>
      <value>Use</value>
      <value>Drop</value>
    </inventoryverbs>
    <take type="boolean">false</take>
    <use type="boolean">false</use>
    <givesingle type="boolean">false</givesingle>
    <drop />
    <gender>it</gender>
    <article>it</article>
    <possessive>its</possessive>
    <wornmodifier>worn</wornmodifier>
    <isopen type="boolean">false</isopen>
    <open type="boolean">false</open>
    <close type="boolean">false</close>
    <container type="boolean">false</container>
    <descprefix>You are in</descprefix>
    <objectslistprefix>You can see</objectslistprefix>
    <exitslistprefix>You can go</exitslistprefix>
    <contentsprefix>containing</contentsprefix>
    <description type="string"></description>
    <attr name="implementation_notes" type="string"></attr>
    <scenery type="boolean">false</scenery>
    <hidechildren type="boolean">false</hidechildren>
    <listchildren type="boolean">false</listchildren>
    <usedefaultprefix />
    <volume type="int">0</volume>
    <price type="int">0</price>
    <dark type="boolean">false</dark>
    <lightstrength type="string"></lightstrength>
    <darklevel type="boolean">false</darklevel>
    <attr name="grid_width" type="int">1</attr>
    <attr name="grid_length" type="int">1</attr>
    <attr name="grid_fill">White</attr>
    <attr name="grid_border">Black</attr>
    <attr name="grid_borderwidth" type="int">1</attr>
    <attr name="grid_bordersides" type="int">15</attr>
    <attr name="grid_render" type="boolean">false</attr>
    <attr name="grid_label" type="string"></attr>
    <attr name="grid_label_colour">Black</attr>
    <grid_parent_offset_auto />
    <attr name="grid_parent_offset_x" type="int">0</attr>
    <attr name="grid_parent_offset_y" type="int">0</attr>
    <attr name="pov_alias">me</attr>
    <pov_alt type="stringlist">
      <value>me</value>
      <value>myself</value>
      <value>self</value>
    </pov_alt>
    <attr name="pov_look">Looking good.</attr>
    <attr name="pov_gender">you</attr>
    <attr name="pov_article">yourself</attr>
    <attr name="pov_possessive">your</attr>
    <attr name="feature_usegive" type="boolean">false</attr>
    <attr name="feature_container" type="boolean">false</attr>
    <attr name="feature_switchable" type="boolean">false</attr>
    <attr name="feature_edible" type="boolean">false</attr>
    <attr name="feature_player" type="boolean">false</attr>
    <attr name="feature_lightdark" type="boolean">false</attr>
    <visited type="boolean">false</visited>
    <hasbeenmoved type="boolean">false</hasbeenmoved>
    <timesexamined type="int">0</timesexamined>
    <attr name="not_all" type="boolean">false</attr>
    <changedparent type="script">
      if (game.pov = this) {
        if (IsDefined("oldvalue")) {
          OnEnterRoom (oldvalue)
        }
        else {
          OnEnterRoom (null)
        }
        if (game.gridmap) {
          MergePOVCoordinates
        }
      }
      this.hasbeenmoved = true
    </changedparent>
    <changedisopen type="script">
      if (this.isopen and HasScript(this, "onopen")) {
        do (this, "onopen")
      }
      if (not this.isopen and HasScript(this, "onclose")) {
        do (this, "onclose")
      }
    </changedisopen>
    <changedlocked type="script">
      if (this.locked and HasScript(this, "onlock")) {
        do (this, "onlock")
      }
      if (not this.locked and HasScript(this, "onunlock")) {
        do (this, "onunlock")
      }
    </changedlocked>
    <changedswitchedon type="script">
      if (this.switchedon and HasScript(this, "onswitchon")) {
        do (this, "onswitchon")
      }
      if (not this.switchedon and HasScript(this, "onswitchoff")) {
        do (this, "onswitchoff")
      }
    </changedswitchedon>
  </type>
  <type name="defaultexit">
    <displayverbs type="stringlist">
      <value>Go to</value>
    </displayverbs>
    <visible />
    <scenery type="boolean">false</scenery>
    <locked type="boolean">false</locked>
    <lockmessage>That way is locked.</lockmessage>
    <lookonly type="boolean">false</lookonly>
    <runscript type="boolean">false</runscript>
    <lightstrength type="string"></lightstrength>
    <attr name="grid_length" type="int">1</attr>
    <attr name="grid_render" type="boolean">false</attr>
    <attr name="grid_offset_x" type="int">0</attr>
    <attr name="grid_offset_y" type="int">0</attr>
  </type>
  <type name="direction">
    <displayverbs type="stringlist">
      <value>Go</value>
    </displayverbs>
  </type>
  <type name="compassdirection">
    <inherit name="direction" />
    <prefix type="string"></prefix>
    <suffix type="string"></suffix>
  </type>
  <type name="updowndirection">
    <inherit name="direction" />
    <prefix type="string"></prefix>
    <suffix type="string"></suffix>
  </type>
  <type name="inoutdirection">
    <inherit name="direction" />
    <prefix type="string"></prefix>
    <suffix type="string"></suffix>
  </type>
  <type name="northwestdirection">
    <inherit name="compassdirection" />
    <alias>northwest</alias>
    <alt type="stringlist">
      <value>nw</value>
    </alt>
  </type>
  <type name="northdirection">
    <inherit name="compassdirection" />
    <alias>north</alias>
    <alt type="stringlist">
      <value>n</value>
    </alt>
  </type>
  <type name="northeastdirection">
    <inherit name="compassdirection" />
    <alias>northeast</alias>
    <alt type="stringlist">
      <value>ne</value>
    </alt>
  </type>
  <type name="westdirection">
    <inherit name="compassdirection" />
    <alias>west</alias>
    <alt type="stringlist">
      <value>w</value>
    </alt>
  </type>
  <type name="eastdirection">
    <inherit name="compassdirection" />
    <alias>east</alias>
    <alt type="stringlist">
      <value>e</value>
    </alt>
  </type>
  <type name="southwestdirection">
    <inherit name="compassdirection" />
    <alias>southwest</alias>
    <alt type="stringlist">
      <value>sw</value>
    </alt>
  </type>
  <type name="southdirection">
    <inherit name="compassdirection" />
    <alias>south</alias>
    <alt type="stringlist">
      <value>s</value>
    </alt>
  </type>
  <type name="southeastdirection">
    <inherit name="compassdirection" />
    <alias>southeast</alias>
    <alt type="stringlist">
      <value>se</value>
    </alt>
  </type>
  <type name="updirection">
    <inherit name="updowndirection" />
    <alias>up</alias>
    <alt type="stringlist">
      <value>u</value>
    </alt>
  </type>
  <type name="downdirection">
    <inherit name="updowndirection" />
    <alias>down</alias>
    <alt type="stringlist">
      <value>d</value>
    </alt>
  </type>
  <type name="indirection">
    <inherit name="inoutdirection" />
    <alias>in</alias>
    <alt type="stringlist">
      <value></value>
    </alt>
  </type>
  <type name="outdirection">
    <inherit name="inoutdirection" />
    <alias>out</alias>
    <alt type="stringlist">
      <value>o</value>
    </alt>
  </type>
  <type name="defaultcommand">
    <pattern type="simplepattern"></pattern>
  </type>
  <type name="defaultverb">
    <separator>with; using</separator>
    <multiobjectmenu>With which object?</multiobjectmenu>
    <multiobjectdefault>That doesn't work.</multiobjectdefault>
    <multiobjectmenuempty>There are no objects available to do that with.</multiobjectmenuempty>
    <script type="script"><![CDATA[
      if (not IsDefined("object2")) {
        object2 = null
      }
      switch (TypeOf(object, this.property)) {
        case ("script") {
          if (object2 = null) {
            do (object, this.property)
          }
          else {
            msg (this.multiobjectdefault)
          }
        }
        case ("string") {
          if (object2 = null) {
            msg (GetString(object, this.property))
          }
          else {
            msg (this.multiobjectdefault)
          }
        }
        case ("scriptdictionary") {
          if (object2 <> null) {
            HandleMultiVerb (object, this.property, object2, this.multiobjectdefault)
          }
          else {
            objectlist = ListCombine (ScopeReachableInventory(), ScopeReachableNotHeld())
            excludelist = NewObjectList()
            list add (excludelist, game.pov)
            list add (excludelist, object)
            candidates = ListExclude(RemoveSceneryObjects(objectlist), excludelist)
            if (ListCount(candidates) = 0) {
              msg (this.multiobjectmenuempty)
            }
            else {
              game.pov.multiverb = this.property
              game.pov.multiverbobject = object
              game.pov.multiverbobjectdefault = this.multiobjectdefault
              ShowMenu (this.multiobjectmenu, candidates, true) {
                if (result <> null) {
                  HandleMultiVerb (game.pov.multiverbobject, game.pov.multiverb, GetObject(result), game.pov.multiverbobjectdefault)
                  game.pov.multiverb = null
                  game.pov.multiverbobject = null
                  game.pov.multiverbobjectdefault = null
                }
              }
            }
          }
        }
        case ("null") {
          if (this.defaulttext <> null) {
            msg (this.defaulttext)
          }
          else if (this.defaulttemplate <> null) {
            msg (DynamicTemplate(this.defaulttemplate, object))
          }
          else if (this.defaultexpression <> null) {
            params = NewDictionary()
            dictionary add (params, "object", object)
            msg (Eval(this.defaultexpression, params))
          }
          else {
            error ("No verb response defined")
          }
        }
        default {
          error ("No verb response defined")
        }
      }
    ]]></script>
  </type>
  <type name="npc_type">
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Speak to</value>
    </displayverbs>
    <not_all />
  </type>
  <type name="plural_npc_type">
    <inherit name="npc_type" />
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Speak to</value>
    </displayverbs>
  </type>
  <type name="male">
    <inherit name="npc_type" />
    <gender>he</gender>
    <article>him</article>
    <possessive>his</possessive>
    <wornmodifier>worn</wornmodifier>
  </type>
  <type name="namedmale">
    <inherit name="male" />
    <usedefaultprefix type="boolean">false</usedefaultprefix>
  </type>
  <type name="female">
    <inherit name="npc_type" />
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Speak to</value>
    </displayverbs>
    <gender>she</gender>
    <article>her</article>
    <possessive>her</possessive>
    <wornmodifier>worn</wornmodifier>
  </type>
  <type name="namedfemale">
    <inherit name="female" />
    <usedefaultprefix type="boolean">false</usedefaultprefix>
  </type>
  <type name="plural">
    <gender>they</gender>
    <article>them</article>
    <possessive>their</possessive>
    <wornmodifier>worn</wornmodifier>
  </type>
  <type name="maleplural">
    <inherit name="plural_npc_type" />
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Speak to</value>
    </displayverbs>
    <gender>they</gender>
    <article>them</article>
    <possessive>their</possessive>
    <wornmodifier>worn</wornmodifier>
  </type>
  <type name="femaleplural">
    <inherit name="plural_npc_type" />
    <displayverbs type="stringlist">
      <value>Look at</value>
      <value>Speak to</value>
    </displayverbs>
    <gender>they</gender>
    <article>them</article>
    <possessive>their</possessive>
    <wornmodifier>worn</wornmodifier>
  </type>
  <type name="openable">
    <open />
    <close />
    <displayverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </inventoryverbs>
  </type>
  <type name="container_base">
    <container />
  </type>
  <type name="container_closed">
    <inherit name="container_base" />
    <open />
    <close />
    <displayverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </inventoryverbs>
  </type>
  <type name="container_open">
    <inherit name="container_base" />
    <isopen />
    <open />
    <close />
    <displayverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </inventoryverbs>
  </type>
  <type name="surface">
    <inherit name="container_base" />
    <isopen />
    <transparent />
    <contentsprefix>on which there is</contentsprefix>
  </type>
  <type name="container">
    <inherit name="container_open" />
    <displayverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </inventoryverbs>
  </type>
  <type name="container_limited">
    <inherit name="container" />
    <maxobjects type="int">1</maxobjects>
    <maxvolume type="int">100</maxvolume>
    <addscript type="script"><![CDATA[
      activecontainer = this
      correct = true
      while (DoesInherit(activecontainer, "container_base")) {
        if (HasInt(activecontainer, "maxvolume")) {
          if (GetVolume(object, true) + GetVolume(activecontainer, false) > activecontainer.maxvolume) {
            correct = false
            if (HasString(this, "containerfullmessage")) {
              message = this.containerfullmessage
            }
            else {
              message = DynamicTemplate("ContainerFull", this)
            }
          }
        }
        activecontainer = activecontainer.parent
      }
      children = GetDirectChildren(this)
      if (listcount(children) >= this.maxobjects) {
        correct = false
        if (HasString(this, "containermaxobjects")) {
          message = this.containermaxobjects
        }
        else {
          message = DynamicTemplate("MaxObjectsInContainer", this)
        }
      }
      if (correct = false) {
        msg (message)
      }
      else {
        if (HasScript(object, "drop")) {
          params = NewDictionary()
          dictionary add (params, "destination", this)
          do (object, "drop", params)
        }
        else {
          object.parent = this
          msg (Template("Done"))
        }
      }
    ]]></addscript>
    <displayverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Open</value>
      <value>Close</value>
    </inventoryverbs>
  </type>
  <type name="container_lockable">
    <locked />
    <nokeymessage>You do not have the key.</nokeymessage>
    <unlockmessage>Unlocked.</unlockmessage>
    <lockmessage>Locked.</lockmessage>
    <canlockopen type="boolean">false</canlockopen>
    <autoopen />
    <autounlock />
    <openscript type="script">
      if (this.locked) {
        if (this.autounlock and AllKeysAvailable(this)) {
          do (this, "unlock")
          if (not this.isopen) {
            OpenObject (this)
          }
        }
        else {
          msg (DynamicTemplate("LockedObject", this))
        }
      }
      else {
        OpenObject (this)
      }
    </openscript>
    <closescript type="script">
      if (this.locked) {
        msg (DynamicTemplate("LockedObject", this))
      }
      else {
        CloseObject (this)
      }
    </closescript>
    <lock type="script">
      if (this.locked) {
        msg (DynamicTemplate("AlreadyLocked", this))
      }
      else if (this.isopen and not this.canlockopen) {
        msg (DynamicTemplate("CannotLockOpen", this))
      }
      else {
        if (AllKeysAvailable(this)) {
          msg (this.lockmessage)
          this.locked = true
        }
        else {
          msg (this.nokeymessage)
        }
      }
    </lock>
    <unlock type="script">
      if (not this.locked) {
        msg (DynamicTemplate("AlreadyUnlocked", this))
      }
      else {
        if (AllKeysAvailable(this)) {
          msg (this.unlockmessage)
          this.locked = false
          if (this.autoopen and not this.isopen) {
            TryOpenClose (true, this)
          }
        }
        else {
          msg (this.nokeymessage)
        }
      }
    </unlock>
  </type>
  <type name="defaultplayer">
    <money type="int">0</money>
  </type>
  <type name="switchable">
    <switchedon type="boolean">false</switchedon>
    <cannotswitchon type="string"></cannotswitchon>
    <turnon type="script">
      if (ListContains(ScopeReachable(), this)) {
        if (this.switchedon) {
          msg (DynamicTemplate("AlreadySwitchedOn", this))
        }
        else if (not this.cannotswitchon = "") {
          msg (this.cannotswitchon)
        }
        else {
          if (HasString(this, "switchonmsg")) {
            msg (this.switchonmsg)
          }
          else {
            msg (DynamicTemplate("SwitchedOn", this))
          }
          this.switchedon = true
        }
      }
      else {
        msg (DynamicTemplate("DefaultTurnOn", this))
      }
    </turnon>
    <turnoff type="script">
      if (ListContains(ScopeReachable(), this)) {
        if (not this.switchedon) {
          msg (DynamicTemplate("AlreadySwitchedOff", this))
        }
        else {
          if (HasString(this, "switchoffmsg")) {
            msg (this.switchoffmsg)
          }
          else {
            msg (DynamicTemplate("SwitchedOff", this))
          }
          this.switchedon = false
        }
      }
      else {
        msg (DynamicTemplate("DefaultTurnOff", this))
      }
    </turnoff>
    <displayverbs type="stringlist">
      <value>Switch on</value>
      <value>Switch off</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Switch on</value>
      <value>Switch off</value>
    </inventoryverbs>
  </type>
  <type name="edible">
    <eathealth type="int">0</eathealth>
    <eat type="script">
      if (HasString(this, "eatmsg")) {
        msg (this.eatmsg)
      }
      else {
        msg (DynamicTemplate("Eaten", this))
      }
      if (HasInt(game.pov, "health")) {
        game.pov.health = game.pov.health + this.eathealth
      }
      destroy (this.name)
    </eat>
    <displayverbs type="stringlist">
      <value>Eat</value>
    </displayverbs>
    <inventoryverbs type="stringlist">
      <value>Eat</value>
    </inventoryverbs>
  </type>
  <type name="gridborder_path_ew">
    <attr name="grid_bordersides" type="int">10</attr>
  </type>
  <type name="gridborder_path_e">
    <attr name="grid_bordersides" type="int">11</attr>
  </type>
  <type name="gridborder_path_w">
    <attr name="grid_bordersides" type="int">14</attr>
  </type>
  <type name="gridborder_path_ns">
    <attr name="grid_bordersides" type="int">5</attr>
  </type>
  <type name="gridborder_path_n">
    <attr name="grid_bordersides" type="int">7</attr>
  </type>
  <type name="gridborder_path_s">
    <attr name="grid_bordersides" type="int">13</attr>
  </type>
  <type name="wearable">
    <usestandardverblist />
    <worn type="boolean">false</worn>
    <armour type="int">0</armour>
    <attr name="multistate_status" type="int">0</attr>
    <invverbs type="string"></invverbs>
    <wornverbs type="string"></wornverbs>
    <removeable />
    <attr name="wear_layer" type="int">2</attr>
    <wear_adjverbs />
    <wear_slots type="stringlist" />
    <take type="script">
      msg (DynamicTemplate("TakeSuccessful", this))
      this.parent = game.pov
      SetVerbs
    </take>
    <colourmylistalias type="script"><![CDATA[
      if (HasString(this, "alias")) {
        s = CapFirst(this.alias)
      }
      else {
        s = CapFirst(this.name)
      }
      if (HasString(this, "listalias")) {
        s = this.listalias
      }
      this.listalias = "<span style=\"color:blue\">" + s + "</span>"
    ]]></colourmylistalias>
    <inventoryverbs type="stringlist">
      <value>Wear</value>
      <value>Remove</value>
    </inventoryverbs>
  </type>
  <type name="devmode">
    <devmode_active />
    <attr name="devmode_changepov" type="boolean">false</attr>
    <attr name="devmode_changepovpos" type="boolean">false</attr>
    <attr name="devmode_setinitscript" type="boolean">false</attr>
    <devmode_setverbs />
    <devmode_showinfos />
    <devmode_showdebugtable />
    <devmode_ownfontcolour />
    <attr name="devmode_fontcolour">Green</attr>
    <devmode_attributes type="stringdictionary" />
    <devmode_verbs type="stringlist">
      <value>#drop</value>
      <value>#take</value>
      <value>#to</value>
      <value>#open</value>
      <value>#close</value>
      <value>#on</value>
      <value>#off</value>
    </devmode_verbs>
  </type>
  <function name="GetDefaultPrefix" parameters="obj" type="string"><![CDATA[
    if (Instr("aeiou", LCase(Left(GetDisplayAlias(obj), 1))) > 0) {
      return ("an")
    }
    else {
      return ("a")
    }
  ]]></function>
  <function name="WriteVerb" parameters="obj, verb" type="string">
    return (CapFirst(obj.gender) + " " + Conjugate(obj, verb))
  </function>
  <function name="Conjugate" parameters="obj, verb" type="string">
    gender = obj.gender
    if (gender = "he" or gender = "she") {
      gender = "it"
    }
    switch (verb) {
      case ("be") {
        switch (gender) {
          case ("i") {
            return ("am")
          }
          case ("you") {
            return ("are")
          }
          case ("it") {
            return ("is")
          }
          case ("we") {
            return ("are")
          }
          case ("they") {
            return ("are")
          }
          default {
            return ("is")
          }
        }
      }
      case ("do") {
        switch (gender) {
          case ("i") {
            return ("do")
          }
          case ("you") {
            return ("do")
          }
          case ("it") {
            return ("does")
          }
          case ("we") {
            return ("do")
          }
          case ("they") {
            return ("do")
          }
          default {
            return ("do")
          }
        }
      }
      default {
        if (gender = "it") {
          if (EndsWith(verb, "y") and not EndsWith(verb, "ey")) {
            return (Mid(verb, 1, Lengthof(verb) - 1) + "ies")
          }
          else {
            return (verb + "s")
          }
        }
        else {
          return (verb)
        }
      }
    }
  </function>
  <function name="Possessive" parameters="possessive, object" type="string">
    return (possessive + " " + GetDisplayAlias(object))
  </function>
  <function name="ToWords" parameters="number" type="string"><![CDATA[
    if (not TypeOf(number) = "int") {
      error ("ToWords can only handle ints")
    }
    number_units = Split("zero;one;two;three;four;five;six;seven;eight;nine;ten;eleven;twelve;thirteen;fourteen;fifteen;sixteen;seventeen;eighteen;nineteen;twenty", ";")
    number_tens = Split("twenty;thirty;forty;fifty;sixty;seventy;eighty;ninety", ";")
    s = ""
    if (number < 0) {
      s = "minus "
      number = -number
    }
    if (number < 2000) {
      hundreds = number / 100
      number = number % 100
      if (hundreds > 0) {
        s = s + StringListItem(number_units, hundreds) + " hundred "
        if (number > 0) {
          s = s + "and "
        }
      }
      if (number < 20) {
        if (not number = 0 or s = "") {
          s = s + StringListItem(number_units, number)
        }
      }
      else {
        units = number % 10
        tens = (number / 10) % 10
        s = s + StringListItem(number_tens, tens - 2)
        if (not units = 0) {
          s = s + StringListItem(number_units, units)
        }
      }
    }
    else {
      s = ToString(number)
    }
    return (Trim(s))
  ]]></function>
  <function name="GetDefiniteName" parameters="obj" type="string">
    result = GetDisplayAlias(obj)
    if (GetBoolean(obj, "usedefaultprefix") or not obj.prefix = null) {
      result = "the " + result
    }
    return (result)
  </function>
  <function name="ListObjectContents" parameters="object"><![CDATA[
    if ((GetBoolean(object, "isopen") or GetBoolean(object, "transparent")) and GetBoolean(object, "listchildren")) {
      if (GetBoolean(object, "hidechildren")) {
        object.hidechildren = false
      }
      if (HasString(object, "listchildrenprefix")) {
        listprefix = object.listchildrenprefix
      }
      else {
        listprefix = DynamicTemplate("ObjectContains", object)
      }
      list = FormatObjectList(listprefix, object, Template("And"), ".")
      if (list <> "") {
        msg (list)
      }
    }
  ]]></function>
  <function name="DoTake" parameters="object, ismultiple"><![CDATA[
    prefix = ""
    if (ismultiple) {
      prefix = GetDisplayAlias(object) + ": "
    }
    if (object.parent = game.pov) {
      msg (prefix + DynamicTemplate("AlreadyTaken", object))
    }
    else if (not ListContains(ScopeReachable(), object)) {
      msg (BlockingMessage(object, prefix))
    }
    else {
      volume = 0
      continue = true
      foreach (obj, GetAllChildObjects(game.pov)) {
        if (HasInt(obj, "volume")) {
          volume = volume + obj.volume
        }
      }
      if (not Contains(game.pov, object)) {
        volume = volume + GetVolume(object,true)
      }
      if (HasInt(game.pov, "maxvolume")) {
        if (volume > game.pov.maxvolume) {
          continue = false
          if (HasString(game.pov, "containerfullmessage")) {
            message = prefix + game.pov.containerfullmessage
          }
          else {
            message = prefix + DynamicTemplate("FullInventory", object)
          }
        }
      }
      children = GetDirectChildren(game.pov)
      if (HasInt(game.pov, "maxobjects")) {
        if (game.pov.maxobjects > 0) {
          if (ListCount(children) >= game.pov.maxobjects) {
            continue = false
            if (HasString(game.pov, "containermaxobjects")) {
              message = prefix + game.pov.containermaxobjects
            }
            else {
              message = prefix + DynamicTemplate("MaxObjectsInInventory", object)
            }
          }
        }
      }
      if (continue = false) {
        msg (message)
      }
      else {
        found = true
        takemsg = object.takemsg
        switch (TypeOf(object, "take")) {
          case ("script") {
            if (ismultiple) {
              OutputTextNoBr (prefix)
            }
            do (object, "take")
            takemsg = ""
          }
          case ("boolean") {
            if (object.take = true) {
              object.parent = game.pov
              if (takemsg = null) {
                takemsg = DynamicTemplate("TakeSuccessful", object)
              }
            }
            else {
              found = false
            }
          }
          case ("string") {
            object.parent = game.pov
            takemsg = object.take
          }
          default {
            found = false
          }
        }
        if (not found and takemsg = null) {
          takemsg = DynamicTemplate("TakeUnsuccessful", object)
        }
        if (LengthOf(takemsg) > 0) {
          msg (prefix + takemsg)
        }
        if (HasScript(object, "ontake")) {
          do (object, "ontake")
        }
        if (found and GetBoolean (object, "scenery") and object.parent = game.pov) {
          object.scenery = false
        }
      }
    }
  ]]></function>
  <function name="DoDrop" parameters="object, ismultiple"><![CDATA[
    prefix = ""
    if (ismultiple) {
      prefix = GetDisplayAlias(object) + ": "
    }
    if (not ListContains(ScopeInventory(), object)) {
      msg (prefix + DynamicTemplate("NotCarrying", object))
    }
    else if (not ListContains(ScopeReachable(), object)) {
      msg (BlockingMessage(object, prefix))
    }
    else {
      found = true
      dropmsg = object.dropmsg
      if (HasObject(game.pov.parent, "dropdestination")) {
        destination = game.pov.parent.dropdestination
      }
      else {
        destination = game.pov.parent
      }
      switch (TypeOf(object, "drop")) {
        case ("script") {
          if (ismultiple) {
            OutputTextNoBr (prefix)
          }
          d = NewDictionary()
          dictionary add (d, "destination", destination)
          do (object, "drop", d)
          dropmsg = ""
        }
        case ("boolean") {
          if (object.drop = true) {
            object.parent = destination
            if (dropmsg = null) {
              dropmsg = DynamicTemplate("DropSuccessful", object)
            }
          }
          else {
            found = false
          }
        }
        case ("string") {
          object.parent = game.pov.parent
          dropmsg = object.drop
        }
        default {
          found = false
        }
      }
      if (not found and dropmsg = null) {
        dropmsg = DynamicTemplate("DropUnsuccessful", object)
      }
      if (LengthOf(dropmsg) > 0) {
        msg (prefix + dropmsg)
      }
      if (HasScript(object, "ondrop")) {
        do (object, "ondrop")
      }
    }
  ]]></function>
  <function name="CreateUseMenuList" parameters="object" type="objectlist">
    objectlist = NewObjectList()
    objectlist = ScopeReachableInventory()
    objectlist = ListCombine (objectlist, ScopeReachableNotHeld())
    excludelist = NewObjectList()
    list add (excludelist, game.pov)
    list add (excludelist, object)
    candidates = NewObjectList()
    candidates = ListExclude(RemoveSceneryObjects(objectlist), excludelist)
    return (candidates)
  </function>
  <function name="TryOpenClose" parameters="doopen, object">
    if (doopen) {
      action = "open"
      scriptaction = "openscript"
    }
    else {
      action = "close"
      scriptaction = "closescript"
    }
    if (not ListContains(ScopeReachable(), object)) {
      msg (BlockingMessage(object, ""))
    }
    else {
      found = false
      if (GetBoolean(object, action)) {
        if (doopen) {
          if (object.isopen) {
            msg (DynamicTemplate("AlreadyOpen", object))
          }
          else {
            if (HasScript(object, scriptaction)) {
              do (object, scriptaction)
            }
            else {
              OpenObject (object)
            }
          }
        }
        else {
          if (not object.isopen) {
            msg (DynamicTemplate("AlreadyClosed", object))
          }
          else {
            if (HasScript(object, scriptaction)) {
              do (object, scriptaction)
            }
            else {
              CloseObject (object)
            }
          }
        }
      }
      else {
        if (doopen) {
          msg (DynamicTemplate("CantOpen", object))
        }
        else {
          msg (DynamicTemplate("CantClose", object))
        }
      }
    }
  </function>
  <function name="OpenObject" parameters="object">
    if (HasString(object, "openmsg")) {
      msg (object.openmsg)
    }
    else {
      msg (DynamicTemplate("OpenSuccessful", object))
    }
    object.isopen = true
    ListObjectContents (object)
  </function>
  <function name="CloseObject" parameters="object">
    if (HasString(object, "closemsg")) {
      msg (object.closemsg)
    }
    else {
      msg (DynamicTemplate("CloseSuccessful", object))
    }
    object.isopen = false
  </function>
  <function name="CreateGiveMenuList" parameters="object" type="objectlist">
    objectlist = NewObjectList()
    objectlist = ScopeReachableInventory()
    objectlist = ListCombine (objectlist, ScopeReachableNotHeld())
    excludelist = NewObjectList()
    list add (excludelist, game.pov)
    list add (excludelist, object)
    candidates = NewObjectList()
    candidates = ListExclude(RemoveSceneryObjects(objectlist), excludelist)
    return (candidates)
  </function>
  <function name="HandleGiveTo" parameters="object1, object2">
    handled = false
    if (HasString(object2, "give")) {
      msg (object2.give)
      handled = true
    }
    else if (TypeOf(object2, "give") = "scriptdictionary") {
      if (DictionaryContains(object2.give, object1.name)) {
        parameters = NewObjectDictionary()
        dictionary add (parameters, "this", object2)
        dictionary add (parameters, "object", object1)
        invoke (ScriptDictionaryItem(object2.give, object1.name), parameters)
        handled = true
      }
      if (not handled) {
        if (HasScript(object2, "giveanything")) {
          // TO DO: Would be better to use a delegate for giveanything, but need to implement Editor support first
          parameters = NewObjectDictionary()
          dictionary add (parameters, "object", object1)
          do (object2, "giveanything", parameters)
          handled = true
        }
      }
    }
    if (not handled) {
      if (HasString(object1, "giveto")) {
        msg (object1.giveto)
        handled = true
      }
      else if (TypeOf(object1, "giveto") = "scriptdictionary") {
        if (DictionaryContains(object1.giveto, object2.name)) {
          parameters = NewObjectDictionary()
          dictionary add (parameters, "this", object1)
          dictionary add (parameters, "object", object2)
          invoke (ScriptDictionaryItem(object1.giveto, object2.name), parameters)
          handled = true
        }
        else {
          if (HasScript(object1, "givetoanything")) {
            // TO DO: Would be better to use a delegate for givetoanything, but need to implement Editor support first
            parameters = NewObjectDictionary()
            dictionary add (parameters, "object", object2)
            do (object1, "givetoanything", parameters)
            handled = true
          }
        }
      }
    }
    if (not handled) {
      msg (DynamicTemplate("DefaultGive", object2, object1))
    }
  </function>
  <function name="HandleUseOn" parameters="object1, object2">
    handled = false
    if (HasString(object2, "useon")) {
      msg (object2.useon)
      handled = true
    }
    else if (TypeOf(object2, "useon") = "scriptdictionary") {
      if (DictionaryContains(object2.useon, object1.name)) {
        parameters = NewObjectDictionary()
        dictionary add (parameters, "this", object2)
        dictionary add (parameters, "object", object1)
        invoke (ScriptDictionaryItem(object2.useon, object1.name), parameters)
        handled = true
      }
      else {
        if (HasScript(object2, "useanything")) {
          // TO DO: Would be better to use a delegate for useanything, but need to implement Editor support first
          parameters = NewObjectDictionary()
          dictionary add (parameters, "object", object1)
          do (object2, "useanything", parameters)
          handled = true
        }
      }
    }
    if (not handled) {
      if (HasString(object1, "selfuseon")) {
        msg (object1.selfuseon)
        handled = true
      }
      else if (TypeOf(object1, "selfuseon") = "scriptdictionary") {
        if (DictionaryContains(object1.selfuseon, object2.name)) {
          parameters = NewObjectDictionary()
          dictionary add (parameters, "this", object1)
          dictionary add (parameters, "object", object2)
          invoke (ScriptDictionaryItem(object1.selfuseon, object2.name), parameters)
          handled = true
        }
        else {
          if (HasScript(object1, "selfuseanything")) {
            // TO DO: Would be better to use a delegate for selfuseanything, but need to implement Editor support first
            parameters = NewObjectDictionary()
            dictionary add (parameters, "object", object2)
            do (object1, "selfuseanything", parameters)
            handled = true
          }
        }
      }
    }
    if (not handled) {
      msg (DynamicTemplate("DefaultUseOn", object2, object1))
    }
  </function>
  <function name="DoAskTell" parameters="object, text, property, defaultscript, defaulttemplate"><![CDATA[
    handled = false
    maxstrength = 0
    match = null
    text = LCase(text)
    if (TypeOf(object, property) = "scriptdictionary") {
      dictionary = GetAttribute(object, property)
      foreach (keywords, dictionary) {
        strength = GetKeywordsMatchStrength(LCase(keywords), text)
        if (strength >= maxstrength and strength>0) {
          match = ScriptDictionaryItem(dictionary, keywords)
          maxstrength = strength
        }
      }
      if (match <> null) {
        parameters = NewObjectDictionary()
        dictionary add (parameters, "this", object)
        invoke (match, parameters)
        handled = true
      }
    }
    if (not handled) {
      if (HasScript(object, defaultscript)) {
        d = NewDictionary()
        dictionary add (d, "text", text)
        do (object, defaultscript, d)
      }
      else {
        msg (DynamicTemplate(defaulttemplate, object))
      }
    }
  ]]></function>
  <function name="GetKeywordsMatchStrength" parameters="keywords, input" type="int">
    // Keywords is the subject. We split it into individual words, and then see how well
    // the words in the input match the keywords.
    keywordlist = Split(keywords, " ")
    inputlist = Split(input, " ")
    strength = 0
    foreach (word, inputlist) {
      foreach (keyword, keywordlist) {
        if (StartsWith(word, keyword)) {
          strength = strength + LengthOf(keyword)
        }
      }
    }
    return (strength)
  </function>
  <function name="UpdateTranscriptString" parameters="data">
    game.suppressturnscripts = true
    game.transcriptstring = game.transcriptstring + data
  </function>
  <function name="BlockingMessage" parameters="blocked, prefix" type="string">
    obj = GetBlockingObject(blocked)
    if (HasString(obj, "blockingmessage")) {
      return (obj.blockingmessage)
    }
    else {
      return (prefix + DynamicTemplate("ObjectNotOpen", obj))
    }
  </function>
  <function name="RandomChance" parameters="percentile" type="boolean"><![CDATA[
    return (GetRandomInt(1,100) <= percentile)
  ]]></function>
  <function name="SetObjectFlagOn" parameters="object, flag">
    set (object, flag, true)
  </function>
  <function name="SetObjectFlagOff" parameters="object, flag">
    set (object, flag, false)
  </function>
  <function name="IncreaseObjectCounter" parameters="object, counter">
    if (not HasInt(object, counter)) {
      set (object, counter, 0)
    }
    set (object, counter, GetInt(object, counter) + 1)
  </function>
  <function name="DecreaseObjectCounter" parameters="object, counter">
    if (not HasInt(object, counter)) {
      set (object, counter, 0)
    }
    set (object, counter, GetInt(object, counter) - 1)
  </function>
  <function name="IsSwitchedOn" parameters="object" type="boolean">
    return (GetBoolean(object, "switchedon"))
  </function>
  <function name="AddToInventory" parameters="object">
    object.parent = game.pov
  </function>
  <function name="MoveObject" parameters="object, parent">
    object.parent = parent
  </function>
  <function name="MoveObjectHere" parameters="object">
    object.parent = game.pov.parent
  </function>
  <function name="RemoveObject" parameters="object">
    object.parent = null
  </function>
  <function name="MakeObjectVisible" parameters="object">
    object.visible = true
  </function>
  <function name="MakeObjectInvisible" parameters="object">
    object.visible = false
  </function>
  <function name="MakeExitVisible" parameters="object">
    object.visible = true
  </function>
  <function name="MakeExitInvisible" parameters="object">
    object.visible = false
  </function>
  <function name="HelperOpenObject" parameters="object">
    object.isopen = true
  </function>
  <function name="HelperCloseObject" parameters="object">
    object.isopen = false
  </function>
  <function name="CloneObject" parameters="object" type="object">
    newobject = ShallowClone(object)
    if (not HasString(object, "alias")) {
      newobject.alias = object.name
    }
    if (not HasAttribute(object, "prototype")) {
      newobject.prototype = object
    }
    foreach (o, GetDirectChildren(object)) {
      o2 = CloneObject (o)
      MoveObject (o2, newobject)
    }
    return (newobject)
  </function>
  <function name="CloneObjectAndMove" parameters="object, newparent" type="object">
    newobject = CloneObject(object)
    newobject.parent = newparent
    return (newobject)
  </function>
  <function name="CloneObjectAndInitialise" parameters="object" type="object">
    newobject = CloneObject(object)
    if (HasScript(newobject, "_initialise_")) {
      do (newobject, "_initialise_")
    }
    return (newobject)
  </function>
  <function name="CloneObjectAndMoveHere" parameters="object" type="object">
    newobject = CloneObject(object)
    newobject.parent = game.pov.parent
    return (newobject)
  </function>
  <function name="LockExit" parameters="exit">
    exit.locked = true
  </function>
  <function name="UnlockExit" parameters="exit">
    exit.locked = false
  </function>
  <function name="SwitchOn" parameters="object">
    object.switchedon = true
  </function>
  <function name="SwitchOff" parameters="object">
    object.switchedon = false
  </function>
  <function name="SetDark" parameters="object">
    object.dark = true
  </function>
  <function name="SetLight" parameters="object">
    object.dark = false
  </function>
  <function name="SetObjectLightstrength" parameters="object, strength">
    if (LengthOf(strength) = 0) {
      object.lightsource = false
    }
    else {
      object.lightsource = true
    }
    object.lightstrength = strength
  </function>
  <function name="SetExitLightstrength" parameters="exit, strength">
    if (LengthOf(strength) = 0) {
      exit.lightsource = false
    }
    else {
      exit.lightsource = true
    }
    exit.lightstrength = strength
  </function>
  <function name="ChangePOV" parameters="object"><![CDATA[
    if (game.pov <> object) {
      game.pov = object
      if (game.gridmap) {
        JS.Grid_ClearAllLayers ()
        Grid_Redraw
      }
      OnEnterRoom (null)
    }
  ]]></function>
  <function name="RequestSave">
    // Deprecated
    request (RequestSave, "")
  </function>
  <function name="RequestSpeak" parameters="s">
    // Deprecated
    request (Speak, s)
  </function>
  <function name="ShowMenu" parameters="caption, options, allowCancel, callback"><![CDATA[
    outputsection = StartNewOutputSection()
    msg (caption)
    count = 0
    game.menuoptionskeys = NewStringList()
    foreach (option, options) {
      count = count + 1
      if (TypeOf(options) = "stringdictionary") {
        optionText = StringDictionaryItem(options, option)
        optiontag = option
        style = GetCurrentLinkTextFormat()
        list add (game.menuoptionskeys, option)
      }
      else if (TypeOf(option) = "string") {
        optionText = option
        optiontag = option
        style = GetCurrentLinkTextFormat()
        list add (game.menuoptionskeys, option)
      }
      else if (TypeOf(option) = "object") {
        optionText = GetDisplayAlias(option)
        optiontag = option.name
        colour = ""
        if (HasString(option, "linkcolour") and GetUIOption("UseGameColours") = "true") {
          colour = option.linkcolour
        }
        else {
          colour = GetLinkTextColour()
        }
        style = GetCurrentTextFormat(colour)
        list add (game.menuoptionskeys, option.name)
      }
      else {
        error ("ShowMenu cannot handle a " + TypeOf(option))
      }
      msg (count + ": <a class=\"cmdlink\" style=\"" + style + "\" onclick=\"ASLEvent('ShowMenuResponse','" + EscapeQuotes(optiontag) + "')\">" + optionText + "</a>")
    }
    EndOutputSection (outputsection)
    game.menuoptions = options
    game.menuallowcancel = allowCancel
    game.menucallback = callback
    game.menuoutputsection = outputsection
  ]]></function>
  <function name="ShowMenuResponse" parameters="option">
    if (game.menucallback = null) {
      error ("Unexpected menu response")
    }
    else {
      parameters = NewStringDictionary()
      dictionary add (parameters, "result", UnescapeQuotes(option))
      script = game.menucallback
      ClearMenu
      // Added by KV to handle the new FinishTurn setup in 580
      if (not GetBoolean(game, "disambiguating")) {
        game.runturnscripts = true
      }
      game.disambiguating = false
      invoke (script, parameters)
      FinishTurn
    }
  </function>
  <function name="EscapeQuotes" parameters="s" type="string">
    s = Replace(s, "\"", "@@@doublequote@@@")
    s = Replace(s, "\'", "@@@singlequote@@@")
    return (s)
  </function>
  <function name="UnescapeQuotes" parameters="s" type="string">
    s = Replace(s, "@@@doublequote@@@", "\"")
    s = Replace(s, "@@@singlequote@@@", "\'")
    return (s)
  </function>
  <function name="JSSafe" parameters="s" type="string"><![CDATA[
    s = Replace(s, "\"", "")
    s = Replace(s, "\'", "")
    s = Replace(s, " ", "")
    s = Replace(s, ".", "")
    s = Replace(s, ",", "")
    s = Replace(s, "!", "")
    s = Replace(s, "?", "")
    s = Replace(s, "-", "")
    s = Replace(s, "/", "")
    s = Replace(s, "(", "")
    s = Replace(s, ")", "")
    s = Replace(s, "$", "")
    s = Replace(s, "%", "")
    s = Replace(s, "&", "")
    s = Replace(s, "*", "")
    s = Replace(s, "@", "")
    return (s)
  ]]></function>
  <function name="HandleMenuTextResponse" parameters="input" type="boolean"><![CDATA[
    handled = false
    if (IsInt(input)) {
      number = ToInt(input)
      if (number > 0 and number <= ListCount(game.menuoptionskeys)) {
        handled = true
        ShowMenuResponse (StringListItem(game.menuoptionskeys, number - 1))
      }
    }
    return (handled)
  ]]></function>
  <function name="ClearMenu">
    HideOutputSection (game.menuoutputsection)
    game.menuoutputsection = null
    game.menuoptions = null
    game.menucallback = null
  </function>
  <function name="StartNewOutputSection" type="string">
    if (not HasInt(game, "lastoutputsection")) {
      game.lastoutputsection = 0
    }
    game.lastoutputsection = game.lastoutputsection + 1
    name = "section" + game.lastoutputsection
    JS.StartOutputSection (name)
    return (name)
  </function>
  <function name="EndOutputSection" parameters="name">
    JS.EndOutputSection (name)
  </function>
  <function name="HideOutputSection" parameters="name">
    JS.HideOutputSection (name)
  </function>
  <function name="StartTurnOutputSection">
    if (HasString(game, "currentturnoutputsection")) {
      game.lastturnoutputsection = game.currentturnoutputsection
      EndOutputSection (game.currentturnoutputsection)
    }
    game.currentturnoutputsection = StartNewOutputSection()
  </function>
  <function name="HidePreviousTurnOutput">
    if (HasString(game, "lastturnoutputsection")) {
      HideOutputSection (game.lastturnoutputsection)
    }
  </function>
  <function name="Ask" parameters="question, callback">
    options = NewStringList()
    list add (options, "Yes")
    list add (options, "No")
    game.askcallback = callback
    ShowMenu (question, options, false) {
      parameters = NewDictionary()
      if (result = "Yes") {
        boolresult = true
      }
      else {
        boolresult = false
      }
      dictionary add (parameters, "result", boolresult)
      callback = game.askcallback
      game.askcallback = null
      invoke (callback, parameters)
    }
  </function>
  <function name="AllKeysAvailable" parameters="object" type="boolean">
    if (HasObject(object, "key")) {
      if (not HasInt(object,"keycount")) {
        object.keycount = 1
        object.key1 = object.key
      }
      if (not HasObject(object, "key1")) {
        object.key1 = object.key
      }
    }
    for (x, 1, object.keycount) {
      keyname = "key" + ToString(x)
      if (HasObject(object, keyname)) {
        if (not ListContains(ScopeInventory(), GetAttribute(object, keyname))) {
          return (false)
        }
      }
    }
    return (true)
  </function>
  <function name="CreateBiExits" parameters="dir, from, to">
    create exit (dir, from, to)
    create exit (ReverseDirection(dir), to, from)
  </function>
  <function name="Equal" parameters="value1, value2" type="boolean">
    if (not TypeOf(value1) = TypeOf(value2)) {
      return (false)
    }
    if (not value1 = value2) {
      return (false)
    }
    return (true)
  </function>
  <function name="ReverseDirection" parameters="dir" type="string">
    list1 = Split("north;northeast;east;southeast;south;southwest;west;northwest;up;down;in;out", ";")
    list2 = Split("south;southwest;west;northwest;north;northeast;east;southeast;down;up;out;in", ";")
    n = IndexOf(list1, dir)
    if (not n = -1) {
      return (StringListItem(list2, n))
    }
    return (dir)
  </function>
  <function name="PadString" parameters="str, n, pad" type="string"><![CDATA[
    s = ""
    str = "" + str
    pad = "" + pad
    step = LengthOf(pad)
    if (step = 0) {
      error ("Zero length pad in PadString")
    }
    if (pad = " ") {
      pad = "&nbsp;"
    }
    for (i, 1, n - LengthOf(str), step) {
      s = s + pad
    }
    return (s + str)
  ]]></function>
  <function name="Decimalise" parameters="n, places" type="string"><![CDATA[
    negative = (n < 0)
    n = abs(n)
    if (places = 0) {
      return ("" + n)
    }
    factor = pow (10, places)
    pounds = floor(n / factor)
    pennies = n % factor
    result = pounds + "." + PadString(pennies, places, 0)
    if (negative) {
      result = "-" + result
    }
    return (result)
  ]]></function>
  <function name="DisplayNumber" parameters="n, control" type="string"><![CDATA[
    n = abs(n)
    regex = "^(?<before>\\D*)(?<padding>\\d+)(?<sep>\\D)(?<places>\\d*)(?<after>\\D*)$"
    if (not IsRegexMatch(regex, control, "DisplayNumber")) {
      error ("Unexpected format in DisplayNumber (" + control + "). Should be a number, followed by a single character separator, followed by a number.")
    }
    options = Populate(regex, control, "DisplayNumber")
    places = ToInt(StringDictionaryItem(options, "places"))
    padding = ToInt(StringDictionaryItem(options, "padding"))
    if (places > 0) {
      padding = padding + 1 + places
    }
    decimal = Replace(Decimalise(n, places), ".", StringDictionaryItem(options, "sep"))
    return (StringDictionaryItem(options, "before") + PadString(decimal, padding, 0) + StringDictionaryItem(options, "after"))
  ]]></function>
  <function name="DisplayMoney" parameters="n" type="string"><![CDATA[
    // Returns the given number formatted according to game.moneyformat
    if (not HasString(game, "moneyformat")) {
      error ("No format for money set in game.moneyformat.")
    }
    ary = Split(game.moneyformat, "!")
    if (ListCount(ary) = 2) {
      return (Replace(game.moneyformat, "!", "" + n))
    }
    else if (ListCount(ary) = 3) {
      negative = (n < 0)
      n = abs(n)
      options = StringListItem(ary, 1)
      showsign = StartsWith(options, "+")
      if (showsign) {
        options = Mid(options, 2)
      }
      number = DisplayNumber(n, options)
      if (negative) {
        number = "-" + number
      }
      else if (not n = 0 and showsign) {
        number = "+" + number
      }
      return (StringListItem(ary, 0) + number + StringListItem(ary, 2))
    }
    else if (ListCount(ary) = 4) {
      if (n < 0) {
        options = StringListItem(ary, 2)
      }
      else {
        options = StringListItem(ary, 1)
      }
      number = DisplayNumber(n, options)
      return (StringListItem(ary, 0) + number + StringListItem(ary, 3))
    }
    else {
      error ("game.moneyformat expected to have either 1, 2 or 3 exclamation marks.")
    }
  ]]></function>
  <function name="IndexOf" parameters="lst, item" type="int">
    for (i, 0, ListCount(lst) - 1) {
      x = ListItem(lst, i)
      if (x = item) {
        return (i)
      }
    }
    return (-1)
  </function>
  <function name="ObjectListToStringList" parameters="list, att" type="stringlist">
    l = NewStringList()
    foreach (o, list) {
      if (HasString(o, att)) {
        list add (l, GetString(o, att))
      }
    }
    return (l)
  </function>
  <function name="FilterByType" parameters="lst, t" type="objectlist">
    l = NewObjectList()
    foreach (o, lst) {
      if (DoesInherit(o, t)) {
        list add (l, o)
      }
    }
    return (l)
  </function>
  <function name="FilterByAttribute" parameters="lst, name, value" type="objectlist">
    if (not IsDefined("value")) {
      return (FilterByNotAttribute (lst, name, null))
    }
    l = NewObjectList()
    foreach (o, lst) {
      val = GetAttribute(o, name)
      if (Equal(val, value)) {
        list add (l, o)
      }
    }
    return (l)
  </function>
  <function name="FilterByNotAttribute" parameters="lst, name, value" type="objectlist">
    if (not IsDefined("value")) {
      return (FilterByAttribute (lst, name, null))
    }
    l = NewObjectList()
    foreach (o, lst) {
      val = GetAttribute(o, name)
      if (not Equal(val, value)) {
        list add (l, o)
      }
    }
    return (l)
  </function>
  <function name="ListCompact" parameters="lst" type="list">
    l = NewList()
    foreach (o, lst) {
      if (not Equal(o, null)) {
        if (IndexOf(l, o) = -1) {
          list add (l, o)
        }
      }
    }
    return (l)
  </function>
  <function name="ObjectListCompact" parameters="lst" type="objectlist">
    l = NewObjectList()
    foreach (o, lst) {
      if (not Equal(o, null)) {
        if (IndexOf(l, o) = -1) {
          list add (l, o)
        }
      }
    }
    return (l)
  </function>
  <function name="AllRooms" type="objectlist">
    return (FilterByAttribute(AllObjects(),"isroom",true))
  </function>
  <function name="DictionaryAdd" parameters="dict, key, val">
    if (dict = null or TypeOf(dict)="object") {
      error ("DictionaryAdd:  Dictionary does not exist!")
    }
    if (DictionaryContains(dict, key)) {
      dictionary remove (dict, key)
    }
    dictionary add (dict, key, val)
  </function>
  <function name="DictionaryRemove" parameters="dict, key">
    if (dict = null or TypeOf(dict)="object") {
      error ("DictionaryAdd:  Dictionary does not exist!")
    }
    if (DictionaryContains(dict, key)) {
      dictionary remove (dict, key)
    }
  </function>
  <function name="DbgLog" parameters="txt">
    if (GetBoolean(game,"debugging")) {
      Log ("DEBUGGING:  "+txt)
    }
  </function>
  <function name="DbgMsg" parameters="txt"><![CDATA[
    if (GetBoolean(game,"debugging")) {
      msg ("<br/><p style='color:blue;font-weight:bold;'>DEBUGGING:  "+txt+"</p><br/>")
    }
  ]]></function>
  <function name="DisableTranscript">
    game.notranscript = true
    JS.eval ("savingTranscript = false;")
  </function>
  <function name="DisableHtmlLog">
    game.nohtmllog = true
  </function>
  <function name="QuickParams" parameters="key1, value1, key2, value2, key3, value3" type="dictionary">
    d = NewDictionary()
    dictionary add (d, key1, value1)
    if (IsDefined("key2")) {
      dictionary add (d, key2, value2)
    }
    if (IsDefined("key3")) {
      dictionary add (d, key3, value3)
    }
    return (d)
  </function>
  <function name="HandleCommand" parameters="command, metadata"><![CDATA[
    handled = false
    if (game.menucallback <> null) {
      if (HandleMenuTextResponse(command)) {
        handled = true
      }
      else {
        if (game.menuallowcancel) {
          ClearMenu
        }
        else {
          handled = true
        }
      }
    }
    if (not handled) {
      StartTurnOutputSection
      if (StartsWith (command, "*")) {
        // Modified by KV to bypass turn scripts and turn counts, and to print "Noted."
        game.suppressturnscripts = true
        msg ("")
        msg (SafeXML (command))
        msg ("Noted.")
        // Added for Quest 5.8    - KV
        FinishTurn
      }
      else {
        shownlink = false
        if (game.echocommand) {
          if (metadata <> null and game.enablehyperlinks and game.echohyperlinks) {
            foreach (key, metadata) {
              if (EndsWith(command, key)) {
                objectname = StringDictionaryItem(metadata, key)
                object = GetObject(objectname)
                if (object <> null) {
                  msg ("")
                  msg ("&gt; " + Left(command, LengthOf(command) - LengthOf(key)) + "{object:" + object.name + "}")
                  shownlink = true
                }
              }
            }
          }
          if (not shownlink) {
            msg ("")
            OutputTextRaw ("&gt; " + SafeXML(command))
          }
        }
        if (game.command_newline) {
          msg ("")
        }
        game.pov.commandmetadata = metadata
        if (game.multiplecommands) {
          commands = Split(command, ".")
          if (ListCount(commands) = 1) {
            game.pov.commandqueue = null
            HandleSingleCommand (Trim(command))
          }
          else {
            game.pov.commandqueue = commands
            HandleNextCommandQueueItem
          }
        }
        else {
          game.pov.commandqueue = null
          HandleSingleCommand (Trim(command))
        }
      }
    }
  ]]></function>
  <function name="HandleNextCommandQueueItem"><![CDATA[
    if (TypeOf(game.pov, "commandqueue") = "stringlist") {
      queuelength = ListCount(game.pov.commandqueue)
      if (queuelength > 0) {
        thiscommand = Trim(StringListItem(game.pov.commandqueue, 0))
        if (queuelength = 1) {
          game.pov.commandqueue = null
        }
        else {
          newqueue = NewStringList()
          for (i, 1, queuelength - 1) {
            list add (newqueue, StringListItem(game.pov.commandqueue, i))
          }
          game.pov.commandqueue = newqueue
        }
        if (LengthOf(thiscommand) > 0) {
          HandleSingleCommand (thiscommand)
        }
        else {
          HandleNextCommandQueueItem
        }
      }
    }
  ]]></function>
  <function name="HandleSingleCommand" parameters="command"><![CDATA[
    if (LCase(command) = "again" or LCase(command) = "g") {
      // First handle AGAIN
      if (not game.pov.currentcommand = null) {
        HandleSingleCommand (game.pov.currentcommand)
      }
      else {
        msg ("There is nothing to repeat.")
      }
    }
    else {
      // Check through all commands for any that match
      candidates = NewObjectList()
      foreach (cmd, ScopeCommands()) {
        if (IsRegexMatch(cmd.pattern, command, cmd.name)) {
          list add (candidates, cmd)
        }
      }
      maxstrength = -1
      thiscommand = null
      // Pick the best match
      foreach (candidate, candidates) {
        strength = GetMatchStrength(candidate.pattern, command, candidate.name)
        // favour commands defined later, so an author can override a library command...
        if (strength >= maxstrength) {
          // ... except if the command defined later (candidate) has no parent, and the current best
          // match (thiscommand) does have a parent. We want to favour any commands defined in rooms
          // over global candidates.
          skip = false
          if (thiscommand <> null) {
            if (thiscommand.parent <> null and candidate.parent = null) {
              skip = true
            }
          }
          if (not skip) {
            thiscommand = candidate
            maxstrength = strength
          }
        }
      }
      if (thiscommand = null) {
        if (HasScript(game, "unresolvedcommandhandler")) {
          params = NewDictionary()
          dictionary add (params, "command", command)
          do (game, "unresolvedcommandhandler", params)
        }
        else {
          msg (Template("UnrecognisedCommand"))
        }
        HandleNextCommandQueueItem
      }
      else {
        varlist = Populate(thiscommand.pattern, command, thiscommand.name)
        HandleSingleCommandPattern (command, thiscommand, varlist)
      }
    }
  ]]></function>
  <function name="HandleSingleCommandPattern" parameters="command, thiscommand, varlist">
    // current command string
    game.pov.currentcommand = command
    // current command object
    game.pov.currentcommandpattern = thiscommand
    // string dictionary of variables, e.g. object1="book"; object2="table"
    game.pov.currentcommandvarlist = varlist
    // string list of variables left to resolve
    game.pov.currentcommandvarlistqueue = NewStringList()
    foreach (key, varlist) {
      list add (game.pov.currentcommandvarlistqueue, key)
    }
    // dictionary of resolved elements, e.g. object1=book_object; object2=table_object
    game.pov.currentcommandresolvedelements = NewDictionary()
    // list of resolved elements, e.g. book_object; table_object
    game.pov.currentcommandresolvedobjects = NewObjectList()
    game.pov.currentcommandunresolvedobject = null
    game.pov.currentcommandpendingvariable = null
    ResolveNextName
  </function>
  <function name="ResolveNextName"><![CDATA[
    resolvedall = false
    queuetype = TypeOf(game.pov, "currentcommandvarlistqueue")
    if (queuetype = "stringlist") {
      queuelength = ListCount(game.pov.currentcommandvarlistqueue)
      if (queuelength > 0) {
        // Pop next variable off the queue
        var = StringListItem(game.pov.currentcommandvarlistqueue, 0)
        if (queuelength = 1) {
          game.pov.currentcommandvarlistqueue = null
        }
        else {
          newqueue = NewStringList()
          for (i, 1, queuelength - 1) {
            list add (newqueue, StringListItem(game.pov.currentcommandvarlistqueue, i))
          }
          game.pov.currentcommandvarlistqueue = newqueue
        }
        // Resolve variable
        value = StringDictionaryItem(game.pov.currentcommandvarlist, var)
        if (value <> "") {
          result = null
          resolvinglist = false
          // This is to resolve issue 626
          if (StartsWith(var, "objectexit")) {
            result = ResolveName(var, value, "exit")
          }
          if (result = null) {
            if (StartsWith(var, "object")) {
              if (GetBoolean(game.pov.currentcommandpattern, "allow_all")) {
                scope = FilterByAttribute(GetScope("object", "", "object"), "scenery", false)
                game.pov.currentcommandpendingobjectscope = ListExclude(scope, FilterByAttribute(scope, "not_all", true))
                game.pov.currentcommandpendingvariable = var
                ResolveNameList (value, "object")
                resolvinglist = true
              }
              else if (HasScript(game.pov.currentcommandpattern, "multipleobjects")) {
                game.pov.currentcommandpendingobjectlist = NewObjectList()
                game.pov.currentcommandpendingvariable = var
                do (game.pov.currentcommandpattern, "multipleobjects")
                ResolveNameList (value, "object")
                resolvinglist = true
              }
              else {
                result = ResolveName(var, value, "object")
              }
            }
            else if (StartsWith(var, "exit")) {
              result = ResolveName(var, value, "exit")
            }
            else if (StartsWith(var, "text")) {
              result = StringDictionaryItem(game.pov.currentcommandvarlist, var)
            }
            else {
              error ("Unhandled command variable '" + var + "' - command variable names must begin with 'object', 'exit' or 'text'")
            }
          }
          // at this point, ResolveName has returned - either an object name, unresolved, or pending
          if (result = null) {
            if ((not resolvinglist) and LengthOf(GetString(game.pov, "currentcommandpendingvariable")) = 0) {
              UnresolvedCommand (value, var)
            }
          }
          else {
            AddToResolvedNames (var, result)
          }
        }
        else {
          ResolveNextName
        }
      }
      else {
        resolvedall = true
      }
    }
    else if (queuetype = "null") {
      resolvedall = true
    }
    else {
      error ("Invalid queue type")
    }
    if (resolvedall) {
      // All the objects have been resolved, so now we can actually do the command
      // TO DO: game.lastobjects should be game.pov.lastobjects
      game.lastobjects = game.pov.currentcommandresolvedobjects
      if (not DictionaryContains(game.pov.currentcommandresolvedelements, "multiple")) {
        dictionary add (game.pov.currentcommandresolvedelements, "multiple", false)
      }
      if (not GetBoolean(game.pov.currentcommandpattern, "isundo")) {
        if (LengthOf(game.pov.currentcommand) > 0) {
          start transaction (game.pov.currentcommand)
        }
      }
      if (not GetBoolean(game.pov.currentcommandpattern, "isoops")) {
        // TO DO: game.unresolved* should be game.pov.unresolved*
        game.unresolvedcommand = null
        game.unresolvedcommandvarlist = null
        game.unresolvedcommandkey = null
      }
      if (HasScript(game.pov.currentcommandpattern, "script")) {
        // This is the bit that actually runs the commands
        do (game.pov.currentcommandpattern, "script", game.pov.currentcommandresolvedelements)
      }
      //
      // Setting game.runturnscripts to true to run turn scripts after ShowMenu , show menu, ask, or Ask.
      // This works in conjuction with FinishTurn, which has also been modified as of Quest 5.8.
      // - KV, 2018/05/25
      game.runturnscripts = true
      FinishTurn
      HandleNextCommandQueueItem
    }
  ]]></function>
  <function name="AddToResolvedNames" parameters="var, result">
    if (TypeOf(result) = "object") {
      if (result.type = "object") {
        list add (game.pov.currentcommandresolvedobjects, result)
      }
    }
    else if (TypeOf(result) = "objectlist") {
      foreach (obj, result) {
        if (obj.type = "object") {
          list add (game.pov.currentcommandresolvedobjects, obj)
        }
      }
    }
    dictionary add (game.pov.currentcommandresolvedelements, var, result)
    ResolveNextName
  </function>
  <function name="ResolveName" parameters="variable, value, objtype" type="object"><![CDATA[
    found = false
    if (game.pov.commandmetadata <> null) {
      if (DictionaryContains(game.pov.commandmetadata, value)) {
        result = GetObject(StringDictionaryItem(game.pov.commandmetadata, value))
        if (result <> null) {
          if (ListContains(ScopeVisible(), result)) {
            found = true
            return (result)
          }
        }
      }
    }
    if (not found) {
      value = LCase(value)
      result = ResolveNameInternal(variable, value, objtype)
      if (result <> null) {
        return (result)
      }
      else {
        // TO DO: Check this behaviour. We only want to try ignoring prefixes if we have definitely got an unresolved name.
        foreach (prefix, game.parserignoreprefixes) {
          if (StartsWith(value, prefix + " ")) {
            result = ResolveNameInternal(variable, Mid(value, LengthOf(prefix) + 1), objtype)
          }
        }
        if (result = null and LengthOf(variable) = 0 and not GetBoolean(game.pov, "currentcommandmultiobjectpending")) {
          UnresolvedCommand (value, game.pov.currentcommandpendingvariable)
        }
        return (result)
      }
    }
  ]]></function>
  <function name="ResolveNameInternal" parameters="variable, value, objtype" type="object">
    game.pov.currentcommandmultiobjectpending = false
    scope = GetScope(variable, value, objtype)
    if (HasString(game.pov.currentcommandpattern, "scope")) {
      secondaryscope = ScopeVisible()
    }
    else {
      secondaryscope = null
    }
    return (ResolveNameFromList(variable, value, objtype, scope, secondaryscope))
  </function>
  <function name="ResolveNameFromList" parameters="variable, value, objtype, scope, secondaryscope" type="object"><![CDATA[
    value = Trim(LCase(value))
    fullmatches = NewObjectList()
    partialmatches = NewObjectList()
    foreach (obj, scope) {
      name = LCase(GetDisplayAlias(obj))
      CompareNames (name, value, obj, fullmatches, partialmatches)
      if (obj.alt <> null) {
        foreach (altname, obj.alt) {
          CompareNames (LCase(altname), value, obj, fullmatches, partialmatches)
        }
      }
    }
    // allow referring to objects from the previous command by gender or article
    if (objtype = "object" and game.lastobjects <> null) {
      foreach (obj, game.lastobjects) {
        CompareNames (LCase(obj.article), value, obj, fullmatches, partialmatches)
        CompareNames (LCase(obj.gender), value, obj, fullmatches, partialmatches)
      }
    }
    // Also check the secondary scope, but only if we have not found anything yet
    if (ListCount(fullmatches) = 0 and ListCount(partialmatches) = 0 and not secondaryscope = null) {
      foreach (obj, secondaryscope) {
        name = LCase(GetDisplayAlias(obj))
        CompareNames (name, value, obj, fullmatches, partialmatches)
        if (obj.alt <> null) {
          foreach (altname, obj.alt) {
            CompareNames (LCase(altname), value, obj, fullmatches, partialmatches)
          }
        }
      }
    }
    if (ListCount(fullmatches) = 1) {
      return (ListItem(fullmatches, 0))
    }
    else if (ListCount(fullmatches) = 0 and ListCount(partialmatches) = 1) {
      return (ListItem(partialmatches, 0))
    }
    else if (ListCount(fullmatches) + ListCount(partialmatches) = 0) {
      return (null)
    }
    else {
      // Added this line to resolve issue with new FinishTurn setup in 580
      game.disambiguating = true
      candidates = ListCompact(ListCombine(fullmatches, partialmatches))
      if (LengthOf(variable) > 0) {
        // single object command, so after showing the menu, add the object to game.pov.currentcommandresolvedelements
        game.pov.currentcommandpendingvariable = variable
        ShowMenu (DynamicTemplate("DisambiguateMenu", value), candidates, true) {
          varname = game.pov.currentcommandpendingvariable
          game.pov.currentcommandpendingvariable = null
          if (result <> null) {
            AddToResolvedNames (varname, GetObject(result))
          }
        }
      }
      else {
        // multi-object command, so after showing the menu, add the object to the list
        game.pov.currentcommandmultiobjectpending = true
        ShowMenu (DynamicTemplate("DisambiguateMenu", value), candidates, true) {
          if (result <> null) {
            list add (game.pov.currentcommandpendingobjectlist, GetObject(result))
            ResolveNextNameListItem
          }
        }
      }
      return (null)
    }
  ]]></function>
  <function name="ResolveNameList" parameters="value, objtype">
    game.pov.currentcommandpendingobjectlist = NewObjectList()
    game.pov.currentcommandpendingobjectlistunresolved = NewStringList()
    game.pov.currentcommandpendingobjecttype = objtype
    inputlist = Split(value, ",")
    foreach (inputbase, inputlist) {
      inputlist2 = Split(inputbase, " " + Template("And") + " ")
      foreach (input, inputlist2) {
        list add (game.pov.currentcommandpendingobjectlistunresolved, input)
      }
    }
    ResolveNextNameListItem
  </function>
  <function name="ResolveNextNameListItem"><![CDATA[
    resolvedall = false
    if (TypeOf(game.pov, "currentcommandpendingobjectlistunresolved") = "stringlist") {
      queuelength = ListCount(game.pov.currentcommandpendingobjectlistunresolved)
      if (queuelength > 0) {
        thisitem = Trim(StringListItem(game.pov.currentcommandpendingobjectlistunresolved, 0))
        if (queuelength = 1) {
          game.pov.currentcommandpendingobjectlistunresolved = null
        }
        else {
          newqueue = NewStringList()
          for (i, 1, queuelength - 1) {
            list add (newqueue, StringListItem(game.pov.currentcommandpendingobjectlistunresolved, i))
          }
          game.pov.currentcommandpendingobjectlistunresolved = newqueue
        }
        ResolveNameListItem (Trim(thisitem))
      }
      else {
        resolvedall = true
      }
    }
    else {
      resolvedall = true
    }
    if (resolvedall) {
      ResolveNameListItemFinished (game.pov.currentcommandpendingobjectlist)
    }
  ]]></function>
  <function name="ResolveNameListItem" parameters="value"><![CDATA[
    if (ListContains(game.allobjects, value)) {
      // value is "all"
      if (not DictionaryContains(game.pov.currentcommandresolvedelements, "multiple")) {
        dictionary add (game.pov.currentcommandresolvedelements, "multiple", true)
      }
      ResolveNameListItemFinished (game.pov.currentcommandpendingobjectscope)
    }
    else {
      object = ResolveName("", value, game.pov.currentcommandpendingobjecttype)
      if (object <> null) {
        if (not ListContains(game.pov.currentcommandpendingobjectlist, object)) {
          list add (game.pov.currentcommandpendingobjectlist, object)
        }
        ResolveNextNameListItem
      }
    }
  ]]></function>
  <function name="ResolveNameListItemFinished" parameters="result"><![CDATA[
    if (ListCount(result) > 1) {
      if (not DictionaryContains(game.pov.currentcommandresolvedelements, "multiple")) {
        dictionary add (game.pov.currentcommandresolvedelements, "multiple", true)
      }
    }
    AddToResolvedNames (game.pov.currentcommandpendingvariable, result)
  ]]></function>
  <function name="UnresolvedCommand" parameters="objectname, varname"><![CDATA[
    // TO DO: Update names below, we don't need these two variables
    unresolvedobject = objectname
    unresolvedkey = varname
    if (HasString(game.pov.currentcommandpattern, "unresolved")) {
      if (ListCount(game.pov.currentcommandvarlist) > 1) {
        msg (game.pov.currentcommandpattern.unresolved + " (" + unresolvedobject + ")")
      }
      else {
        msg (game.pov.currentcommandpattern.unresolved)
      }
    }
    else {
      if (ListCount(game.pov.currentcommandvarlist) > 1) {
        msg (Template("UnresolvedObject") + " (" + unresolvedobject + ")")
      }
      else {
        msg (Template("UnresolvedObject"))
      }
    }
    game.unresolvedcommand = game.pov.currentcommandpattern
    game.unresolvedcommandvarlist = game.pov.currentcommandvarlist
    game.unresolvedcommandkey = unresolvedkey
  ]]></function>
  <function name="HandleMultiVerb" parameters="object, property, object2, default">
    dictionary = GetAttribute(object, property)
    if (DictionaryContains(dictionary, object2.name)) {
      parameters = NewDictionary()
      dictionary add (parameters, "this", object)
      dictionary add (parameters, "object", object2)
      invoke (ScriptDictionaryItem(dictionary, object2.name), parameters)
    }
    else {
      parameters = NewDictionary()
      dictionary add (parameters, "this", object)
      dictionary add (parameters, "object", object2)
      if (DictionaryContains(dictionary, "default")) {
        invoke (ScriptDictionaryItem(dictionary, "default"), parameters)
      }
      else {
        msg (default)
      }
    }
  </function>
  <function name="GetScope" parameters="variable, value, objtype" type="objectlist"><![CDATA[
    items = NewObjectList()
    if (HasString(game.pov.currentcommandpattern, "scope")) {
      scoping = GetScoping(game.pov.currentcommandpattern.scope, variable)
      foreach (partscope, Split(scoping, ";")) {
        switch (partscope) {
          case ("inventory") {
            items = ListCombine(items, ScopeInventory())
          }
          case ("notheld", "room") {
            items = ListCombine(items, ScopeVisibleNotHeld()) - game.pov
          }
          case ("all") {
            items = ListCombine(items, ScopeVisible()) - game.pov
          }
          case ("container") {
            items = ListCombine(items, FilterByType(ScopeVisible(), "container_base"))
          }
          case ("contents") {
            foreach (cont, FilterByType(ScopeVisible(), "container_base")) {
              items = ListCombine(items, GetAllChildObjects(cont))
            }
          }
          case ("world") {
            items = ListCombine(items, AllObjects())
          }
          case ("none") {
          }
          default {
            // The command's "scope" can be the name of an object, or an attribute of the player's parent
            obj = GetObject(partscope)
            if (not obj = null) {
              items = ListCombine(items, GetAllChildObjects(obj))
            }
            if (HasObject(game.pov.parent, partscope)) {
              obj = GetAttribute(game.pov.parent, partscope)
              items = ListCombine(items, GetAllChildObjects(obj))
            }
            else if (HasAttribute(game.pov.parent, partscope)) {
              attr = GetAttribute(game.pov.parent, partscope)
              if (TypeOf(attr) = "objectlist") {
                items = ListCombine (items, attr)
              }
            }
            else if (HasAttribute(game.pov, partscope)) {
              attr = GetAttribute(game.pov, partscope)
              if (TypeOf(attr) = "objectlist") {
                items = ListCombine (items, attr)
              }
            }
          }
        }
      }
    }
    else if (objtype = "object") {
      items = ScopeVisible()
    }
    else if (objtype = "exit") {
      items = ScopeExits()
    }
    else {
      // Should never get here!
      // CHANGE: Should still never get here, but we don't return null.
      // If we get here somehow, trust user's scripts to define scope.
    }
    items = ObjectListCompact(items)
    // CHANGE: Run the script 'changecommandscope' (if it exists) for the game object, the player's room and
    // containing rooms, and the current command. This allows the user to change command scope on a per-location
    // or per-command basis
    // This script gets an "items" list parameter, like `scopebackdrop` script does; but also has parameters
    // 'command', 'variable', and 'objtype', so the user can adjust their script to give different item lists
    // for different commands, or different variables within a command.
    objectswithscripts = NewObjectList()
    if (HasScript(game.pov.currentcommandpattern, "changecommandscope")) {
      list add (objectswithscripts, game.pov.currentcommandpattern)
    }
    room = game.pov
    while (not room = null) {
      if (HasScript(room, "changecommandscope")) {
        list add (objectswithscripts, room)
      }
      room = room.parent
    }
    if (HasScript(game, "changecommandscope")) {
      list add (objectswithscripts, game)
    }
    if (ListCount(objectswithscripts) > 0) {
      params = NewDictionary()
      dictionary add (params, "items", items)
      dictionary add (params, "command", game.pov.currentcommandpattern)
      dictionary add (params, "variable", variable)
      dictionary add (params, "objtype", objtype)
      dictionary add (params, "matched", game.pov.currentcommandresolvedelements)
      foreach (o, objectswithscripts) {
        do (o, "changecommandscope", params)
      }
      items = ObjectListCompact(items)
    }
    return (items)
  ]]></function>
  <function name="GetScoping" parameters="scopestring, variable" type="string">
    lst = Split(scopestring, "|")
    if (ListCount(lst) = 1) {
      return (scopestring)
    }
    foreach (s, lst) {
      if (StartsWith(s, variable + "=")) {
        return (Mid(s, LengthOf(variable) + 2))
      }
    }
    return ("all")
  </function>
  <function name="CompareNames" parameters="name, value, obj, fullmatches, partialmatches"><![CDATA[
    if (name = value) {
      if (not ListContains(fullmatches, obj)) {
        list add (fullmatches, obj)
      }
    }
    else {
      if (StartsWith(name, value)) {
        if (not ListContains(partialmatches, obj)) {
          list add (partialmatches, obj)
        }
      }
      else {
        // check if input matches the start of any word in the name
        if (Instr(name, " " + value) > 0) {
          if (not ListContains(partialmatches, obj)) {
            list add (partialmatches, obj)
          }
        }
      }
    }
  ]]></function>
  <function name="GenerateMenuChoices" parameters="dictionary, objects">
    msg ("WARNING: GenerateMenuChoices is deprecated as ShowMenu can handle lists with objects")
    foreach (obj, objects) {
      if (not DictionaryContains(dictionary, obj.name)) {
        dictionary add (dictionary, obj.name, GetDisplayAlias(obj))
      }
    }
  </function>
  <function name="GetPlacesObjectsList" type="objectlist">
    return (ListExclude(ScopeVisibleNotHeldNotScenery(), game.pov))
  </function>
  <function name="GetExitsList" type="objectlist">
    return (RemoveLookOnlyExits(RemoveSceneryObjects(ScopeExits())))
  </function>
  <function name="ScopeInventory" type="objectlist">
    result = NewObjectList()
    foreach (obj, GetAllChildObjects(game.pov)) {
      if (ContainsVisible(game.pov, obj)) {
        list add (result, obj)
      }
    }
    return (result)
  </function>
  <function name="ScopeReachableInventory" type="objectlist">
    result = NewObjectList()
    foreach (obj, GetAllChildObjects(game.pov)) {
      if (ContainsReachable(game.pov, obj)) {
        list add (result, obj)
      }
    }
    return (result)
  </function>
  <function name="ScopeVisibleNotHeld" type="objectlist">
    return (ScopeVisibleNotHeldForRoom(game.pov.parent))
  </function>
  <function name="ScopeVisibleNotHeldForRoom" parameters="room" type="objectlist">
    if (room = game.pov.parent) {
      result = ListCombine(ScopeReachableNotHeldForRoom(room), ScopeVisibleNotReachableForRoom(room))
      list add (result, game.pov)
      return (result)
    }
    else {
      return (ListCombine(ScopeReachableNotHeldForRoom(room), ScopeVisibleNotReachableForRoom(room)))
    }
  </function>
  <function name="ScopeVisibleNotHeldNotScenery" type="objectlist">
    return (ScopeVisibleNotHeldNotSceneryForRoom(game.pov.parent))
  </function>
  <function name="ScopeVisibleNotHeldNotSceneryForRoom" parameters="room" type="objectlist">
    return (RemoveSceneryObjects(ScopeVisibleNotHeldForRoom(room)))
  </function>
  <function name="ScopeReachable" type="objectlist">
    return (ScopeReachableForRoom(game.pov.parent))
  </function>
  <function name="ScopeReachableForRoom" parameters="room" type="objectlist">
    if (room = game.pov.parent) {
      result = ListCombine(ScopeReachableNotHeldForRoom(room), ScopeReachableInventory())
      list add (result, game.pov)
    }
    else {
      result = ScopeReachableNotHeldForRoom(room)
    }
    return (result)
  </function>
  <function name="ScopeVisibleNotReachable" type="objectlist">
    return (ScopeVisibleNotReachableForRoom(game.pov.parent))
  </function>
  <function name="ScopeVisibleNotReachableForRoom" parameters="room" type="objectlist">
    result = NewObjectList()
    exclude = ScopeReachableForRoom(room)
    list add (exclude, game.pov)
    newParent = GetNonTransparentParent(room)
    foreach (obj, GetAllChildObjects(newParent)) {
      if (ContainsVisible(newParent, obj) and not ListContains(exclude, obj)) {
        list add (result, obj)
      }
    }
    return (result)
  </function>
  <function name="GetNonTransparentParent" parameters="room" type="object">
    if (GetBoolean(room, "transparent")) {
      if (room.parent = null) {
        return (room)
      }
      else {
        return (GetNonTransparentParent(room.parent))
      }
    }
    else {
      return (room)
    }
  </function>
  <function name="ScopeReachableNotHeld" type="objectlist">
    return (ScopeReachableNotHeldForRoom(game.pov.parent))
  </function>
  <function name="ScopeVisibleLightsource" parameters="lightstrength" type="objectlist">
    result = ScopeVisible()
    lightobjects = NewObjectList()
    foreach (obj, result) {
      if (GetBoolean(obj, "lightsource") and GetString(obj, "lightstrength") = lightstrength) {
        list add (lightobjects, obj)
      }
    }
    exits = ScopeExits()
    foreach (obj, exits) {
      if (GetBoolean(obj, "lightsource") and GetString(obj, "lightstrength") = lightstrength) {
        list add (lightobjects, obj)
      }
    }
    return (lightobjects)
  </function>
  <function name="ScopeReachableNotHeldForRoom" parameters="room" type="objectlist"><![CDATA[
    result = NewObjectList()
    foreach (obj, GetAllChildObjects(room)) {
      if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
        list add (result, obj)
      }
    }
    if (HasScript(game, "scopebackdrop")) {
      dict = NewDictionary()
      dictionary add (dict, "items", result)
      do (game, "scopebackdrop", dict)
    }
    return (result)
  ]]></function>
  <function name="ScopeVisible" type="objectlist">
    return (ScopeVisibleForRoom(game.pov.parent))
  </function>
  <function name="ScopeVisibleForRoom" parameters="room" type="objectlist">
    if (room = game.pov.parent) {
      return (ListCombine(ScopeVisibleNotHeldForRoom(room), ScopeInventory()))
    }
    else {
      return (ScopeVisibleNotHeldForRoom(room))
    }
  </function>
  <function name="ScopeExits" type="objectlist">
    return (ScopeExitsForRoom(game.pov.parent))
  </function>
  <function name="ScopeExitsForRoom" parameters="room" type="objectlist">
    result = NewObjectList()
    foreach (exit, AllExits()) {
      if (exit.parent = room) {
        if (exit.visible) {
          if (GetBoolean(room, "darklevel")) {
            if (GetBoolean(exit, "lightsource")) {
              list add (result, exit)
            }
          }
          else {
            list add (result, exit)
          }
        }
      }
    }
    return (result)
  </function>
  <function name="ScopeUnlockedExitsForRoom" parameters="room" type="objectlist">
    result = NewObjectList()
    foreach (exit, AllExits()) {
      if (exit.parent = room) {
        if (exit.visible and not exit.locked) {
          if (GetBoolean(room, "darklevel")) {
            if (GetBoolean(exit, "lightsource")) {
              list add (result, exit)
            }
          }
          else {
            list add (result, exit)
          }
        }
      }
    }
    return (result)
  </function>
  <function name="ScopeCommands" type="objectlist">
    result = NewObjectList()
    foreach (command, AllCommands()) {
      if (command.parent = null or command.parent = game.pov.parent) {
        list add (result, command)
      }
      if (not game.pov.parent.parent = null) {
        if (command.parent = game.pov.parent.parent) {
          list add (result, command)
        }
      }
    }
    return (result)
  </function>
  <function name="GetBlockingObject" parameters="obj" type="object">
    result = null
    foreach (obj, ListParents(obj)) {
      if (result = null and not CanReachThrough(obj)) {
        result = obj
      }
    }
    return (result)
  </function>
  <function name="ListParents" parameters="obj" type="objectlist"><![CDATA[
    result = NewObjectList()
    if (obj.parent <> null) {
      parent_as_list = NewObjectList()
      list add (parent_as_list, obj.parent)
      result = ListCombine(parent_as_list, ListParents(obj.parent))
    }
    return (result)
  ]]></function>
  <function name="ContainsVisible" parameters="parentObj, searchObj" type="boolean">
    return (ContainsAccessible(parentObj, searchObj, false))
  </function>
  <function name="ContainsReachable" parameters="parentObj, searchObj" type="boolean">
    return (ContainsAccessible(parentObj, searchObj, true))
  </function>
  <function name="ContainsAccessible" parameters="parentObj, searchObj, onlyReachable" type="boolean">
    if (not HasObject(searchObj, "parent")) {
      return (false)
    }
    else if (not searchObj.visible) {
      return (false)
    }
    else if (GetBoolean(parentObj, "darklevel") and not GetBoolean(searchObj, "lightsource")) {
      return (false)
    }
    else {
      if (searchObj.parent = null) {
        return (false)
      }
      else if (searchObj.parent = parentObj) {
        return (true)
      }
      else {
        if (onlyReachable) {
          canAdd = CanReachThrough(searchObj.parent)
        }
        else {
          canAdd = CanSeeThrough(searchObj.parent)
        }
        if (canAdd) {
          return (ContainsAccessible(parentObj, searchObj.parent, onlyReachable))
        }
        else {
          return (false)
        }
      }
    }
  </function>
  <function name="GetVolume" parameters="obj, allinclusive" type="int">
    result = 0
    foreach (object, GetAllChildObjects ( obj )) {
      if (HasInt(object, "volume")) {
        result = result + object.volume
      }
    }
    if (allinclusive and HasInt(obj, "volume")) {
      result = result + obj.volume
    }
    return (result)
  </function>
  <function name="CanSeeThrough" parameters="obj" type="boolean">
    return ((GetBoolean(obj, "transparent") or CanReachThrough(obj)) and not GetBoolean(obj, "hidechildren"))
  </function>
  <function name="CanReachThrough" parameters="obj" type="boolean">
    return (GetBoolean(obj, "isopen") and not GetBoolean(obj, "hidechildren"))
  </function>
  <function name="Got" parameters="obj" type="boolean">
    return (ListContains(ScopeInventory(), obj))
  </function>
  <function name="UpdateObjectLinks">
    if (game.enablehyperlinks) {
      data = NewStringDictionary()
      foreach (object, ScopeVisible()) {
        dictionary add (data, object.name, Join(GetDisplayVerbs(object), "/"))
      }
      JS.updateObjectLinks (data)
      exits = NewStringList()
      foreach (exit, ScopeExits()) {
        list add (exits, exit.name)
      }
      JS.updateExitLinks (exits)
      commands = NewStringList()
      foreach (cmd, ScopeCommands()) {
        list add (commands, cmd.name)
      }
      JS.updateCommandLinks (commands)
    }
  </function>
  <function name="SecondaryScopeReachableForRoom" parameters="room" type="objectlist">
    return (NewObjectList())
  </function>
  <function name="ShowRoomDescription"><![CDATA[
    isDark = CheckDarkness()
    if (isDark) {
      descriptionfield = "darkroomdescription"
    }
    else {
      descriptionfield = "description"
    }
    if (game.autodescription) {
      desc = ""
      for (i, 1, 4) {
        if (i = game.autodescription_youarein) {
          if (game.autodescription_youarein_useprefix) {
            youarein = game.pov.parent.descprefix
            desc = AddDescriptionLine (desc, youarein + " " + GetDisplayName(game.pov.parent) + ".")
          }
          else {
            desc = AddDescriptionLine (desc, "<b>" + CapFirst(GetDisplayName(game.pov.parent)) + "</b>")
          }
          if (game.autodescription_youarein_newline) {
            msg (desc + "<br/>")
            desc = ""
          }
        }
        if (i = game.autodescription_youcansee) {
          objects = FormatObjectList(game.pov.parent.objectslistprefix, GetNonTransparentParent(game.pov.parent), Template("And"), ".")
          desc = AddDescriptionLine(desc, objects)
          if (game.autodescription_youcansee_newline) {
            msg (desc + "<br/>")
            desc = ""
          }
        }
        if (i = game.autodescription_youcango) {
          exits = FormatExitList(game.pov.parent.exitslistprefix, GetExitsList(), Template("Or"), ".")
          desc = AddDescriptionLine(desc, exits)
          if (game.autodescription_youcango_newline) {
            msg (desc + "<br/>")
            desc = ""
          }
        }
        if (i = game.autodescription_description) {
          if (HasScript(game.pov.parent, descriptionfield)) {
            if (LengthOf(desc) > 0) {
              msg (desc)
              desc = ""
            }
            do (game.pov.parent, descriptionfield)
            if (game.autodescription_description_newline) {
              msg ("")
            }
          }
          else {
            desc = AddDescriptionLine(desc, GetRoomDescription())
            if (game.autodescription_description_newline) {
              msg (desc + "<br/>")
              desc = ""
            }
          }
        }
      }
      if (LengthOf(desc) > 0) {
        msg (desc)
      }
    }
    else {
      if (HasScript(game.pov.parent, descriptionfield)) {
        do (game.pov.parent, descriptionfield)
      }
      else {
        fulldesc = GetRoomDescription()
        if (LengthOf(fulldesc) > 0) {
          msg (fulldesc)
        }
      }
    }
  ]]></function>
  <function name="AddDescriptionLine" parameters="desc, line" type="string"><![CDATA[
    if (LengthOf(line) > 0) {
      if (LengthOf(desc) > 0) {
        msg (desc)
        desc = ""
      }
      desc = desc + line
    }
    return (desc)
  ]]></function>
  <function name="GetRoomDescription" type="string"><![CDATA[
    fulldesc = ""
    if (CheckDarkness()) {
      if (HasString(game.pov.parent, "darkroomdescription")) {
        if (LengthOf(game.pov.parent.darkroomdescription) > 0) {
          fulldesc = game.pov.parent.darkroomdescription
        }
      }
      // Added by The Pixie to correct what appears to be a bug
      if (fulldesc = "") {
        fulldesc = DynamicTemplate("LookAtDarkness", game.pov.parent)
      }
    }
    else {
      if (HasString(game.pov.parent, "description")) {
        if (LengthOf(game.pov.parent.description) > 0) {
          fulldesc = game.pov.parent.description
        }
      }
    }
    if (game.appendobjectdescription) {
      foreach (val, ScopeVisibleNotHeld()) {
        if (HasString(val, "inroomdescription")) {
          if (LengthOf(val.inroomdescription) > 0 and val <> game.pov) {
            fulldesc = fulldesc + " " + val.inroomdescription
          }
        }
      }
    }
    return (Trim(fulldesc))
  ]]></function>
  <function name="OnEnterRoom" parameters="oldRoom"><![CDATA[
    game.displayroomdescriptiononstart = false
    if (IsDefined("oldRoom")) {
      if (oldRoom <> null) {
        if (game.clearscreenonroomenter) {
          ClearScreen
          if (not game.currentexitmessage = null) {
            msg (game.currentexitmessage)
            game.currentexitmessage = null
          }
        }
        if (HasScript(oldRoom, "onexit")) {
          do (oldRoom, "onexit")
        }
      }
    }
    on ready {
      if ((not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "beforefirstenter")) {
        do (game.pov.parent, "beforefirstenter")
      }
      on ready {
        if (HasScript(game.pov.parent, "beforeenter")) {
          do (game.pov.parent, "beforeenter")
        }
        on ready {
          if (game.gridmap) {
            Grid_CalculateMapCoordinates (game.pov.parent, game.pov)
            Grid_DrawPlayerInRoom (game.pov.parent)
          }
          if (IsDefined("oldRoom")) {
            if (oldRoom <> null and game.changeroom_newline and not game.command_newline) {
              msg ("")
            }
          }
          JS.updateLocation (CapFirst(GetDisplayName(game.pov.parent)))
          roomFrameExists = false
          if (HasString(game.pov.parent, "picture")) {
            if (LengthOf(game.pov.parent.picture) > 0) {
              roomFrameExists = true
              SetFramePicture (game.pov.parent.picture)
            }
          }
          if (game.clearframe and not roomFrameExists) {
            ClearFramePicture
          }
          if (game.showdescriptiononenter) {
            ShowRoomDescription
          }
          if (HasScript( game, "roomenter")) {
            do (game, "roomenter")
          }
          on ready {
            if ((not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "firstenter")) {
              do (game.pov.parent, "firstenter")
            }
            on ready {
              if (HasScript(game.pov.parent, "enter")) {
                do (game.pov.parent, "enter")
              }
            }
            set (game.pov.parent, "visited", true)
          }
        }
      }
    }
  ]]></function>
  <function name="FormatObjectList" parameters="preList, parent, preFinal, postList" type="string"><![CDATA[
    result = ""
    count = 0
    list = RemoveSceneryObjects(GetDirectChildren(parent))
    if (CheckDarkness()) {
      list = RemoveDarkObjects(list)
    }
    listLength = ListCount(list)
    foreach (item, list) {
      if (LengthOf(result) = 0) {
        result = preList + " "
      }
      result = result + GetDisplayNameLink(item, "object")
      if (CanSeeThrough(item)) {
        result = result + FormatObjectList(" (" + item.contentsprefix, item, preFinal, ")")
      }
      count = count + 1
      if (count = listLength - 1) {
        result = result + " " + preFinal + " "
      }
      else if (count < listLength) {
        result = result + ", "
      }
      else {
        result = result + postList
      }
    }
    return (result)
  ]]></function>
  <function name="RemoveSceneryObjects" parameters="list" type="objectlist"><![CDATA[
    result = NewObjectList()
    foreach (obj, list) {
      if (not obj.scenery and obj <> game.pov and obj.visible) {
        list add (result, obj)
      }
    }
    return (result)
  ]]></function>
  <function name="RemoveLookOnlyExits" parameters="list" type="objectlist">
    result = NewObjectList()
    foreach (obj, list) {
      if (not obj.lookonly) {
        list add (result, obj)
      }
    }
    return (result)
  </function>
  <function name="RemoveDarkObjects" parameters="list" type="objectlist">
    result = NewObjectList()
    foreach (obj, list) {
      if (GetBoolean(obj, "lightsource") or obj.parent = game.pov) {
        list add (result, obj)
      }
    }
    return (result)
  </function>
  <function name="FormatExitList" parameters="preList, list, preFinal, postList" type="string"><![CDATA[
    result = ""
    listLength = ListCount(list)
    if (listLength > 0) {
      count = 0
      result = preList + " "
      foreach (item, list) {
        result = result + GetDisplayNameLink(item, "exit")
        count = count + 1
        if (count = listLength - 1) {
          result = result + " " + preFinal + " "
        }
        else if (count < listLength) {
          result = result + ", "
        }
      }
      result = result + postList
    }
    return (result)
  ]]></function>
  <function name="GetDisplayAlias" parameters="obj" type="string">
    if (HasString(obj, "alias")) {
      result = obj.alias
    }
    else {
      result = obj.name
    }
    return (result)
  </function>
  <function name="GetDisplayName" parameters="obj" type="string">
    return (GetDisplayNameLink(obj, ""))
  </function>
  <function name="GetDisplayNameLink" parameters="obj, type" type="string"><![CDATA[
    verbs = GetDisplayVerbs(obj)
    if (verbs <> null) {
      verbCount = ListCount(verbs)
    }
    else {
      verbCount = 0
    }
    if (type = "exit" and verbCount = 1) {
      if (not game.enablehyperlinks) {
        result = GetDisplayAlias(obj)
      }
      else {
        result = "{exit:" + obj.name + "}"
      }
    }
    else if (type = "") {
      result = GetDisplayAlias(obj)
    }
    else {
      result = "{object:" + obj.name + "}"
    }
    if (not GetBoolean(obj, "usedefaultprefix")) {
      if (obj.prefix = null) {
        prefix = ""
      }
      else {
        prefix = obj.prefix
      }
    }
    else if (type = "exit") {
      prefix = ""
    }
    else {
      prefix = GetDefaultPrefix(obj)
    }
    if (LengthOf(prefix) > 0) {
      prefix = prefix + " "
    }
    result = prefix + result
    if (not GetBoolean(obj, "usedefaultprefix") and HasString(obj, "suffix")) {
      if (LengthOf(obj.suffix) > 0) {
        result = result + " " + obj.suffix
      }
    }
    return (result)
  ]]></function>
  <function name="ObjectLink" parameters="obj" type="string">
    return ("{object:" + obj.name + "}")
  </function>
  <function name="GetListDisplayAlias" parameters="obj" type="string">
    if (HasString(obj, "listalias")) {
      // Modified by KV
      result = ProcessText(obj.listalias)
    }
    else {
      result = GetDisplayAlias(obj)
    }
    return (result)
  </function>
  <function name="CheckDarkness" type="boolean"><![CDATA[
    roomCheckDarkness = true
    if (GetBoolean(game.pov.parent, "dark")) {
      if (ListCount(ScopeVisibleLightsource("strong")) > 0) {
        roomCheckDarkness = false
      }
    }
    else {
      roomCheckDarkness = false
    }
    game.pov.parent.darklevel = roomCheckDarkness
    return (roomCheckDarkness)
  ]]></function>
  <function name="EnableTimer" parameters="timer">
    timer.enabled = true
    timer.trigger = game.timeelapsed + timer.interval
  </function>
  <function name="DisableTimer" parameters="timer">
    timer.enabled = false
  </function>
  <function name="SetTimerInterval" parameters="timer, interval">
    timer.interval = interval
  </function>
  <function name="SetTimerScript" parameters="timer, script">
    timer.script = script
  </function>
  <function name="SetTimeout" parameters="interval, script">
    SetTimeoutID (interval, "", script)
  </function>
  <function name="SetTimeoutID" parameters="interval, name, script">
    timername = ""
    if (name = "") {
      timername = GetUniqueElementName("timeout")
    }
    else {
      if (GetTimer(name) = null and GetObject(name) = null) {
        timername = name
      }
      else {
        error ("Error creating timer: There is already an existing object named " + name)
      }
    }
    if (not timername = "") {
      create timer (timername)
      timer = GetTimer(timername)
      SetTimerInterval (timer, interval)
      timer.timeoutscript = script
      SetTimerScript (timer) {
        this.enabled = false
        invoke (this.timeoutscript)
        JS.scrollToEnd ()
        destroy (this.name)
      }
      EnableTimer (timer)
    }
  </function>
  <function name="Pause" parameters="interval">
    error ("The Pause function is obsolete as of Quest 5.5")
  </function>
  <function name="RunTurnScripts">
    if (IsGameRunning()) {
      if (game.menucallback = null) {
        foreach (turnscript, ObjectListSort(AllTurnScripts(), "name")) {
          if (GetBoolean(turnscript, "enabled")) {
            inscope = false
            if (turnscript.parent = game or turnscript.parent = null) {
              inscope = true
            }
            else {
              if (Contains(turnscript.parent, game.pov)) {
                inscope = true
              }
            }
            if (inscope) {
              do (turnscript, "script")
            }
          }
        }
      }
    }
  </function>
  <function name="EnableTurnScript" parameters="turnscript">
    turnscript.enabled = true
  </function>
  <function name="DisableTurnScript" parameters="turnscript">
    turnscript.enabled = false
  </function>
  <function name="SetTurnScript" parameters="turnscript, script">
    turnscript.script = script
  </function>
  <function name="SetTurnTimeout" parameters="turncount, script">
    SetTurnTimeoutID (turncount, "", script)
  </function>
  <function name="SetTurnTimeoutID" parameters="turncount, name, script"><![CDATA[
    turnscriptname = ""
    if (name = "") {
      turnscriptname = GetUniqueElementName("turnscript")
    }
    else {
      if (GetObject(name) = null and GetTimer(name) = null) {
        turnscriptname = name
      }
      else {
        error ("Error creating turnscript: There is already an existing object named " + name)
      }
    }
    if (not turnscriptname="") {
      create turnscript (turnscriptname)
      turnscript = GetObject(turnscriptname)
      turnscript.turncount = 0
      turnscript.triggerturncount = turncount
      turnscript.timeoutscript = script
      SetTurnScript (turnscript) {
        this.turncount = this.turncount + 1
        if (this.turncount >= this.triggerturncount) {
          this.enabled = false
          invoke (this.timeoutscript)
          destroy (this.name)
        }
      }
      EnableTurnScript (turnscript)
    }
  ]]></function>
  <function name="SuppressTurnscripts">
    game.suppressturnscripts = true
  </function>
  <function name="UpdateStatusAttributes"><![CDATA[
    status = NewStringList()
    AddStatusAttributesForElement (status, game, game.statusattributes)
    AddStatusAttributesForElement (status, game.pov, game.povstatusattributes)
    AddStatusAttributesForElement (status, game.pov, game.pov.statusattributes)
    JS.updateStatus (Join(status, "<br/>"))
  ]]></function>
  <function name="AddStatusAttributesForElement" parameters="status, element, statusAttributes" type="string">
    if (not statusAttributes = null) {
      foreach (attr, statusAttributes) {
        list add (status, FormatStatusAttribute(attr, GetAttribute(element, attr), StringDictionaryItem(statusAttributes, attr)))
      }
    }
  </function>
  <function name="FormatStatusAttribute" parameters="attr, value, format" type="string">
    if (LengthOf(format) = 0) {
      return (CapFirst(attr) + ": " + value)
    }
    else {
      if (TypeOf(value) = "int" and attr = "money" and HasString(game, "moneyformat")) {
        value = DisplayMoney(value)
      }
      else if (TypeOf(value) = "int" or TypeOf(value) = "double") {
        value = ToString(value)
      }
      else if (TypeOf(value) = "null") {
        value = ""
      }
      return (Replace(format, "!", value))
    }
  </function>
  <function name="InitStatusAttributes">
    if (game.showscore) {
      game.score = 0
      if (game.statusattributes = null) {
        game.statusattributes = NewStringDictionary()
      }
      dictionary add (game.statusattributes, "score", "Score: !")
    }
    if (game.showhealth) {
      if (game.povstatusattributes = null) {
        game.povstatusattributes = NewStringDictionary()
      }
      dictionary add (game.povstatusattributes, "health", "Health: !%")
    }
    if (game.showmoney) {
      if (game.povstatusattributes = null) {
        game.povstatusattributes = NewStringDictionary()
      }
      dictionary add (game.povstatusattributes, "money", "Money: !")
    }
  </function>
  <function name="IncreaseScore" parameters="amount">
    if (not HasInt(game, "score")) {
      error ("Score is not configured. To enable score, go to 'game' and tick 'Show score' on the Player tab.")
    }
    game.score = game.score + amount
  </function>
  <function name="DecreaseScore" parameters="amount">
    if (not HasInt(game, "score")) {
      error ("Score is not configured. To enable score, go to 'game' and tick 'Show score' on the Player tab.")
    }
    game.score = game.score - amount
  </function>
  <function name="IncreaseHealth" parameters="amount">
    if (not HasInt(game.pov, "health")) {
      error ("Health is not configured. To enable health, go to 'game' and tick 'Show health' on the Player tab.")
    }
    game.pov.health = game.pov.health + amount
  </function>
  <function name="DecreaseHealth" parameters="amount">
    if (not HasInt(game.pov, "health")) {
      error ("Health is not configured. To enable health, go to 'game' and tick 'Show health' on the Player tab.")
    }
    game.pov.health = game.pov.health - amount
  </function>
  <function name="IncreaseMoney" parameters="amount">
    if (not HasInt(game.pov, "money")) {
      error ("Money is not configured. To enable money, go to 'game' and tick 'Show money' on the Player tab.")
    }
    game.pov.money = game.pov.money + amount
  </function>
  <function name="DecreaseMoney" parameters="amount">
    if (not HasInt(game.pov, "money")) {
      error ("Money is not configured. To enable money, go to 'game' and tick 'Show money' on the Player tab.")
    }
    game.pov.money = game.pov.money - amount
  </function>
  <function name="OutputText" parameters="text">
    OutputTextRaw (ProcessText(text))
  </function>
  <function name="OutputTextRaw" parameters="text"><![CDATA[
    format = GetCurrentTextFormat("")
    JS.addText ("<span style=\"" + format + "\">" + text + "</span><br/>")
    if (GetString(game, "commandbarformat") <> format) {
      ResetCommandBarFormat
    }
    RequestSpeak (text)
  ]]></function>
  <function name="ResetCommandBarFormat">
    format = GetCurrentTextFormat("") + ";background:" + game.defaultbackground
    game.commandbarformat = format
    JS.setCommandBarStyle (format)
  </function>
  <function name="OutputTextNoBr" parameters="text">
    OutputTextRawNoBr (ProcessText(text))
  </function>
  <function name="OutputTextRawNoBr" parameters="text"><![CDATA[
    JS.addText ("<span style=\"" + GetCurrentTextFormat("") + "\">" + text + "</span>")
    RequestSpeak (text)
  ]]></function>
  <function name="GetCurrentTextFormat" parameters="colour" type="string"><![CDATA[
    style = ""
    if (UIOptionUseGameFont()) {
      font = GetCurrentFontFamily()
    }
    else {
      font = GetUIOption("OverrideFontName")
    }
    if (LengthOf(font) > 0) {
      style = style + "font-family:" + font + ";"
    }
    if (LengthOf(colour) = 0) {
      if (UIOptionUseGameColours()) {
        colour = game.defaultforeground
      }
      else {
        colour = GetUIOption("OverrideForeground")
      }
    }
    if (LengthOf(colour) > 0) {
      style = style + "color:" + colour + ";"
    }
    if (UIOptionUseGameFont()) {
      size = game.defaultfontsize
    }
    else {
      size = ToDouble(GetUIOption("OverrideFontSize"))
    }
    if (size > 0) {
      style = style + "font-size:" + ToString(size) + "pt;"
    }
    return (style)
  ]]></function>
  <function name="GetCurrentLinkTextFormat" type="string">
    return (GetCurrentTextFormat(GetLinkTextColour()))
  </function>
  <function name="UIOptionUseGameFont" type="boolean">
    value = GetUIOption("UseGameFont")
    if (value = null or value = "true") {
      return (true)
    }
    else {
      return (false)
    }
  </function>
  <function name="UIOptionUseGameColours" type="boolean">
    value = GetUIOption("UseGameColours")
    if (value = null or value = "true") {
      return (true)
    }
    else {
      return (false)
    }
  </function>
  <function name="ParamsForTextProcessor" type="dictionary">
    params = NewDictionary()
    if (not game.text_processor_this = null) {
      dictionary add (params, "this", game.text_processor_this)
    }
    if (HasAttribute(game, "text_processor_variables")) {
      foreach (key, game.text_processor_variables) {
        if (not key = "this" or game.text_processor_this = null) {
          dictionary add (params, key, DictionaryItem(game.text_processor_variables, key))
        }
      }
    }
    return (params)
  </function>
  <function name="ObjectForTextProcessor" parameters="objectname" type="object">
    if (not game.text_processor_this = null and objectname = "this") {
      object = game.text_processor_this
      if (TypeOf(object) = "object") {
        return (object)
      }
    }
    if (not game.text_processor_variables = null and DictionaryContains (game.text_processor_variables, objectname)) {
      object = DictionaryItem(game.text_processor_variables, objectname)
      if (TypeOf(object) = "object") {
        return (object)
      }
    }
    return (GetObject(objectname))
  </function>
  <function name="GetLinkTextColour" type="string">
    if (UIOptionUseGameColours()) {
      return (game.defaultlinkforeground)
    }
    else {
      return (GetUIOption("OverrideLinkForeground"))
    }
  </function>
  <function name="ProcessText" parameters="text" type="string">
    data = NewDictionary()
    dictionary add (data, "fulltext", text)
    text = ProcessTextSection(text, data)
    return (Replace(Replace(text, "@@@open@@@", "{"), "@@@close@@@", "}"))
  </function>
  <function name="ProcessTextSection" parameters="text, data" type="string"><![CDATA[
    containsUnprocessedSection = false
    open = Instr(text, "{")
      if (open > 0) {
        nestCount = 1
        searchStart = open + 1
        finished = false
        while (not finished) {
          nextOpen = Instr(searchStart, text, "{")
            nextClose = Instr(searchStart, text, "}")
          if (nextClose > 0) {
            if (nextOpen > 0 and nextOpen < nextClose) {
              nestCount = nestCount + 1
              searchStart = nextOpen + 1
            }
            else {
              nestCount = nestCount - 1
              searchStart = nextClose + 1
              if (nestCount = 0) {
                close = nextClose
                containsUnprocessedSection = true
                finished = true
              }
            }
          }
          else {
            finished = true
          }
        }
      }
      if (containsUnprocessedSection) {
        section = Mid(text, open + 1, close - open - 1)
        value = ProcessTextCommand(section, data)
        value = ProcessTextSection(value, data)
        text = Left(text, open - 1) + value + ProcessTextSection(Mid(text, close + 1), data)
      }
      return (text)
  ]]></function>
  <function name="ProcessTextCommand" parameters="section, data" type="string">
    params = NewDictionary()
    dictionary add (params, "section", section)
    dictionary add (params, "data", data)
    foreach (command, game.textprocessorcommands) {
      if (StartsWith(section, command)) {
        invoke (ScriptDictionaryItem(game.textprocessorcommands, command), params)
        if (HasString(game, "textprocessorcommandresult")) {
          result = game.textprocessorcommandresult
          game.textprocessorcommandresult = null
          return (result)
        }
      }
    }
    dot = Instr(section, ".")
    if (dot = 0) {
      return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
    }
    else {
      objectname = Left(section, dot - 1)
      attributename = Mid(section, dot + 1)
      object = ObjectForTextProcessor(objectname)
      if (object = null) {
        return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
      }
      else {
        if (HasAttribute(object, attributename)) {
          type = TypeOf(object, attributename)
          switch (type) {
            case ("string", "int", "double") {
              return (ToString(GetAttribute(object, attributename)))
            }
            case ("boolean") {
              result = GetAttribute(object, attributename)
              if (result) {
                return ("true")
              }
              else {
                return ("false")
              }
            }
            default {
              return ("(" + type + ")")
            }
          }
        }
        else {
          return ("")
        }
      }
    }
  </function>
  <function name="ProcessTextCommand_Eval" parameters="section, data" type="string">
    if (StartsWith(section, "=")) {
      section = Mid(section, 2)
    }
    else {
      section = Mid(section, 6)
    }
    if (not IsRegexMatch("[^\\w\\s]", section, "tp_punctuation_check")) {
      section = section + "()"
    }
    return (ToString(eval(section)))
  </function>
  <function name="ProcessTextCommand_Either" parameters="section, data" type="string">
    command = Mid(section, 8)
    l = Tsplit(command)
    if (ListCount(l) = 1) {
      return ("@@@open@@@either " + command + "@@@close@@@")
    }
    condition = StringListItem(l, 0)
    text = StringListItem(l, 1)
    if (ListCount(l) = 2) {
      sep = Instr(text, "|")
      if (sep = 0) {
        text2 = ""
      }
      else {
        text2 = Mid(text, sep + 1)
        text = Replace(text, "|" + text2, "")
      }
    }
    else {
      text2 = StringListItem(l, 2)
    }
    result = eval(condition, ParamsForTextProcessor())
    if (result) {
      return (ProcessTextSection(text, data))
    }
    else {
      if (text2 = "") {
        return ("")
      }
      else {
        return (ProcessTextSection(text2, data))
      }
    }
  </function>
  <function name="ProcessTextCommand_Here" parameters="section, data" type="string">
    if (StartsWith(section, "here")) {
      flag = true
      command = Mid(section, 6)
    }
    else {
      flag = false
      command = Mid(section, 9)
    }
    colon = Instr(command, ":")
    if (colon = 0) {
      return ("@@@open@@@" + section + "@@@close@@@")
    }
    else {
      text = Mid(command, colon + 1)
      condition = Left(command, colon - 1)
      object = Eval(condition, ParamsForTextProcessor())
      if (object = null) {
        return ("@@@open@@@" + section + "@@@close@@@")
      }
      if (object.parent = game.pov.parent and flag) {
        return (ProcessTextSection(text, data))
      }
      else if (not object.parent = game.pov.parent and not flag) {
        return (ProcessTextSection(text, data))
      }
      else {
        return ("")
      }
    }
  </function>
  <function name="ProcessTextCommand_If" parameters="section, data" type="string"><![CDATA[
    command = Mid(section, 4)
    colon = Instr(command, ":")
    if (colon = 0) {
      return ("@@@open@@@if " + command + "@@@close@@@")
    }
    else {
      text = Mid(command, colon + 1)
      condition = Left(command, colon - 1)
      if (not game.text_processor_this = null) {
        condition = Replace(condition, "this", game.text_processor_this.name)
      }
      operator = Instr(condition, "<=")
      if (operator <> 0) {
        operatorlength = 2
      }
      if (operator = 0) {
        operator = Instr(condition, ">=")
        if (operator <> 0) {
          operatorlength = 2
        }
      }
      if (operator = 0) {
        operator = Instr(condition, "<>")
        if (operator <> 0) {
          operatorlength = 2
        }
      }
      if (operator = 0) {
        operator = Instr(condition, "<")
        if (operator <> 0) {
          operatorlength = 1
        }
      }
      if (operator = 0) {
        operator = Instr(condition, ">")
        if (operator <> 0) {
          operatorlength = 1
        }
      }
      if (operator = 0) {
        operator = Instr(condition, "=")
        if (operator <> 0) {
          operatorlength = 1
        }
      }
      if (operator = 0) {
        checkfor = true
        if (StartsWith(condition, "not ")) {
          checkfor = false
          condition = Mid(condition, 5)
        }
        dot = Instr(condition, ".")
        if (dot = 0) {
          result = GetBoolean(game, condition)
        }
        else {
          objectname = Left(condition, dot - 1)
          attributename = Mid(condition, dot + 1)
          object = ObjectForTextProcessor(objectname)
          if (object = null) {
            result = false
          }
          else {
            result = GetBoolean(object, attributename)
          }
        }
        if (result = checkfor) {
          return (ProcessTextSection(text, data))
        }
        else {
          return ("")
        }
      }
      else {
        lhs = Left(condition, operator - 1)
        rhs = Mid(condition, operator + operatorlength)
        op = Mid(condition, operator, operatorlength)
        dot = Instr(lhs, ".")
        if (dot = 0) {
          objectname = ""
          attributename = ""
          if (HasInt(game, lhs)) {
            objectname = "game"
            attributename = lhs
          }
          else {
            return ("@@@open@@@if " + command + "@@@close@@@")
          }
        }
        else {
          objectname = Left(lhs, dot - 1)
          attributename = Mid(lhs, dot + 1)
        }
        object = ObjectForTextProcessor(objectname)
        if (object = null) {
          return ("@@@open@@@if " + command + "@@@close@@@")
        }
        else if (not HasAttribute(object, attributename)) {
          return ("@@@open@@@if " + command + "@@@close@@@")
        }
        else {
          value = GetAttribute(object, attributename)
          if (TypeOf(value) = "object") {
            value = value.name
          }
          if (op = "=") {
            if (ToString(value) = rhs) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
          else if (op = "<>") {
            if (not ToString(value) = rhs) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
          else if (op = ">") {
            if (ToDouble(ToString(value)) > ToDouble(rhs)) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
          else if (op = "<") {
            if (ToDouble(ToString(value)) < ToDouble(rhs)) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
          else if (op = ">=") {
            if (ToDouble(ToString(value)) >= ToDouble(rhs)) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
          else if (op = "<=") {
            if (ToDouble(ToString(value)) <= ToDouble(rhs)) {
              return (ProcessTextSection(text, data))
            }
            else {
              return ("")
            }
          }
        }
      }
    }
  ]]></function>
  <function name="ProcessTextCommand_Format" parameters="section, data" type="string"><![CDATA[
    html = Mid(section, 1, 1)
    section = Mid(section, 3)
    return (ProcessTextSection("<" + html + ">" + section + "</" + html + ">", data))
  ]]></function>
  <function name="ProcessTextCommand_Colour" parameters="section, data" type="string"><![CDATA[
    ary = Split(section, ":")
    com = StringListItem(ary, 0)
    c = StringListItem(ary, 1)
    list remove (ary, com)
    list remove (ary, c)
    s = Join (ary, ":")
    if (com = "back") {
      return (ProcessTextSection("<span style=\"background-color:" + c + ";\">" + s + "</span>", data))
    }
    else {
      return (ProcessTextSection("<span style=\"color:" + c + ";\">" + s + "</span>", data))
    }
  ]]></function>
  <function name="ProcessTextCommand_Popup" parameters="section, data" type="string"><![CDATA[
    section = Mid(section, 7)
    ary = Split(section, ":")
    s1 = StringListItem(ary, 0)
    list remove (ary, s1)
    s2 = Join (ary, ":")
    id = JSSafe(s1) + GetRandomInt(0, 999999999)
    link = game.defaultlinkforeground
    if (HasString(game, "altlinkforeground")) {
      link = game.altlinkforeground
    }
    s = "<span  style=\"cursor:pointer;color:" + link + ";\" onclick=\"$('#" + id + "').css('display', 'block');\">" + s1 + "</span><div id=\"" + id + "\" class=\"w3-theme-border\" style=\"position:fixed;z-index:9999;display:none;cursor:pointer;left:50px;top:40%;width:40%;background-color:" + game.defaultbackground + ";border:2px solid " + game.defaultforeground + ";color:" + link + ";border-radius:5px;padding:5px;\" onclick=\"$('#" + id + "').css('display', 'none');\"><p>"
    s = s + s2 + "</p></div>"
    return (ProcessTextSection(s, data))
  ]]></function>
  <function name="ProcessTextCommand_Object" parameters="section, data" type="string"><![CDATA[
    objectname = Mid(section, 8)
    text = ""
    colon = Instr(objectname, ":")
    if (colon > 0) {
      text = Mid(objectname, colon + 1)
      objectname = Left(objectname, colon - 1)
    }
    object = ObjectForTextProcessor(objectname)
    if (object = null) {
      return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
    }
    else {
      if (LengthOf(text) = 0) {
        text = SafeXML(GetDisplayAlias(object))
      }
      if (game.enablehyperlinks) {
        linkid = ProcessTextCommand_GetNextLinkId()
        colour = ""
        if (HasString(object, "linkcolour") and GetUIOption("UseGameColours") = "true") {
          colour = object.linkcolour
        }
        else {
          colour = GetLinkTextColour()
        }
        style = GetCurrentTextFormat(colour)
        return ("<a id=\"" + linkid + "\" style=\"" + style + "\" class=\"cmdlink elementmenu\" data-elementid=\"" + object.name + "\">" + text + "</a>")
      }
      else {
        return (text)
      }
    }
  ]]></function>
  <function name="ProcessTextCommand_GetNextLinkId" type="string">
    if (not HasInt(game, "lastlinkid")) {
      game.lastlinkid = 0
    }
    game.lastlinkid = game.lastlinkid + 1
    return ("verblink" + game.lastlinkid)
  </function>
  <function name="ProcessTextCommand_Command" parameters="section, data" type="string"><![CDATA[
    colon = Instr(section, ":")
    command = Mid(section, colon + 1)
    text = command
    colon = Instr(command, ":")
    if (colon > 0) {
      text = Mid(command, colon + 1)
      command = Left(command, colon - 1)
    }
    style = GetCurrentLinkTextFormat()
    candidates = NewObjectList()
    foreach (cmd, ScopeCommands()) {
      if (IsRegexMatch(cmd.pattern, command, cmd.name)) {
        list add (candidates, cmd)
      }
    }
    elementid = ""
    if (ListCount(candidates) = 1) {
      cmd = ObjectListItem(candidates, 0)
      elementid = cmd.name
    }
    linkid = ProcessTextCommand_GetNextLinkId()
    dataattrs = ""
    if (game.deactivatecommandlinks) {
      dataattrs = dataattrs + "data-deactivateonclick=\"true\" "
    }
    dataattrs = dataattrs + "data-command=\"" + command + "\""
    return ("<a id=\"" + linkid + "\" style=\"" + style + "\" class=\"cmdlink commandlink\" data-elementid=\"" + elementid + "\" " + dataattrs + ">" + ProcessTextSection(text, data) + "</a>")
  ]]></function>
  <function name="ProcessTextCommand_Exit" parameters="section, data" type="string"><![CDATA[
    exitname = Mid(section, 6)
    exit = GetObject(exitname)
    if (exit = null) {
      return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
    }
    else {
      verbs = GetDisplayVerbs(exit)
      alias = GetDisplayAlias(exit)
      command = LCase(StringListItem(verbs, 0)) + " " + alias
      style = GetCurrentLinkTextFormat()
      return ("<a style=\"" + style + "\" class=\"cmdlink exitlink\" data-elementid=\"" + exit.name + "\" data-command=\"" + command + "\">" + alias + "</a>")
    }
  ]]></function>
  <function name="ProcessTextCommand_Once" parameters="section, data" type="string">
    if (not HasAttribute(game, "textprocessor_seen")) {
      game.textprocessor_seen = NewDictionary()
    }
    fulltext = StringDictionaryItem(data, "fulltext")
    if (not DictionaryContains(game.textprocessor_seen, fulltext)) {
      onceSectionsInThisText = NewList()
      dictionary add (game.textprocessor_seen, fulltext, onceSectionsInThisText)
    }
    else {
      onceSectionsInThisText = DictionaryItem(game.textprocessor_seen, fulltext)
    }
    if (not ListContains(onceSectionsInThisText, section)) {
      list add (onceSectionsInThisText, section)
      return (ProcessTextSection(Mid(section, 6), data))
    }
    else {
      return ("")
    }
  </function>
  <function name="ProcessTextCommand_NotFirst" parameters="section, data" type="string">
    if (not HasAttribute(game, "textprocessor_seen")) {
      game.textprocessor_seen = NewDictionary()
    }
    fulltext = StringDictionaryItem(data, "fulltext")
    if (not DictionaryContains(game.textprocessor_seen, fulltext)) {
      onceSectionsInThisText = NewList()
      dictionary add (game.textprocessor_seen, fulltext, onceSectionsInThisText)
    }
    else {
      onceSectionsInThisText = DictionaryItem(game.textprocessor_seen, fulltext)
    }
    if (not ListContains(onceSectionsInThisText, section)) {
      list add (onceSectionsInThisText, section)
      return ("")
    }
    else {
      return (ProcessTextSection(Mid(section, 10), data))
    }
  </function>
  <function name="ProcessTextCommand_Random" parameters="section, data" type="string">
    elements = Mid(section, 8)
    elementslist = Tsplit(elements)
    index = GetRandomInt(0, ListCount(elementslist) - 1)
    return (ProcessTextSection(ListItem(elementslist, index), data))
  </function>
  <function name="Tsplit" parameters="splittext" type="stringlist"><![CDATA[
    itemlist = NewStringList()
    sections = 0
    startpos = 1
    for (i, 1, LengthOf(splittext)) {
      if (Mid(splittext, i, 1) = "{") {
          sections = sections + 1
        }
        if (Mid(splittext, i, 1) = "}") {
        sections = sections - 1
      }
      if (Mid(splittext, i, 1) = ":" and 0 >= sections) {
        item = Mid(splittext, startpos, i - startpos)
        list add (itemlist, item)
        startpos = i + 1
      }
    }
    item = Mid(splittext, startpos)
    list add (itemlist, item)
    return (itemlist)
  ]]></function>
  <function name="ProcessTextCommand_RandomAlias" parameters="section, data" type="string"><![CDATA[
    objectname = Mid(section, 8)
    object = ObjectForTextProcessor(objectname)
    if (object = null) {
      return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
    }
    else {
      count = ListCount(object.alt)
      if (count > 0) {
        return (ListItem(object.alt, GetRandomInt(0, count - 1)))
      }
      else {
        return ("")
      }
    }
  ]]></function>
  <function name="ProcessTextCommand_Img" parameters="section, data" type="string"><![CDATA[
    filename = Mid(section, 5)
    return ("<img src=\"" + GetFileURL(filename) + "\" />")
  ]]></function>
  <function name="ProcessTextCommand_Counter" parameters="section, data" type="string">
    section = Mid(section, 9)
    if (HasAttribute(game, section)) {
      return (ToString(GetAttribute(game, section)))
    }
    else {
      return ("0")
    }
  </function>
  <function name="ProcessTextCommand_Select" parameters="section, data" type="string"><![CDATA[
    elements = Mid(section, 8)
    elementslist = Tsplit(elements)
    objectandatt = StringListItem (elementslist, 0)
    list remove (elementslist, objectandatt)
    objectandattlist = Split(objectandatt, ".")
    if (not ListCount (objectandattlist) = 2) {
      return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
    }
    else {
      objectname = StringListItem(objectandattlist, 0)
      object = ObjectForTextProcessor(objectname)
      if (object = null) {
        return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
      }
      else if (not HasInt (object, StringListItem(objectandattlist, 1))) {
        return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
      }
      else {
        if (Instr(elements, "|") > 0) {
          elementslist = Split(Join(elementslist, ":"), "|")
        }
        index = GetInt(object, StringListItem(objectandattlist, 1))
        if ((0 > index) or (index >= Listcount(elementslist))) {
          return ("@@@open@@@" + ProcessTextSection(section, data) + "@@@close@@@")
        }
        else {
          return (ProcessTextSection(ListItem(elementslist, index), data))
        }
      }
    }
  ]]></function>
  <function name="SetFramePicture" parameters="filename"><![CDATA[
    JS.setPanelContents ("<img src=\"" + GetFileURL(filename) + "\" onload=\"setPanelHeight()\"/>")
    game.panelcontents = filename
  ]]></function>
  <function name="ClearFramePicture">
    JS.setPanelContents ("")
    game.panelcontents = null
  </function>
  <function name="ClearScreen">
    JS.clearScreen ()
  </function>
  <function name="SetForegroundColour" parameters="colour">
    // request (Foreground, colour)
    game.defaultforeground = colour
  </function>
  <function name="SetBackgroundColour" parameters="colour">
    JS.setBackground (colour)
    game.defaultbackground = colour
  </function>
  <function name="SetLinkForegroundColour" parameters="colour">
    // request (LinkForeground, colour)
    game.defaultlinkforeground = colour
  </function>
  <function name="SetFontName" parameters="font">
    game.defaultfont = font
    game.defaultwebfont = ""
  </function>
  <function name="SetWebFontName" parameters="font">
    AddExternalStylesheet ("https://fonts.googleapis.com/css?family=" + Replace(font, " ", "+"))
    game.defaultwebfont = font
  </function>
  <function name="AddExternalStylesheet" parameters="stylesheet">
    if (game.externalstylesheets = null) {
      game.externalstylesheets = NewStringList()
    }
    if (not ListContains(game.externalstylesheets, stylesheet)) {
      list add (game.externalstylesheets, stylesheet)
      JS.addExternalStylesheet (stylesheet)
    }
  </function>
  <function name="SetFontSize" parameters="size">
    game.defaultfontsize = size
  </function>
  <function name="PrintCentered" parameters="text">
    SetAlignment ("center")
    msg (text)
    SetAlignment ("left")
  </function>
  <function name="ShowYouTube" parameters="id">
    JS.AddYouTube (id)
  </function>
  <function name="ShowVimeo" parameters="id">
    JS.AddVimeo (id)
  </function>
  <function name="DisplayHttpLink" parameters="text, url, https"><![CDATA[
    pos = Instr(url, "://")
    if (pos > 0) {
      url = Mid(url, pos + 3)
    }
    if (https) {
      url = "https://" + url
    }
    else {
      url = "http://" + url
    }
    msg ("<a style=\"" + GetCurrentLinkTextFormat() + "\" href=\"" + url + "\">" + text + "</a>")
  ]]></function>
  <function name="DisplayMailtoLink" parameters="text, url"><![CDATA[
    if (Instr(url, "mailto:") = 0) {
      url = "mailto:" + url
    }
    msg ("<a style=\"" + GetCurrentLinkTextFormat() + "\" href=\"" + url + "\">" + text + "</a>")
  ]]></function>
  <function name="CommandLink" parameters="cmd, text" type="string">
    return ("{command:" + cmd + ":" + text + "}")
  </function>
  <function name="Log" parameters="text"><![CDATA[
    // request (Log, text)
    // Replacing double quotes with 2 single quotes
    text = Replace(text, "\"", "''")
    // Changing syntax from single quotes to escaped double quotes to allow single quotes in log entries
    if (not GetBoolean(game, "nohtmllog")) {
      JS.eval ("if(typeof(addLogEntry)===\"function\"){ addLogEntry(\""+text+"\"); };")
    }
    JS.eval ("if(!webPlayer && typeof(WriteToLog)===\"function\"){var s = \""+text+"\";WriteToLog(s);}")
  ]]></function>
  <function name="SetBackgroundImage" parameters="filename">
    JS.SetBackgroundImage (GetFileURL(filename))
    game.backgroundimage = filename
  </function>
  <function name="SetBackgroundOpacity" parameters="opacity">
    JS.SetBackgroundOpacity (opacity)
    game.backgroundopacity = opacity
    game.setbackgroundopacity = true
  </function>
  <function name="DisplayList" parameters="list, numbers"><![CDATA[
    if (numbers) {
      result = "<ol>"
    }
    else {
      result = "<ul>"
    }
    foreach (item, list) {
      result = result + "<li>" + item + "</li>"
    }
    if (numbers) {
      result = result + "</ol>"
    }
    else {
      result = result + "</ul>"
    }
    msg (result)
  ]]></function>
  <function name="SetAlignment" parameters="align">
    JS.createNewDiv (align)
  </function>
  <function name="GetCurrentFontFamily" type="string">
    if (game.defaultwebfont = null) {
      return (game.defaultfont)
    }
    else {
      if (game.defaultwebfont = "") {
        return (game.defaultfont)
      }
      else {
        return ("'" + game.defaultwebfont + "', " + game.defaultfont)
      }
    }
  </function>
  <function name="FormatList" parameters="list, joiner, lastjoiner, nothing" type="string"><![CDATA[
    if (ListCount (list) = 0) {
      return (nothing)
    }
    else {
      result = ""
      count = 0
      listLength = ListCount(list)
      foreach (item, list) {
        if (TypeOf(item) = "object") {
          result = result + GetDisplayName(item)
        }
        else {
          result = result + item
        }
        count = count + 1
        if (count = listLength - 1) {
          if (not IsRegexMatch("^\\W", lastjoiner)) {
            result = result + " "
          }
          result = result + lastjoiner + " "
        }
        else if (count < listLength) {
          result = result + joiner + " "
        }
      }
      return (Trim (result))
    }
  ]]></function>
  <function name="Spaces" parameters="number" type="string"><![CDATA[
    game.command_successful = True
    text = ""
    for (x, 1, number) {
      text = text+ "&nbsp;"
    }
    return (text)
  ]]></function>
  <function name="ToRoman" parameters="n" type="string"><![CDATA[
    if (not TypeOf(n) = "int") {
      error ("ToRoman can only handle ints")
    }
    arabic = Split("1000;900;500;400;100;90;50;40;10;9;5;4;1", ";")
    roman = Split("M;CM;D;CD;C;XC;L;XL;X;IX;V;IV;I", ";")
    result = ""
    for (i, 0, 12) {
      a = ToInt(StringListItem(arabic, i))
      r = StringListItem(roman, i)
      while (n >= a) {
        result = result + r
        n = n - a
      }
    }
    return (result)
  ]]></function>
  <function name="Grid_SetScale" parameters="scale">
    JS.Grid_SetScale (scale)
  </function>
  <function name="Grid_CalculateMapCoordinates" parameters="room, playerobject"><![CDATA[
    if (room.parent <> null) {
      if (room.grid_parent_offset_auto) {
        room.grid_parent_offset_x = (room.parent.grid_width - room.grid_width) /2.0
        room.grid_parent_offset_y = (room.parent.grid_length - room.grid_length) /2.0
      }
      Grid_SetGridCoordinateForPlayer (playerobject, room.parent, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") - room.grid_parent_offset_x)
      Grid_SetGridCoordinateForPlayer (playerobject, room.parent, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") - room.grid_parent_offset_y)
      Grid_SetGridCoordinateForPlayer (playerobject, room.parent, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
      room.parent.grid_render = true
      Grid_CalculateMapCoordinates (room.parent, playerobject)
    }
    // go through all exits in room, set x,y co-ordinates for the rooms they point to
    foreach (exit, AllExits()) {
      if (exit.parent = room and not GetBoolean(exit, "lookonly")) {
        if (DoesInherit(exit, "northdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width/2.0 + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.to.grid_width/2.0)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.to.grid_length) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "eastdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length/2.0 + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.to.grid_length/2.0)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y"))
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "southdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width/2.0 + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.to.grid_width/2.0)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "westdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length/2.0 + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.to.grid_width) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.to.grid_length/2.0)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y"))
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "northwestdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.to.grid_width) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.to.grid_length) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "northeastdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.to.grid_length) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") - exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "southwestdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", (Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.to.grid_width) - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") - exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "southeastdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_x", Grid_GetGridCoordinateForPlayer(playerobject, exit, "x") + exit.grid_length)
          Grid_SetGridCoordinateForPlayer (playerobject, exit, "end_y", Grid_GetGridCoordinateForPlayer(playerobject, exit, "y") + exit.grid_length)
          exit.grid_render = true
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "updirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width/2.0 - exit.to.grid_width/2.0 + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length/2.0 - exit.to.grid_length/2.0 + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z") + exit.grid_length)
          exit.grid_render = false
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "downdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width/2.0 - exit.to.grid_width/2.0 + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length/2.0 - exit.to.grid_length/2.0 + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z") - exit.grid_length)
          exit.grid_render = false
          exit.to.grid_render = true
        }
        else if (DoesInherit(exit, "indirection") or DoesInherit(exit, "outdirection")) {
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "x", Grid_GetGridCoordinateForPlayer(playerobject, room, "x") + room.grid_width/2.0 - exit.to.grid_width/2.0 + exit.grid_offset_x)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "y", Grid_GetGridCoordinateForPlayer(playerobject, room, "y") + room.grid_length/2.0 - exit.to.grid_length/2.0 + exit.grid_offset_y)
          Grid_SetGridCoordinateForPlayer (playerobject, exit.to, "z", Grid_GetGridCoordinateForPlayer(playerobject, room, "z"))
          exit.grid_render = false
          exit.to.grid_render = true
        }
      }
    }
  ]]></function>
  <function name="Grid_DrawPlayerInRoom" parameters="room">
    if (room.grid_render) {
      Grid_DrawRoom (room, false, game.pov)
      player_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
      player_y = Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0
      player_z = Grid_GetGridCoordinateForPlayer(game.pov, room, "z")
      // Grid_DrawPlayer(x, y, z, radius, border, borderWidth, fill)
      JS.Grid_DrawPlayer (player_x, player_y, player_z, 5, "black", 2, "yellow")
    }
  </function>
  <function name="Grid_DrawRoom" parameters="room, redraw, playerobject"><![CDATA[
    if (room.grid_render) {
      if (redraw or not Grid_GetRoomBooleanForPlayer(playerobject, room, "grid_isdrawn")) {
        if (room.parent <> null) {
          Grid_DrawRoom (room.parent, redraw, playerobject)
        }
        JS.Grid_DrawBox (Grid_GetGridCoordinateForPlayer(game.pov, room, "x"), Grid_GetGridCoordinateForPlayer(game.pov, room, "y"), Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_width, room.grid_length, room.grid_border, room.grid_borderwidth, room.grid_fill, room.grid_bordersides)
        if (LengthOf(room.grid_label) > 0) {
          label_x = Grid_GetGridCoordinateForPlayer(game.pov, room, "x") + room.grid_width/2.0
          label_y = (Grid_GetGridCoordinateForPlayer(game.pov, room, "y") + room.grid_length/2.0) - 0.5
          JS.Grid_DrawLabel (label_x, label_y, Grid_GetGridCoordinateForPlayer(game.pov, room, "z"), room.grid_label, room.grid_label_colour)
        }
        foreach (exit, AllExits()) {
          if (exit.grid_render and exit.parent = room and exit.grid_length > 0) {
            Grid_DrawLine (Grid_GetGridCoordinateForPlayer(game.pov, exit, "x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "y"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_x"), Grid_GetGridCoordinateForPlayer(game.pov, exit, "end_y"), game.mapexitcolour, game.mapexitwidth)
          }
        }
        Grid_SetRoomBooleanForPlayer (playerobject, room, "grid_isdrawn", true)
      }
    }
  ]]></function>
  <function name="Grid_ShowCustomLayer" parameters="visible">
    if (visible) {
      JS.Grid_ShowCustomLayer (true)
    }
    else {
      JS.Grid_ShowCustomLayer (false)
    }
  </function>
  <function name="Grid_ClearCustomLayer">
    JS.Grid_ClearCustomLayer ()
  </function>
  <function name="Grid_DrawLine" parameters="x1, y1, x2, y2, border, borderWidth">
    JS.Grid_DrawLine (x1, y1, x2, y2, border, borderWidth)
  </function>
  <function name="Grid_DrawArrow" parameters="id, x1, y1, x2, y2, border, borderWidth">
    JS.Grid_DrawArrow (id, x1, y1, x2, y2, border, borderWidth)
  </function>
  <function name="Grid_DrawGridLines" parameters="x1, y1, x2, y2, border">
    JS.Grid_DrawGridLines (x1, y1, x2, y2, border)
  </function>
  <function name="Grid_SetCentre" parameters="x, y">
    JS.Grid_SetCentre (x, y)
  </function>
  <function name="Grid_DrawSquare" parameters="id, x, y, width, height, text, fill">
    JS.Grid_DrawSquare (id, x, y, width, height, text, fill)
  </function>
  <function name="Grid_LoadSvg" parameters="data, id">
    JS.Grid_LoadSvg (data, id)
  </function>
  <function name="Grid_DrawSvg" parameters="id, symbolid, x, y, width, height">
    JS.Grid_DrawSvg (id, symbolid, x, y, width, height)
  </function>
  <function name="Grid_DrawImage" parameters="id, url, x, y, width, height">
    JS.Grid_DrawImage (id, url, x, y, width, height)
  </function>
  <function name="Grid_AddNewShapePoint" parameters="x, y">
    JS.Grid_AddNewShapePoint (x, y)
  </function>
  <function name="Grid_DrawShape" parameters="id, border, fill, opacity">
    JS.Grid_DrawShape (id, border, fill, opacity)
  </function>
  <function name="JS_GridSquareClick" parameters="parameterstring">
    parameters = Split(parameterstring, ";")
    x = ToInt(StringListItem(parameters, 0))
    y = ToInt(StringListItem(parameters, 1))
    GridSquareClick (x, y)
  </function>
  <function name="GridSquareClick" parameters="x, y">
    // Copy this function into your game to handle grid square clicks
  </function>
  <function name="Grid_Redraw">
    foreach (object, AllObjects()) {
      if (Grid_GetRoomBooleanForPlayer(game.pov, object, "grid_isdrawn")) {
        Grid_DrawRoom (object, true, game.pov)
      }
    }
  </function>
  <function name="Grid_SetGridCoordinateForPlayer" parameters="playerobject, room, coordinate, value">
    coordinates = Grid_GetPlayerCoordinatesForRoom(playerobject, room)
    if (DictionaryContains(coordinates, coordinate)) {
      dictionary remove (coordinates, coordinate)
    }
    dictionary add (coordinates, coordinate, value * 1.0)
  </function>
  <function name="Grid_GetGridCoordinateForPlayer" parameters="playerobject, room, coordinate" type="double">
    coordinates = Grid_GetPlayerCoordinatesForRoom(playerobject, room)
    return (DictionaryItem(coordinates, coordinate))
  </function>
  <function name="Grid_SetRoomBooleanForPlayer" parameters="playerobject, room, coordinate, value">
    datadictionary = Grid_GetPlayerCoordinatesForRoom(playerobject, room)
    if (DictionaryContains(datadictionary, coordinate)) {
      dictionary remove (datadictionary, coordinate)
    }
    dictionary add (datadictionary, coordinate, value)
  </function>
  <function name="Grid_GetRoomBooleanForPlayer" parameters="playerobject, room, attribute" type="boolean">
    coordinatedata = Grid_GetPlayerCoordinateDictionary(playerobject)
    if (not DictionaryContains(coordinatedata, room.name)) {
      return (false)
    }
    else {
      datadictionary = Grid_GetPlayerCoordinatesForRoom(playerobject, room)
      if (DictionaryContains(datadictionary, attribute)) {
        return (DictionaryItem(datadictionary, attribute))
      }
      else {
        return (false)
      }
    }
  </function>
  <function name="Grid_GetPlayerCoordinateDictionary" parameters="playerobject" type="dictionary">
    if (HasAttribute(playerobject, "grid_coordinates_delegate")) {
      return (Grid_GetPlayerCoordinateDictionary(playerobject.grid_coordinates_delegate))
    }
    else {
      if (not HasAttribute(playerobject, "grid_coordinates")) {
        playerobject.grid_coordinates = NewDictionary()
        Grid_SetGridCoordinateForPlayer (playerobject, playerobject.parent, "x", 0)
        Grid_SetGridCoordinateForPlayer (playerobject, playerobject.parent, "y", 0)
        Grid_SetGridCoordinateForPlayer (playerobject, playerobject.parent, "z", 0)
        playerobject.parent.grid_render = true
        Grid_CalculateMapCoordinates (playerobject.parent, playerobject)
      }
      return (playerobject.grid_coordinates)
    }
  </function>
  <function name="Grid_GetPlayerCoordinatesForRoom" parameters="playerobject, room" type="dictionary">
    coordinatedata = Grid_GetPlayerCoordinateDictionary(playerobject)
    if (not DictionaryContains(coordinatedata, room.name)) {
      dictionary add (coordinatedata, room.name, NewDictionary())
    }
    return (DictionaryItem(coordinatedata, room.name))
  </function>
  <function name="MergePOVCoordinates"><![CDATA[
    coordinateowner = GetCoordinateOwner(game.pov)
    foreach (obj, GetDirectChildren(game.pov.parent)) {
      if (obj <> game.pov and HasAttribute(obj, "grid_coordinates")) {
        objcoordinateowner = GetCoordinateOwner(obj)
        if (coordinateowner <> objcoordinateowner) {
          MapPOVCoordinates (objcoordinateowner, coordinateowner)
        }
      }
    }
  ]]></function>
  <function name="GetCoordinateOwner" parameters="playerobject" type="object">
    if (HasAttribute(playerobject, "grid_coordinates_delegate")) {
      return (GetCoordinateOwner(playerobject.grid_coordinates_delegate))
    }
    else {
      return (playerobject)
    }
  </function>
  <function name="MapPOVCoordinates" parameters="source, target">
    sourcecoordinates = Grid_GetPlayerCoordinateDictionary(source)
    targetcoordinates = Grid_GetPlayerCoordinateDictionary(target)
    xoffset = Grid_GetGridCoordinateForPlayer(target, game.pov.parent, "x") - Grid_GetGridCoordinateForPlayer(source, game.pov.parent, "x")
    yoffset = Grid_GetGridCoordinateForPlayer(target, game.pov.parent, "y") - Grid_GetGridCoordinateForPlayer(source, game.pov.parent, "y")
    zoffset = Grid_GetGridCoordinateForPlayer(target, game.pov.parent, "z") - Grid_GetGridCoordinateForPlayer(source, game.pov.parent, "z")
    foreach (roomname, sourcecoordinates) {
      coordinatedata = DictionaryItem(sourcecoordinates, roomname)
      if (not DictionaryContains(targetcoordinates, roomname)) {
        newroomdata = NewDictionary()
        dictionary add (targetcoordinates, roomname, newroomdata)
        MapPOVCoordinate (coordinatedata, newroomdata, "x", xoffset)
        MapPOVCoordinate (coordinatedata, newroomdata, "y", yoffset)
        MapPOVCoordinate (coordinatedata, newroomdata, "z", zoffset)
        MapPOVCoordinate (coordinatedata, newroomdata, "end_x", xoffset)
        MapPOVCoordinate (coordinatedata, newroomdata, "end_y", yoffset)
      }
      else {
        newroomdata = DictionaryItem(targetcoordinates, roomname)
      }
      if (DictionaryContains(coordinatedata, "grid_isdrawn")) {
        if (DictionaryContains(newroomdata, "grid_isdrawn")) {
          dictionary remove (newroomdata, "grid_isdrawn")
        }
        dictionary add (newroomdata, "grid_isdrawn", DictionaryItem(coordinatedata, "grid_isdrawn"))
      }
    }
    source.grid_coordinates_delegate = target
    Grid_Redraw
    Grid_DrawPlayerInRoom (game.pov.parent)
  </function>
  <function name="MapPOVCoordinate" parameters="sourcedata, targetdata, name, offset">
    if (DictionaryContains(sourcedata, name)) {
      value = DictionaryItem(sourcedata, name)
      dictionary add (targetdata, name, value + offset)
    }
  </function>
  <function name="DiceRoll" parameters="dice" type="int"><![CDATA[
    if (TypeOf(dice) = "int") {
      return (dice)
    }
    p1 = Instr(dice, "d")
    p2 = Instr(dice, "+")
    p4 = Instr(dice, "-")
    p3 = LengthOf(dice)
    if (p1 = 0) {
      if (IsInt(dice)) {
        return (ToInt(dice))
      }
      error ("Invalid dice type: " + dice)
    }
    number_str = Mid(dice, 1, p1 - 1)
    if (LengthOf(number_str) = 0) {
      number = 1
    }
    else {
      number = ToInt(number_str)
    }
    if (p2 > 0) {
      sides = ToInt(Mid(dice, p1 + 1, p2 - p1 - 1))
      total = ToInt(Mid(dice, p2 + 1, p3 - p2))
    }
    else if (p4 > 0) {
      sides = ToInt(Mid(dice, p1 + 1, p4 - p1 - 1))
      total = -ToInt(Mid(dice, p4 + 1, p3 - p2))
    }
    else {
      sides = ToInt(Mid(dice, p1 + 1, p3 - p1))
      total = 0
    }
    for (i, 1, number) {
      total = total + GetRandomInt(1, sides)
    }
    return (total)
  ]]></function>
  <function name="PickOneObject" parameters="lst" type="object">
    n = ListCount(lst)
    if (n = 0) {
      return (null)
    }
    index = GetRandomInt(0, n - 1)
    return (ObjectListItem(lst, index))
  </function>
  <function name="PickOneString" parameters="lst" type="string">
    if (TypeOf(lst) = "string") {
      lst = Split(lst, ";")
    }
    n = ListCount(lst)
    if (n = 0) {
      return ("")
    }
    index = GetRandomInt(0, n - 1)
    return (StringListItem(lst, index))
  </function>
  <function name="PickOneChild" parameters="obj" type="object">
    return (PickOneObject(GetDirectChildren(obj)))
  </function>
  <function name="PickOneChildOfType" parameters="room, typename" type="object">
    l = NewObjectList()
    foreach (o, GetDirectChildren(room)) {
      if (DoesInherit(o, typename)) {
        list add (l, o)
      }
    }
    return (PickOneObject(l))
  </function>
  <function name="PickOneExit" parameters="room" type="object">
    return (PickOneObject(ScopeExitsForRoom (room)))
  </function>
  <function name="PickOneUnlockedExit" parameters="room" type="object">
    return (PickOneObject(ScopeUnlockedExitsForRoom (room)))
  </function>
  <function name="TextFX_Typewriter" parameters="text, speed">
    TextFX_Typewriter_Internal (text, speed, GetCurrentFontFamily(), game.defaultforeground, game.defaultfontsize)
  </function>
  <function name="TextFX_Typewriter_Internal" parameters="text, speed, font, color, size">
    JS.TextFX.Typewriter (text, speed, font, color, size)
  </function>
  <function name="TextFX_Unscramble" parameters="text, speed, reveal">
    TextFX_Unscramble_Internal (text, speed, reveal, GetCurrentFontFamily(), game.defaultforeground, game.defaultfontsize)
  </function>
  <function name="TextFX_Unscramble_Internal" parameters="text, speed, reveal, font, color, size">
    JS.TextFX.Unscramble (text, speed, reveal, font, color, size)
  </function>
  <function name="_DoWear" parameters="object" type="boolean"><![CDATA[
    // Is this possible?
    if (not HasAttribute(object,"worn") or not HasAttribute(object,"wear_slots")) {
      // No, not a garment
      msg (DynamicTemplate("WearUnsuccessful", object))
      return (false)
    }
    if (object.parent = game.pov and object.worn = true) {
      // No, already worn
      msg (DynamicTemplate("AlreadyWearing", object))
      return (false)
    }
    if (not ListContains(ScopeInventory(), object)) {
      // No, not held
      msg (DynamicTemplate("CannotWearIfNotHeld", object))
      return (false)
    }
    // Are other worn garments in the way?
    obj = _GetOuterForGarment(game.pov, object)
    if (not obj = null) {
      if (obj.wear_layer > object.wear_layer or obj.wear_layer = 0 or object.wear_layer = 0) {
        msg (DynamicTemplate("CannotWearOver", obj))
        return (false)
      }
      if (obj.wear_layer = object.wear_layer) {
        msg (DynamicTemplate("CannotWearWith", obj))
        return (false)
      }
    }
    if (not TestGarment(object)) {
      return (false)
    }
    WearGarment (object)
    if (object.wearmsg = null) {
      P (DynamicTemplate("WearSuccessful",object))
    }
    else {
      P (object.wearmsg)
    }
    // do after
    if (HasScript(object, "onafterwear")) {
      do (object, "onafterwear")
    }
    else if (HasString(object, "onafterwear")) {
      P (object.onafterwear)
    }
    AfterWear
    return (true)
  ]]></function>
  <function name="WearGarment" parameters="object">
    if (GetBoolean(object, "multistate")) {
      object.multistate_status = 1
    }
    else {
      object.multistate_status = 0
    }
    if (object.alias = null) {
      object.alias = object.name
    }
    if (object.listalias = null) {
      object.listalias = object.alias
    }
    if (object.original_alias = null) {
      object.original_drop = object.drop
      object.original_alias = object.alias
      object.original_listalias = object.listalias
      object.original_bonusatts = object.bonusatts
      object.original_wearslots = object.wear_slots
      object.display = GetDisplayAlias(object)
    }
    object.parent = _GetWornClothingLocation()
    object.worn = True
    object.drop = false
    _SetGarmentAlias (object)
    _SetMultistate (object)
    SetVerbs
    SetBonuses (object, true)
    if (HasInt(game.pov, "maxobjects")) {
      game.pov.maxobjects = game.pov.maxobjects + 1
    }
    // Do error checking now so item can be put on even if multistate is going to fail
    if (GetBoolean(object, "multistate")) {
      if (not HasAttribute(object, "multistate_descriptors")) {
        error ("No descriptors for multistate clothing: " + object.name)
      }
      if (not HasAttribute(object, "multistate_verbs")) {
        error ("No verbs for multistate clothing: " + object.name)
      }
      if (not HasAttribute(object, "multistate_wearslots")) {
        error ("No wearslots for multistate clothing: " + object.name)
      }
      statecount = ListCount(object.multistate_descriptors)
      if (not statecount = ListCount(object.multistate_verbs)) {
        error ("Mismatch in lists for multistate clothing: " + object.name)
      }
      if (not statecount = ListCount(object.multistate_wearslots)) {
        error ("Mismatch in lists for multistate clothing: " + object.name)
      }
      object.original_wearslots = object.wear_slots
    }
  </function>
  <function name="_DoRemove" parameters="object" type="boolean"><![CDATA[
    if (not ListContains(GetAllChildObjects(game.pov), object)) {
      msg (DynamicTemplate("CannotRemoveIfNotHeld", object))
      return (false)
    }
    if (not GetBoolean(object, "worn")) {
      msg (DynamicTemplate("CannotRemoveIfNotWearing", object))
      return (false)
    }
    if (not GetBoolean(object, "removeable")) {
      if (HasString(object, "notremoveablemessage")) {
        msg (object.notremoveablemessage)
      }
      else {
        msg (DynamicTemplate("NotRemovable", object))
      }
      return (false)
    }
    if (HasInt(game.pov, "maxobjects")) {
      if (ListCount(GetAllChildObjects(game.pov)) >= game.pov.maxobjects) {
        msg (DynamicTemplate("MaxObjectsInInventory", object))
        return (false)
      }
    }
    obj = _GetOuterForGarment(game.pov, object)
    if (not obj = null) {
      if (obj.wear_layer > object.wear_layer) {
        msg (DynamicTemplate("RemoveFirst", obj))
        return (false)
      }
    }
    if (not TestRemove(object)) {
      return (false)
    }
    RemoveGarment (object)
    if (object.removemsg = null) {
      P (DynamicTemplate("RemoveSuccessful",object))
    }
    else {
      P (object.removemsg)
    }
    // do after
    if (HasScript(object, "onafterremove")) {
      do (object, "onafterremove")
    }
    else if (HasString(object, "onafterremove")) {
      P (object.onafterremove)
    }
    AfterRemove
    return (true)
  ]]></function>
  <function name="RemoveGarment" parameters="object"><![CDATA[
    SetBonuses (object, false)
    object.worn = false
    object.drop = object.original_drop
    object.alias = object.original_alias
    object.multistate_status = 0
    if (HasString(object, "listalias")) {
      if (StartsWith(object.listalias, "<span style=\"color:blue\">")) {
        object.listalias = null
        do (object, "colourmylistalias")
      }
      else {
        object.listalias = object.original_listalias
      }
    }
    object.parent = game.pov
    if (HasInt(game.pov, "maxobjects")) {
      game.pov.maxobjects = game.pov.maxobjects - 1
    }
    SetVerbs
  ]]></function>
  <function name="Slots" type="stringlist">
    sl = NewStringList()
    foreach (o, AllObjects()) {
      if (HasAttribute(o, "wear_slots")) {
        foreach (s, o.wear_slots) {
          if (not ListContains(sl, s)) {
            list add (sl, s)
          }
        }
      }
    }
    return (sl)
  </function>
  <function name="GetDisplayGarment" parameters="obj" type="string"><![CDATA[
    if (not GetBoolean(obj, "usedefaultprefix")) {
      if (obj.prefix = null) {
        prefix = ""
      }
      else {
        prefix = obj.prefix
      }
    }
    else {
      prefix = GetDefaultPrefix(obj)
    }
    if (LengthOf(prefix) > 0) {
      prefix = prefix + " "
    }
    if (HasString(obj, "original_alias")) {
      result = prefix + obj.original_alias
    }
    else {
      result = prefix + obj.alias
    }
    if (not GetBoolean(obj, "usedefaultprefix") and HasString(obj, "suffix")) {
      if (LengthOf(obj.suffix) > 0) {
        result = result + " " + obj.suffix
      }
    }
    return (result)
  ]]></function>
  <function name="GetDescriptor" parameters="object" type="string">
    if (object.multistate_status = 0) {
      return (" (" + object.wornmodifier + ")")
    }
    s = StringListItem(object.multistate_descriptors, object.multistate_status - 1)
    if (s = "*") {
      return (" (" + object.wornmodifier + ")")
    }
    return (" (" + object.wornmodifier + " " + s + ")")
  </function>
  <function name="SetMultistate" parameters="object, state"><![CDATA[
    if (state < 1) {
      error ("Attempt to set state to " + state + " for " + object.name)
    }
    if (state > ListCount(object.multistate_descriptors)) {
      error ("Attempt to set state to " + state + " for " + object.name + " (max " + ListCount(object.multistate_descriptors) + ")")
    }
    if (not object.multistate_status = state) {
      SetBonuses (object, false)
      object.multistate_status = state
      _SetGarmentAlias (object)
      _SetMultistate (object)
      SetBonuses (object, true)
      SetVerbs
    }
  ]]></function>
  <function name="GetOuterFor" parameters="char, slot" type="object"><![CDATA[
    garment = null
    foreach (o, _GetList(char, slot)) {
      if (garment = null) {
        garment = o
      }
      else if (o.wear_layer > garment.wear_layer) {
        garment = o
      }
    }
    return (garment)
  ]]></function>
  <function name="ListWornFor" parameters="char" type="objectlist">
    return (_GetList(char, null))
  </function>
  <function name="ListVisibleFor" parameters="char" type="objectlist">
    ol = newObjectList()
    foreach (s, Slots()) {
      o = GetOuterFor(char, s)
      if (not o = null and not ListContains(ol, o)) {
        list add (ol, o)
      }
    }
    return (ol)
  </function>
  <function name="GetArmourFor" parameters="char" type="int">
    total = 2 * _GetSlotArmour(char, "head") + 3 * _GetSlotArmour(char, "torso")
    foreach (s, Split("feet|legs|shoulders|arms|hands", "|")) {
      total = total + _GetSlotArmour(char, s)
    }
    return (total)
  </function>
  <function name="GetOuter" parameters="slot" type="object">
    return (GetOuterFor(game.pov, slot))
  </function>
  <function name="GetArmour" type="int">
    return (GetArmourFor(game.pov))
  </function>
  <function name="SetVerbs">
    foreach (o, GetAllChildObjects(game.pov)) {
      if (DoesInherit(o, "wearable")) {
        if (HasAttribute(o, "wear_adjverbs")) {
          if (o.wear_adjverbs) {
            if (HasAttribute(o, "wear_slots") and HasInt(o, "wear_layer")) {
              _SetVerbsForGarment (o)
            }
            if (not HasString(o, "alias")) {
              o.alias = o.name
            }
            if (not HasString(o, "listalias")) {
              o.listalias = o.alias
            }
          }
        }
      }
    }
  </function>
  <function name="WornCount" type="int">
    count = 0
    foreach (o, GetAllChildObjects(game.pov)) {
      if (GetBoolean(o, "worn")) {
        count = count + 1
      }
    }
    return (count)
  </function>
  <function name="ListClothes" type="string">
    l = NewStringList()
    foreach (obj, ListWornFor(game.pov)) {
      list add (l, GetDisplayGarment(obj))
    }
    return (FormatList(l, ",", "and", "nothing"))
  </function>
  <function name="SetBonuses" parameters="garment, wearflag">
    if (HasString(garment, "bonusatts")) {
      foreach (att, Split(garment.bonusatts, ";")) {
        bonus = 1
        plusarray = Split(att, "+")
        minusarray = Split(att, "-")
        if (ListCount(plusarray) = 2) {
          att = StringListitem(plusarray, 0)
          if (not IsInt(StringListitem(plusarray, 1))) {
            error ("Bonus attribute for " + garment.name + " not properly formatted: " + garment.bonusatts)
          }
          bonus = ToInt(StringListitem(plusarray, 1))
        }
        if (ListCount(minusarray) = 2) {
          att = StringListitem(minusarray, 0)
          if (not IsInt(StringListitem(minusarray, 1))) {
            error ("Negative bonus attribute for " + garment.name + " not properly formatted: " + garment.bonusatts)
          }
          bonus = -ToInt(StringListitem(minusarray, 1))
        }
        if (not wearflag) {
          bonus = -bonus
        }
        bonus = ClothingBonusMultiplier() * bonus
        n = GetInt(game.pov, att) + bonus
        set (player, att, n)
      }
    }
  </function>
  <function name="SetAlias" parameters="object, alias">
    SetListAlias (object, alias, alias)
  </function>
  <function name="SetListAlias" parameters="object, alias, listalias">
    object.alias = alias
    object.listalias = listalias
    if (Equal(object.worn, true)) {
      object.original_alias = object.alias
      object.original_listalias = object.listalias
      object.display = GetDisplayAlias(object)
      _SetGarmentAlias (object)
    }
  </function>
  <function name="_SetMultistate" parameters="object">
    if (GetBoolean(object, "multistate")) {
      ws = StringListItem(object.multistate_wearslots, object.multistate_status - 1)
      if (ws = "*") {
        object.wear_slots = object.original_wearslots
      }
      else {
        object.wear_slots = Split(ws, ";")
      }
      wv = StringListItem(object.multistate_verbs, object.multistate_status - 1)
      if (wv = "*") {
        object.wornverbs = null
      }
      else {
        object.wornverbs = wv
      }
      ba = StringListItem(object.multistate_bonusatts, object.multistate_status - 1)
      if (ba = "*") {
        object.bonusatts = object.original_bonusatts
      }
      else {
        object.bonusatts = ba
      }
    }
  </function>
  <function name="_SetGarmentAlias" parameters="object"><![CDATA[
    ext = GetDescriptor(object)
    object.alias = object.display + ext
    if (HasString(object, "listalias")) {
      if (StartsWith(object.listalias, "<span style=\"color:blue\">")) {
        object.listalias = null
        do (object, "colourmylistalias")
      }
      else {
        object.listalias = object.original_listalias + ext
      }
    }
  ]]></function>
  <function name="_GetWornClothingLocation" type="object">
    foreach (o, GetDirectChildren(game.pov)) {
      if (GetBoolean(o, "wornclothinglocation")) {
        return (o)
      }
    }
    return (game.pov)
  </function>
  <function name="_GetOuterForGarment" parameters="char, garment" type="object">
    foreach (slot, garment.wear_slots) {
      obj = GetOuterFor(char, slot)
      if (not obj = null and not obj = garment) {
        return (obj)
      }
    }
    return (null)
  </function>
  <function name="_SetVerbList" parameters="garment, list, s">
    garment.inventoryverbs = list
    if (not s = null) {
      if (not s = "") {
        foreach (s2, Split(s, ";")) {
          list add (garment.inventoryverbs, s2)
        }
      }
    }
  </function>
  <function name="_SetVerbsForGarment" parameters="garment"><![CDATA[
    outer = _GetOuterForGarment(game.pov, garment)
    if (not garment.worn) {
      if (outer = null) {
        _SetVerbList (garment, Split("Look at;Drop;Wear", ";"), garment.invverbs)
      }
      else if (outer.wear_layer < garment.wear_layer) {
        _SetVerbList (garment, Split("Look at;Drop;Wear", ";"), garment.invverbs)
      }
      else {
        _SetVerbList (garment, Split("Look at;Drop", ";"), garment.invverbs)
      }
    }
    else {
      if (outer = null) {
        if (garment.removeable) {
          _SetVerbList (garment, Split("Look at;Remove", ";"), garment.wornverbs)
        }
        else {
          _SetVerbList (garment, Split("Look at", ";"), garment.wornverbs)
        }
      }
      else if (outer.wear_layer < garment.wear_layer) {
        if (garment.removeable) {
          _SetVerbList (garment, Split("Look at;Remove", ";"), garment.wornverbs)
        }
        else {
          _SetVerbList (garment, Split("Look at", ";"), garment.wornverbs)
        }
      }
      else {
        garment.inventoryverbs = Split("Look at", ";")
      }
    }
  ]]></function>
  <function name="_GetList" parameters="char, slot" type="objectlist">
    garments = NewObjectList()
    foreach (o, GetAllChildObjects(char)) {
      if (HasAttribute(o, "wear_slots") and HasInt(o, "wear_layer") and GetBoolean(o, "worn")) {
        if (ListContains(o.wear_slots, slot) or slot = null) {
          list add (garments, o)
        }
      }
    }
    return (garments)
  </function>
  <function name="_GetSlotArmour" parameters="char, slot" type="int"><![CDATA[
    total = 0
    max = 0
    foreach (o, _GetList(char, slot)) {
      total = total + o.armour
      if (o.armour > max) {
        max = o.armour
      }
    }
    return (total + max)
  ]]></function>
  <function name="ClothingBonusMultiplier" type="int">
    return (1)
  </function>
  <function name="AfterRemove">
  </function>
  <function name="AfterWear">
  </function>
  <function name="P" parameters="s">
    msg (s)
  </function>
  <function name="UpdateArmour">
  </function>
  <function name="TestGarment" parameters="object" type="boolean">
    return (true)
  </function>
  <function name="TestRemove" parameters="object" type="boolean">
    return (true)
  </function>
  <function name="ParseToQuestCode" parameters="text"><![CDATA[
    // ----------------------------------------------------------------------------------------------------
    // REGEX
    // the regular expression to check the user input.
    // RegEx available in https://regex101.com/r/4qBEbT/1
    // ----------------------------------------------------------------------------------------------------
    regex = "^(?<object>\\S+?)\\.(?<attribute>\\S+?)(?:(?<keytoken>\\[|\\{)(?<key>.*?)(?:\\]|\\}))?(?:\\s?(?<istoken>\\=)\\s?(?:(?<valkeytoken>(?:\\[|\\{)?)(?<value>.*?)(?:\\]|\\})?)(?(valkeytoken)|(?:(?<valobject>.+?)\\.(?<valattribute>.+?))))?$"
    // ----------------------------------------------------------------------------------------------------
    // SUCCESS MATCH
    // If the user's entry is error-free, it is validated further.
    // ----------------------------------------------------------------------------------------------------
    if (IsRegexMatch (regex, text)) {
      result = populate (regex, text)
      Log (ToString(result))
      // ----------------------------------------------------------------------------------------------------
      // ASSIGN RESULT
      // Assign the result of the match to the appropriate object and attribute.
      // ----------------------------------------------------------------------------------------------------
      // Object
      object = getObjectExt(result["object"])
      if (TypeOf(object) = "null") {
        error (DynamicTemplate("DevModeErrorCantFindObject", result["object"]))
      }
      // Attribute
      attribute = result["attribute"]
      current_value = GetAttribute(object, attribute)
      if (TypeOf(current_value) = "null" and result["istoken"] <> "=") {
        error (DynamicTemplate("DevModeErrorCantFindAttribute", result["attribute"]))
      }
      // Value
      value = result["value"]
      // ----------------------------------------------------------------------------------------------------
      // SET VALUE
      // If an actual equals sign has been set, the input is treated as an assignment.
      // ----------------------------------------------------------------------------------------------------
      if (result["istoken"] = "=") {
        // ----------------------------------------------------------------------------------------------------
        // BOOLEAN-TOKENS
        // Short notation for Boolean states
        // ----------------------------------------------------------------------------------------------------
        if (result["value"] = "?") {
          value = true
        }
        else if (result["value"] = "!") {
          value = false
        }
        else if (result["value"] = "~") {
          value = not GetBoolean (object, attribute)
        }
        else if (result["valkeytoken"] = "[") {
          value = NewList ()
          if (result["value"] <> "") {
            list = Split(result["value"], ",")
            foreach (item, list) {
              list add (value, Eval(Trim(item)))
            }
          }
        }
        else if (result["valkeytoken"] = "{") {
            value = NewDictionary ()
            if (result["value"] <> "") {
              list = Split(result["value"], ",")
              foreach (assign, list) {
                if (not Instr(assign, ":") = 0) {
                  dic = Split(assign, ":")
                  dickey = dic[0]
                  dicvalue = dic[1]
                  dictionary add (value, dickey, Eval(Trim(dicvalue)))
                }
                else {
                  error (Template("DevModeErrorWrongFormat"))
                }
              }
            }
          }
          else if (result["valobject"] <> "") {
            valobject = getObjectExt(result["valobject"])
            if (TypeOf(valobject) = "null") {
              error (DynamicTemplate("DevModeErrorCantFindObject", result["valobject"]))
            }
            // Valattribute
            if (result["valattribute"] <> "") {
              valattribute = result["valattribute"]
              value = GetAttribute(valobject, valattribute)
              if (TypeOf(value) = "null") {
                error (DynamicTemplate("DevModeErrorCantFindAttribute", result["valattribute"]))
              }
            }
          }
          else {
            value = Eval(result["value"])
          }
          // ----------------------------------------------------------------------------------------------------
          // VALUE-LIST
          // Creating a new list
          // ----------------------------------------------------------------------------------------------------
          // ----------------------------------------------------------------------------------------------------
          // VALUE-DICTIONARY
          // Creating a new dictionary
          // ----------------------------------------------------------------------------------------------------
          // ----------------------------------------------------------------------------------------------------
          // VALUE-OBJECT AND VALUE-ATTRIBUTE
          // Assigning an attribute from another object
          // ----------------------------------------------------------------------------------------------------
          // ----------------------------------------------------------------------------------------------------
          // VALUE EVALUATION
          // Value is evaluated
          // ----------------------------------------------------------------------------------------------------
          // ----------------------------------------------------------------------------------------------------
          // SET-ATTRIBUTE-LIST
          // Add a new item to a list or overwrite an existing one
          // ----------------------------------------------------------------------------------------------------
          if (result["keytoken"] = "[") {
            if (TypeOf(current_value) <> "list" and TypeOf(current_value) <> "objectlist" and TypeOf(current_value) <> "stringlist") {
              current_value = NewList ()
            }
            if (result["key"] <> "") {
              if (not IsNumeric(result["key"])) {
                error (Template("DevModeErrorWrongTyp"))
              }
              else if (ToInt(result["key"]) < ListCount(current_value)) {
                list remove (current_value, ListItem(current_value, ToInt(result["key"])))
              }
            }
            list add (current_value, value)
            value = NewList ()
            value = current_value
          }
          else if (result["keytoken"] = "{") {
              if (TypeOf(current_value) <> "dictionary" and TypeOf(current_value) <> "objectdictionary" and TypeOf(current_value) <> "stringdictionary") {
                current_value = NewDictionary ()
              }
              if (result["key"] <> "") {
                if (result["key"] in current_value) {
                  dictionary remove (current_value, result["key"])
                }
                dictionary add (current_value, result["key"], value)
                value = NewDictionary ()
                value = current_value
              }
            }
            // ----------------------------------------------------------------------------------------------------
            // SET-ATTRIBUTE-DICTIONARY
            // Add a new key to a dictionary or overwrite an existing one
            // ----------------------------------------------------------------------------------------------------
            // ----------------------------------------------------------------------------------------------------
            // VALUE-ASSIGNMENT
            // The value is assigned to the attribute and a corresponding output appears
            // ----------------------------------------------------------------------------------------------------
            set (object, attribute, value)
            DevModeOutput (Template("DevModeComSetAttribute") + object.name + "." + attribute + "=" + ParseToFlyScript(value))
          }
          else {
            key = ""
            // ----------------------------------------------------------------------------------------------------
            // GET-ATTRIBUTE-LIST
            // If the attribute is a list and the specified key is in it, the content is read out.
            // ----------------------------------------------------------------------------------------------------
            if (result["keytoken"] = "[") {
              if (TypeOf(current_value) <> "list" and TypeOf(current_value) <> "objectlist" and TypeOf(current_value) <> "stringlist") {
                error (Template("DevModeErrorWrongTyp"))
              }
              else if (not IsNumeric(result["key"])) {
                error (Template("DevModeErrorWrongTyp"))
              }
              else if (ToInt(result["key"]) > ListCount(current_value)-1) {
                error (Template("DevModeErrorWrongKey"))
              }
              else {
                current_value = ListItem(current_value, ToInt(result["key"]))
              }
              key = "[" + result["key"] + "]"
            }
            // ----------------------------------------------------------------------------------------------------
            // GET-ATTRIBUTE-DICTIONARY
            // If the attribute is a dictionary and the specified key is in it, the content is read out.
            // ----------------------------------------------------------------------------------------------------
            if (result["keytoken"] = "{") {
                if (TypeOf(current_value) <> "dictionary" and TypeOf(current_value) <> "objectdictionary" and TypeOf(current_value) <> "stringdictionary") {
                  error (Template("DevModeErrorWrongTyp"))
                }
                else if (not result["key"] in current_value) {
                  error (Template("DevModeErrorWrongKey"))
                }
                else {
                  current_value = DictionaryItem(current_value, result["key"])
                }
                key = "{" + result["key"] + "}"
              }
              // ----------------------------------------------------------------------------------------------------
              // VALUE-READING
              // The value of the attribute is read out
              // ----------------------------------------------------------------------------------------------------
              DevModeOutput (Template("DevModeComGetAttribute") + object.name + "." + attribute + key + "=" + ParseToFlyScript(current_value))
            }
            // ----------------------------------------------------------------------------------------------------
            // GET VALUE
            // If no equal sign has been set, the result is treated as readout.
            // ----------------------------------------------------------------------------------------------------
          }
          else {
            error (Template("DevModeErrorWrongFormat"))
          }
          // ----------------------------------------------------------------------------------------------------
          // FAIL MATCH
          // An error message is displayed if the user's entry is incorrect.
          // ----------------------------------------------------------------------------------------------------
  ]]></function>
  <function name="ParseToFlyScript" parameters="text" type="string"><![CDATA[
    switch (TypeOf(text)) {
      // ----------------------------------------------------------------------------------------------------
      // STRING
      // ----------------------------------------------------------------------------------------------------
      case ("string") {
        parsetext = "\"" + text + "\""
      }
      // ----------------------------------------------------------------------------------------------------
      // OBJECT
      // ----------------------------------------------------------------------------------------------------
      case ("object") {
        parsetext = text.name
      }
      // ----------------------------------------------------------------------------------------------------
      // SCRIPT
      // ----------------------------------------------------------------------------------------------------
      case ("script") {
        parsetext = "<" + Replace(ToString(text), "Script: ", "") + ">"
      }
      // ----------------------------------------------------------------------------------------------------
      // LIST
      // ----------------------------------------------------------------------------------------------------
      case ("list", "stringlist", "objectlist") {
        list = NewStringList()
        foreach (item, text) {
          switch (TypeOf(item)) {
            case ("string") item = "\"" + item + "\""
            case ("object") item = item.name
            default item = ToString(item)
          }
          list add (list, item)
        }
        parsetext = "[" + Join (list, ",") + "]"
      }
      // ----------------------------------------------------------------------------------------------------
      // DICTIONARY
      // ----------------------------------------------------------------------------------------------------
      case ("dictionary", "stringdictionary", "objectdictionary", "scriptdictionary") {
        list = NewStringList()
        foreach (key, text) {
          item = DictionaryItem(text, key)
          switch (TypeOf(item)) {
            case ("string") item = "\"" + item + "\""
            case ("object") item = item.name
            case ("script") item = "<" + Replace(ToString(item), "Script: ", "") + ">"
            default item = ToString(item)
          }
          list add (list, key + ":" + item)
        }
        parsetext = "{" + Join (list, ",") + "}"
      }
      // ----------------------------------------------------------------------------------------------------
      // OTHER TYPES
      // ----------------------------------------------------------------------------------------------------
      default {
        parsetext = ToString(text)
      }
    }
    return (parsetext)
  ]]></function>
  <function name="DevModeOutput" parameters="str"><![CDATA[
    if (game.devmode_showinfos) {
      if (game.devmode_ownfontcolour) {
        col = " color=\"" + game.devmode_fontcolour + "\""
      }
      else {
        col = ""
      }
      msg ("<font" + col + ">" + str + "</font>")
    }
  ]]></function>
  <function name="DevModeOutputError" parameters="str"><![CDATA[
    if (game.devmode_showinfos) {
      msg ("<font color=\"red\">" + str + "</font>")
    }
  ]]></function>
  <function name="setWithoutChange" parameters="obj, att, val"><![CDATA[
    cha = "changed" + att
    bla => {
    }
    scr => {
    }
    if (obj = null) {
      error (Template("DevModeErrorObjectNotRecognised"))
    }
    if (HasAttribute (obj, cha)) {
      scr = GetAttribute (obj, cha)
      set (obj, cha, bla)
      set (obj, att, val)
      set (obj, cha, scr)
    }
    else {
      set (obj, att, val)
    }
  ]]></function>
  <function name="setDevMode">
    if (HasAttribute(game, "devmode_active")) {
      if (game.devmode_active) {
        DevModeOutput (Template("DevModeActive"))
        if (HasAttribute(game, "devmode_attributes") and not DictionaryCount(game.devmode_attributes) = 0) {
          foreach (key, game.devmode_attributes) {
            command = key + "=" + ToString(DictionaryItem(game.devmode_attributes, key))
            commandOutput ("#" + command)
            ParseToQuestCode (command)
          }
        }
        if (game.devmode_changepov) {
          commandOutput ("#to " + game.devmode_pov)
          HandleSingleCommand ("#to " + game.devmode_pov)
        }
        if (game.devmode_changepovpos) {
          commandOutput ("#go " + game.devmode_povpos)
          HandleSingleCommand ("#go " + game.devmode_povpos)
        }
        if (game.devmode_setverbs) {
          setVerbs
        }
        if (game.devmode_setinitscript and HasScript(game, "devmode_initscript")) {
          msg ("")
          DevModeOutput (Template("DevModeStartScript"))
          do (game, "devmode_initscript")
        }
        msg ("")
      }
    }
  </function>
  <function name="getTableDataNames" parameters="empty">
    data = NewStringList ()
    list add (data, "{\"name\":\"game\"}")
    foreach (obj, AllObjects()) {
      list add (data, "{\"name\":\"" + obj.name + "\"}")
    }
    datastr = "[" + Join (data, ",") + "]"
    JS.setTableData ("names", datastr)
  </function>
  <function name="getTableDataAttr" parameters="name">
    data = NewStringList ()
    obj = GetObject (name)
    foreach (attr, GetAttributeNames (obj, true)) {
      val = ParseToFlyScript (GetAttribute (obj, attr))
      list add (data, "{\"attribute\":\"" + attr + "\",\"value\":\"" + Replace(val, "\"", "\\\"") + "\"}")
    }
    datastr = "[" + Join (data, ",") + "]"
    JS.setTableData ("attr", datastr)
  </function>
  <function name="setTableData" parameters="command">
    commandOutput ("#" + command)
    ParseToQuestCode (command)
  </function>
  <function name="commandOutput" parameters="command"><![CDATA[
    msg ("")
    DevModeOutput ("> " + command)
  ]]></function>
  <function name="setVerbs">
    verbs = game.devmode_verbs
    foreach (object, AllObjects()) {
      if (HasAttribute(object, "displayverbs")) {
        object.displayverbs = ListCombine (object.displayverbs, verbs)
      }
      if (HasAttribute(object, "inventoryverbs")) {
        object.inventoryverbs = ListCombine (object.inventoryverbs, verbs)
      }
    }
    game.enablehyperlinks = true
    msg ("")
    DevModeOutput (Template("DevModeSetVerbs"))
  </function>
  <function name="getObjectExt" parameters="name" type="object">
    obj = GetObject(name)
    if (obj = null) {
      foreach (sobj, AllObjects()) {
        if (HasAttribute(sobj, "alias")) {
          if (LCase(sobj.alias) = LCase(name)) {
            return (sobj)
          }
        }
      }
    }
    return (obj)
  </function>
  <function name="selfTest"><![CDATA[
    msg ("")
    DevModeOutput ("<b>Start DevMode-Selftest...</b>")
    // ----------------------------------------------------------------------------------------------------
    // TESTOBJECTS
    // Generate testobjects
    // ----------------------------------------------------------------------------------------------------
    create ("testobject1")
    create ("testobject2")
    testobject1.testattribut = ""
    // ----------------------------------------------------------------------------------------------------
    // COMMANDS
    // Generate commmands for testing
    // ----------------------------------------------------------------------------------------------------
    commands = NewDictionary ()
    // ----------------------------------------------------------------------------------------------------
    // OBJECT-COMMANDS
    // Unlike the commands in the game, they are executed directly and without detours via intercept scripts
    // ----------------------------------------------------------------------------------------------------
    dictionary add (commands, "#take testobject1", "Got (testobject1)")
    dictionary add (commands, "#drop testobject1", "Contains (game.pov.parent, testobject1)")
    dictionary add (commands, "#put testobject1 in testobject2", "Contains (testobject2, testobject1)")
    dictionary add (commands, "#open testobject1", "testobject1.isopen")
    dictionary add (commands, "#close testobject1", "not testobject1.isopen")
    dictionary add (commands, "#on testobject1", "IsSwitchedOn(testobject1)")
    dictionary add (commands, "#off testobject1", "not IsSwitchedOn(testobject1)")
    dictionary add (commands, "#to testobject1", "game.pov = testobject1")
    dictionary add (commands, "#go testobject2", "game.pov.parent = testobject2")
    // ----------------------------------------------------------------------------------------------------
    // OBJECT-ATTRIBUTES
    // assign and read attributes
    // ----------------------------------------------------------------------------------------------------
    // BOOLEAN
    dictionary add (commands, "#testobject1.testattribut=true", "TypeOf(testobject1.testattribut) = \"boolean\" and testobject1.testattribut=true")
    dictionary add (commands, "#testobject1.testattribut=false", "TypeOf(testobject1.testattribut) = \"boolean\" and testobject1.testattribut=false")
    dictionary add (commands, "#testobject1.testattribut=?", "TypeOf(testobject1.testattribut) = \"boolean\" and testobject1.testattribut=true")
    dictionary add (commands, "#testobject1.testattribut=!", "TypeOf(testobject1.testattribut) = \"boolean\" and testobject1.testattribut=false")
    dictionary add (commands, "#testobject1.testattribut=~", "TypeOf(testobject1.testattribut) = \"boolean\" and testobject1.testattribut=true")
    // STRING
    dictionary add (commands, "#testobject1.testattribut=\"teststring\"", "TypeOf(testobject1.testattribut) = \"string\" and testobject1.testattribut=\"teststring\"")
    // INTEGER
    dictionary add (commands, "#testobject1.testattribut=25", "TypeOf(testobject1.testattribut) = \"int\" and testobject1.testattribut = 25")
    // DOUBLE
    dictionary add (commands, "#testobject1.testattribut=25.25", "TypeOf(testobject1.testattribut) = \"double\" and testobject1.testattribut = 25.25")
    // OBJECT
    dictionary add (commands, "#testobject1.testattribut=testobject1", "TypeOf(testobject1.testattribut) = \"object\" and testobject1.testattribut = testobject1")
    // LIST
    dictionary add (commands, "#testobject1.testattribut=[]", "TypeOf(testobject1.testattribut) = \"list\" and ListCount(testobject1.testattribut) = 0")
    dictionary add (commands, "#testobject1.testattribut=[\"testitem1\",\"testitem2\",testobject1,testobject2]", "TypeOf(testobject1.testattribut) = \"list\" and ListCount(testobject1.testattribut) = 4 and TypeOf(ListItem(testobject1.testattribut, 0)) = \"string\" and ListItem(testobject1.testattribut, 0) = \"testitem1\" and TypeOf(ListItem(testobject1.testattribut, 1)) = \"string\" and ListItem(testobject1.testattribut, 1) = \"testitem2\" and TypeOf(ListItem(testobject1.testattribut, 2)) = \"object\" and ListItem(testobject1.testattribut, 2) = testobject1 and TypeOf(ListItem(testobject1.testattribut, 3)) = \"object\" and ListItem(testobject1.testattribut, 3) = testobject2")
    dictionary add (commands, "#testobject1.testattribut[2]=\"newtestitem2\"", "TypeOf(testobject1.testattribut) = \"list\" and ListCount(testobject1.testattribut) = 4 and TypeOf(ListItem(testobject1.testattribut, 3)) = \"string\" and ListItem(testobject1.testattribut, 3) = \"newtestitem2\"")
    dictionary add (commands, "#testobject1.testattribut[]=\"newtestitem5\"", "TypeOf(testobject1.testattribut) = \"list\" and ListCount(testobject1.testattribut) = 5 and ListItem(testobject1.testattribut, 4) = \"newtestitem5\"")
    dictionary add (commands, "#testobject1.testattribut[1]", "")
    // DICTIONARY
    dictionary add (commands, "#testobject1.testattribut={}", "TypeOf(testobject1.testattribut) = \"dictionary\" and DictionaryCount(testobject1.testattribut) = 0")
    dictionary add (commands, "#testobject1.testattribut={testkey1:\"testitem1\",testkey2:\"testitem2\",testkey3:testobject1,testkey4:testobject2}", "TypeOf(testobject1.testattribut) = \"dictionary\" and DictionaryCount(testobject1.testattribut) = 4 and TypeOf(DictionaryItem(testobject1.testattribut, \"testkey1\")) = \"string\" and DictionaryItem(testobject1.testattribut, \"testkey1\") = \"testitem1\" and TypeOf(DictionaryItem(testobject1.testattribut, \"testkey2\")) = \"string\" and DictionaryItem(testobject1.testattribut, \"testkey2\") = \"testitem2\" and TypeOf(DictionaryItem(testobject1.testattribut, \"testkey3\")) = \"object\" and DictionaryItem(testobject1.testattribut, \"testkey3\") = testobject1 and TypeOf(DictionaryItem(testobject1.testattribut, \"testkey4\")) = \"object\" and DictionaryItem(testobject1.testattribut, \"testkey4\") = testobject2")
    dictionary add (commands, "#testobject1.testattribut{testkey4}=\"newtestitem4\"", "TypeOf(testobject1.testattribut) = \"dictionary\" and DictionaryCount(testobject1.testattribut) = 4 and TypeOf(DictionaryItem(testobject1.testattribut, \"testkey4\")) = \"string\" and DictionaryItem(testobject1.testattribut, \"testkey4\") = \"newtestitem4\"")
    dictionary add (commands, "#testobject1.testattribut{testkey1}", "")
    // OBJECTATTRIBUT
    dictionary add (commands, "#testobject1.testattribut=testobject2.name", "TypeOf(testobject1.testattribut) = \"string\" and testobject1.testattribut=\"testobject2\"")
    // ALL TYPES
    dictionary add (commands, "#testobject1.testattribut", "")
    // ----------------------------------------------------------------------------------------------------
    // TESTING
    // Testing the Commands
    // ----------------------------------------------------------------------------------------------------
    iserror = false
    foreach (command, commands) {
      if (not iserror) {
        on ready {
          DevModeOutput ("<br/>&gt; " + command)
          HandleSingleCommand (command)
          on ready {
            compare = ToString(DictionaryItem(commands, command))
            if (compare <> "") {
              result = Eval(compare)
            }
            DevModeOutput ("Quest-Presentation: testobject1.testattribut = " + ToString(testobject1.testattribut))
            if (not result) {
              iserror = true
              DevModeOutputError (Template("DevModeComSelfTestFailed"))
              Log (ToString(ListItem(testobject1.testattribut, 2)))
            }
          }
        }
      }
    }
  ]]></function>
  <function name="InitInterface"><![CDATA[
    // Added by KV for transcript
    // Use JSSafe to remove any offensive characters!  - KV   May 27, 2018
    jsgamename = JSSafe(game.gamename)
    JS.eval ("var gameName = '"+jsgamename+"';var transcriptName = gameName;")
    if (GetBoolean(game,"savetranscript")) {
      JS.eval ("var savingTranscript = true;")
      JS.replaceTranscriptString (game.transcriptstring)
    }
    // End of addition by KV for transcript
    if (game.setcustomwidth) {
      JS.setGameWidth (game.customwidth)
    }
    if (game.setcustompadding) {
      JS.setGamePadding (game.custompaddingtop, game.custompaddingbottom, game.custompaddingleft, game.custompaddingright)
    }
    if (game.externalstylesheets <> null) {
      foreach (stylesheet, game.externalstylesheets) {
        JS.addExternalStylesheet (stylesheet)
      }
    }
    if (game.setbackgroundopacity) {
      SetBackgroundOpacity (game.backgroundopacity)
    }
    SetBackgroundColour (game.defaultbackground)
    SetForegroundColour (game.defaultforeground)
    SetLinkForegroundColour (game.defaultlinkforeground)
    if (LengthOf(game.backgroundimage) > 0) {
      SetBackgroundImage (game.backgroundimage)
    }
    JS.setCompassDirections (Join(game.compassdirections, ";"))
    JS.setInterfaceString ("InventoryLabel", "Inventory")
    JS.setInterfaceString ("StatusLabel", "Status")
    JS.setInterfaceString ("PlacesObjectsLabel", "Places and Objects")
    JS.setInterfaceString ("CompassLabel", "Compass")
    JS.setInterfaceString ("InButtonLabel", "in")
    JS.setInterfaceString ("OutButtonLabel", "out")
    JS.setInterfaceString ("EmptyListLabel", "(empty)")
    JS.setInterfaceString ("NothingSelectedLabel", "(nothing selected)")
    JS.setInterfaceString ("TypeHereLabel", "Type here...")
    JS.setInterfaceString ("ContinueLabel", "Continue...")
    JS.SetMenuBackground (game.menubackground)
    JS.SetMenuForeground (game.menuforeground)
    JS.SetMenuHoverBackground (game.menuhoverbackground)
    JS.SetMenuHoverForeground (game.menuhoverforeground)
    JS.SetMenuFontName (game.menufont)
    JS.SetMenuFontSize (game.menufontsize + "pt")
    if (not game.underlinehyperlinks) {
      JS.TurnOffHyperlinksUnderline ()
    }
    ResetCommandBarFormat
    if (game.showcommandbar) {
      JS.uiShow ("#txtCommandDiv")
    }
    else {
      JS.uiHide ("#txtCommandDiv")
    }
    if (HasString(game, "panelcontents")) {
      SetFramePicture (game.panelcontents)
    }
    if (game.gridmap) {
      JS.ShowGrid (game.mapsize)
      Grid_SetScale (game.mapscale)
      if (game.pov <> null) {
        if (game.pov.parent <> null) {
          Grid_Redraw
          Grid_DrawPlayerInRoom (game.pov.parent)
        }
      }
    }
    // Added by the Pixie
    // Note that panesVisible in playercore.js must be updated too
    // This line will get the save confirmation to appear in the right font and colour
    JS.setCss ("body", "color:" + game.defaultforeground + ";font-family:" + game.defaultfont + ";font-size:" + game.defaultfontsize + "pt;")
    // various new options
    if (HasString(game, "bordercolour")) {
      JS.setCss ("#gameBorder", "border-left:1px solid " + game.bordercolour + ";border-right:1px solid " + game.bordercolour)
    }
    if (not game.classiclocation) {
      JS.setCss ("#status", "background-image:none")
      if (HasString(game, "customlocationcolour")) {
        JS.setCss ("#status", "background-color:" + game.customlocationcolour)
      }
      else {
        JS.setCss ("#status", "background:transparent")
      }
      if (HasString(game, "customlocationtextcolour")) {
        JS.setCss ("#status", "color:" + game.customlocationtextcolour)
      }
      if (HasString(game, "customlocationbordercolour")) {
        JS.setCss ("#status", "border:1px solid " + game.customlocationbordercolour)
      }
      else {
        JS.setCss ("#status", "border:none")
      }
    }
    // request (Show, "Location")
    if (game.showlocation) {
      JS.uiShow ("#location")
      JS.setCss ("#status", "display:block")
    }
    else {
      JS.setCss ("#status", "display:none")
    }
    if (HasString(game, "marginscolour")) {
      JS.setCss ("body", "background-color:" + game.marginscolour)
    }
    if (game.turnoffsavebutton) {
      JS.setCss ("#controlButtons", "display:none")
    }
    if (game.turnoffcompass) {
      JS.setCss ("#compassLabel", "display:none;")
      JS.setCss ("#compassAccordion", "display:none;")
    }
    if (game.turnoffinventory) {
      JS.setCss ("#inventoryLabel", "display:none")
      JS.setCss ("#inventoryAccordion", "display:none")
    }
    if (game.turnoffplacesandobjects) {
      JS.setCss ("#placesObjectsLabel", "display:none")
      JS.setCss ("#placesObjectsAccordion", "display:none")
    }
    if (game.statusandcompassattop) {
      JS.eval ("$('#commandPane').insertBefore('#inventoryLabel')")
      JS.eval ("$('#customStatusPane').insertBefore('#inventoryLabel')")
      JS.eval ("$('#statusVarsLabel').insertBefore('#inventoryLabel')")
      JS.eval ("$('#statusVarsAccordion').insertBefore('#inventoryLabel')")
      JS.eval ("$('#compassLabel').insertBefore('#inventoryLabel')")
      JS.eval ("$('#compassAccordion').insertBefore('#inventoryLabel')")
    }
    if (game.showpanes and game.commandpane) {
      JS.setCss ("#commandPane", "display:block")
    }
    if (game.showpanes and game.customstatuspane) {
      JS.setCss ("#customStatusPane", "display:block")
    }
    if (game.colourblend) {
      JS.colourBlend (game.colourblendtop, game.colourblendbottom)
    }
    if (game.borderlesscursor) {
      JS.addScript ("<style>#txtCommand { outline:none; border:none; margin:0; padding:0; width:100px; background-color:transparent;}</style>")
      JS.setCss ("#txtCommandDiv", "color:" + game.defaultforeground)
      JS.eval ("$('#txtCommandPrompt').html('" + game.commandcursor + "')")
    }
    else if (game.shadowbox) {
      JS.addScript ("<style>#txtCommand { outline:none; border:none; margin:2px; padding:7px; width:100 px;box-shadow: 0px 0px 15px 5px #888;}</style>")
    }
    if (game.panestheme = "Midnight") {
      JS.setPanes ("white", "midnightblue", "midnightblue", "skyblue")
    }
    if (game.panestheme = "Nature") {
      JS.setPanes ("#A1C935", "#254117", "#306754", "#A1C935", "green")
    }
    if (game.panestheme = "Parchment") {
      JS.setPanes ("#493D26", "#FAEBD7", "#FAEBD7", "#493D26", "#C88141")
    }
    if (game.panestheme = "Vanilla") {
      JS.setPanes ("black", "white")
    }
    if (game.panestheme = "Black") {
      JS.setPanes ("orange", "black", "black", "orange")
    }
    if (game.panestheme = "Blood") {
      JS.setPanes ("orange", "#800000", "#800000", "orange", "yellow")
    }
    if (game.panestheme = "Tranquil") {
      JS.setPanes ("midnightblue", "skyblue", "white", "midnightblue", "blue")
    }
    if (game.respondtogridclicks) {
      JS.respondToGridClicks (true)
    }
    //
    // -----------------------------------------------------------------------
    // This is in the original, but must come last
    if (not game.showborder) {
      JS.hideBorder ()
    }
    if (game.showpanes) {
      JS.panesVisible (true)
    }
    else {
      JS.panesVisible (false)
    }
    JS.getDivCount ()
    if (not game.pov = null) {
      JS.updateLocation (CapFirst(GetDisplayName(game.pov.parent)))
    }
    if (game.feature_devmode) {
      setDevMode
    }
    InitUserInterface
    if (HasScript(game, "inituserinterface")) {
      do (game, "inituserinterface")
    }
  ]]></function>
  <function name="InitUserInterface">
  </function>
  <function name="StartGame"><![CDATA[
    StartTurnOutputSection
    if (game.showtitle) {
      JS.StartOutputSection ("title")
      PrintCentered ("<span style=\"font-size:260%\">" + game.gamename + "</span>")
      if (game.subtitle <> null) {
        if (LengthOf(game.subtitle) > 0) {
          PrintCentered ("<span style=\"font-size:130%\">" + game.subtitle + "</span>")
        }
      }
      if (game.author <> null) {
        if (LengthOf(game.author) > 0) {
          PrintCentered ("<br/><span style=\"font-size:140%\">by " + game.author + "</span>")
        }
      }
      msg ("<div style=\"margin-top:20px\"></div>")
      JS.EndOutputSection ("title")
    }
    if (game.pov = null) {
      playerObject = GetObject("player")
      if (playerObject = null) {
        if (ListCount(AllObjects()) > 0) {
          firstRoom = ObjectListItem(AllObjects(), 0)
        }
        else {
          create ("room")
          firstRoom = room
        }
        create ("player")
        player.parent = firstRoom
      }
      game.pov = player
    }
    else {
      InitPOV (null, game.pov)
    }
    InitStatusAttributes
    UpdateStatusAttributes
    InitVerbsList
    if (HasScript(game, "start")) {
      do (game, "start")
    }
    foreach (obj, AllObjects()) {
      if (HasScript(obj, "_initialise_")) {
        do (obj, "_initialise_")
      }
    }
    UpdateStatusAttributes
    UpdateObjectLinks
    on ready {
      if (game.gridmap) {
        Grid_DrawPlayerInRoom (game.pov.parent)
      }
      if (game.displayroomdescriptiononstart) {
        OnEnterRoom (null)
      }
      UpdateStatusAttributes
      UpdateObjectLinks
    }
    // Added by KV to use the old JS clearScreen if the transcript is disabled
    if (GetBoolean(game, "notranscript")) {
      JS.eval ("transcriptEnabled = false;")
    }
    game.runturnscripts = false
    FinishTurn
  ]]></function>
  <function name="InitVerbsList">
    game.verbattributes = NewStringList()
    game.verbattributeslookup = NewObjectDictionary()
    foreach (cmd, AllCommands()) {
      if (HasString(cmd, "property")) {
        list add (game.verbattributes, cmd.property)
        dictionary add (game.verbattributeslookup, cmd.property, cmd)
      }
    }
  </function>
  <function name="GetDisplayVerbs" parameters="object" type="stringlist">
    if (Contains(game.pov, object)) {
      baselist = object.inventoryverbs
    }
    else {
      baselist = object.displayverbs
    }
    if (not game.autodisplayverbs or GetBoolean(object, "usestandardverblist") or not HasAttribute(game, "verbattributes")) {
      return (baselist)
    }
    else {
      if (HasAttribute(object, "generatedverbslist")) {
        verbs = object.generatedverbslist
      }
      else {
        verbs = NewStringList()
        foreach (attr, GetAttributeNames(object, false)) {
          if (ListContains(game.verbattributes, attr)) {
            cmd = ObjectDictionaryItem(game.verbattributeslookup, attr)
            if (HasString(cmd, "displayverb")) {
              displayverb = CapFirst(cmd.displayverb)
            }
            else {
              displayverb = CapFirst(attr)
            }
            if (not ListContains(baselist, displayverb)) {
              list add (verbs, displayverb)
            }
          }
        }
        object.generatedverbslist = verbs
      }
      if (GetBoolean(object, "useindividualverblist")) {
        return (verbs)
      }
      else {
        return (ListCombine(baselist, verbs))
      }
    }
  </function>
  <function name="InitPOV" parameters="oldPOV, newPOV"><![CDATA[
    if (oldPOV <> null) {
      oldPOV.alias = oldPOV.external_alias
      oldPOV.alt = oldPOV.external_alt
      oldPOV.look = oldPOV.external_look
      oldPOV.gender = oldPOV.external_gender
      oldPOV.article = oldPOV.external_article
    }
    newPOV.external_alias = newPOV.alias
    newPOV.external_alt = newPOV.alt
    newPOV.external_look = newPOV.look
    newPOV.external_gender = newPOV.gender
    newPOV.external_article = newPOV.article
    if (not GetBoolean(newPOV, "pov_used")) {
      if (newPOV.alt = null) {
        newPOV.pov_alt = newPOV.pov_alt
      }
      else {
        newPOV.pov_alt = ListCombine(newPOV.alt, newPOV.pov_alt)
      }
      if (newPOV.alias <> null) {
        list add (newPOV.pov_alt, newPOV.alias)
      }
      if (game.showmoney and not HasInt(newPOV, "money")) {
        newPOV.money = 0
      }
      if (game.showhealth) {
        newPOV.health = 100
        newPOV.changedhealth => {
          if (this.health > 100) {
            this.health = 100
          }
          else if (this.health = 0) {
            if (HasScript(game, "onhealthzero")) {
              do (game, "onhealthzero")
            }
          }
          else if (this.health < 0) {
            this.health = 0
            // changedhealth will be called again so the onhealthzero script will run
          }
        }
      }
      newPOV.pov_used = true
    }
    newPOV.alias = newPOV.pov_alias
    newPOV.alt = newPOV.pov_alt
    newPOV.look = newPOV.pov_look
    newPOV.gender = newPOV.pov_gender
    newPOV.article = newPOV.pov_article
  ]]></function>
  <function name="FinishTurn">
    if (GetBoolean(game,"runturnscripts")) {
      if (not GetBoolean(game, "suppressturnscripts")) {
        RunTurnScripts
      }
    }
    game.runturnscripts = false
    game.suppressturnscripts = false
    UpdateStatusAttributes
    CheckDarkness
    UpdateObjectLinks
  </function>
  <function name="WhereAmI" parameters="s">
    game.questplatform = s
  </function>
</asl>