← All the games

Delve

All of Delve is here, in Quantum's game language: delve.q, compiled for Godot 4.4.1, with no script besides. Point at a tag or an attribute to see what it does; a tag opens its entry in the language's reference.

Play in the browser
The 57 tags it uses, of the language's 145 qg:animation qg:behavior qg:button qg:camera qg:camera-to qg:character qg:continue qg:counter qg:destroy qg:emit qg:emitter qg:fullscreen qg:goto-scene qg:hud qg:instance qg:inventory qg:item qg:keep-distance qg:language qg:leave qg:light qg:lobby qg:menu qg:multiplayer qg:music qg:next-language qg:on-animation-end qg:on-collision qg:on-hit qg:on-input qg:particles qg:phrase qg:play qg:prefab qg:rebind qg:reset-items qg:scene qg:seek qg:set-tile qg:shake qg:shoot qg:slider qg:sound qg:sprite qg:spritesheet qg:swap qg:take qg:text qg:tile qg:tilemap qg:tileset qg:timer qg:touch-button qg:touch-stick qg:tween qg:wander qg:when
delve.q568 lines Download On GitHub
<q:application id="delve" type="game">  <!-- Delve: a dungeon crawl for one delver, or two over the network.       Three crypts, down and down: a wall a lever opens (qg:set-tile), and       the skeletons behind it that find their way through as soon as it does       (ai="pathfind"); crushers that slide to and fro (qg:tween); a vault       two levers keep shut, and its treasure, in the dark (ambient=): its       torches and the delvers' lanterns light it and its pillars cast shadows       (qg:light). Torches burn and gems sparkle (qg:particles). A skeleton archer, made of parts, keeps its distance and       shoots. The hearts and the gems are what the delvers carry       (qg:item), shown by the HUD's inventory. Each crypt entered is saved (Continue, alone); the       game speaks English, Portuguese and Spanish. The art is drawn for it by       scripts/art/delve.py and the music written by scripts/art/delve_music.py       (CC0); the sounds are Kenney's (CC0). -->  <!-- The delve's state, kept from crypt to crypt; the first crypt starts it anew. -->  <q:set name="message" value="" />  <!-- a hurt, the same in every crypt: a function of the game -->  <q:function name="hurt" params="me">    <qg:play sound="hurt" vary="0.1" />    <qg:shake at="me" frames="8" strength="2" />    <qg:take item="heart" />    <q:if condition="{held('heart') <= 0}">      <qg:goto-scene name="fallen" fade="0.6" />    </q:if>  </q:function>  <!-- Two players, each on their own machine: the delve starts in crypt-1 once both are there. -->  <qg:multiplayer players="2" start="crypt-1" />  <!-- 1 is the floor and 12 the rubble of a wall broken open (walked on); 2 the wall, 3 a wall with a torch. -->  <qg:tileset name="crypt" src="assets/crypt.png" tile="18">    <qg:tile frame="0" shape="none" />    <qg:tile frame="11" shape="none" />  </qg:tileset>  <qg:spritesheet name="delvers" src="assets/delvers.png" tile="24" />  <qg:sound bus="effects" name="hit" src="assets/kenney/audio/stomp.ogg" />  <qg:sound bus="effects" name="hurt" src="assets/kenney/audio/hurt.ogg" />  <qg:sound bus="effects" name="pick" src="assets/kenney/audio/coin.ogg" />  <qg:sound bus="effects" name="heal" src="assets/kenney/audio/powerup.ogg" />  <qg:sound bus="effects" name="open" src="assets/kenney/audio/block.ogg" />  <qg:sound bus="effects" name="win" src="assets/kenney/audio/win.ogg" />  <qg:sound bus="effects" name="twang" src="assets/kenney/audio/jump.ogg" />  <qg:sound bus="music" name="torchlight" src="assets/torchlight.ogg" loop="true" />  <qg:sound bus="music" name="crypt" src="assets/crypt.ogg" loop="true" />  <qg:sound bus="music" name="warden" src="assets/warden.ogg" loop="true" />  <!-- a skeleton falling apart: one of three, so no two fall alike -->  <qg:sound bus="effects" name="bones1" src="assets/bones1.ogg" />  <qg:sound bus="effects" name="bones2" src="assets/bones2.ogg" />  <qg:sound bus="effects" name="bones3" src="assets/bones3.ogg" />  <!-- effects: only seen, the game's state never depends on them -->  <qg:particles name="torch" preset="fire" amount="20" size="3" lifetime="0.7" speed="30" />  <qg:particles name="sparkle" preset="stars" color="#a8f0ff" />  <qg:particles name="glow" preset="sparks" color="#ff8098" amount="12" />  <qg:particles name="slain" preset="smoke" color="#c8c0b0" />  <qg:particles name="rumble" preset="dust" color="#8a8098" amount="30" speed="60" size="3" />  <qg:particles name="treasure" preset="confetti" />  <qg:particles name="dust" preset="snow" color="#6a6478" amount="16" speed="8" size="1" />  <!-- What the delvers carry, kept from crypt to crypt and in a save: hearts (five at most; one       less at each wound, and none is the fall) and gems. A heart picked up at five stays where it is. -->  <qg:item name="heart" label="HEARTS" sheet="crypt" frame="6" start="5" max="5" sound="heal" particles="glow" />  <qg:item name="gem" label="GEMS" sheet="crypt" frame="5" sound="pick" particles="sparkle" />  <qg:prefab name="Gem" tag="gem" sheet="crypt" frame="5" hitbox="10x12" gives="gem" />  <qg:prefab name="Heart" tag="heart" sheet="crypt" frame="6" hitbox="12x12" gives="heart" />  <qg:prefab name="Lever" tag="lever" sheet="crypt" frame="3" hitbox="14x14" />  <qg:prefab name="LeverOn" tag="lever-on" sheet="crypt" frame="4" hitbox="14x14" />  <qg:prefab name="Stairs" tag="stairs" sheet="crypt" frame="8" hitbox="10x10" />  <qg:prefab name="Slab" tag="slab" sheet="crypt" frame="9" hitbox="16x16" />  <qg:prefab name="Chest" tag="chest" sheet="crypt" frame="7" hitbox="16x16" />  <qg:prefab name="Skeleton" tag="enemy" sheet="delvers" frame="20" hitbox="12x14"             ai="pathfind" speed="30" sight="400">    <qg:animation name="walk" frames="20,21,20,22" fps="6" />  </qg:prefab>  <!-- a slain skeleton falls to a heap of bones, once, and the heap goes up in smoke -->  <qg:prefab name="Fallen" tag="fallen" sheet="delvers" frame="26" hitbox="8x8">    <qg:animation name="walk" frames="26,27,28,28,28" fps="8" loop="false" />    <qg:on-animation-end name="walk">      <qg:emit particles="slain" at="me" />      <qg:destroy target="me" />    </qg:on-animation-end>  </qg:prefab>  <!-- a bat flutters about until it sees a delver, then dives at it -->  <qg:prefab name="Bat" tag="enemy" sheet="delvers" frame="23" hitbox="14x12"             ai="behavior" speed="42" sight="110">    <qg:animation name="walk" frames="23,24,25,24" fps="10" />    <qg:behavior>      <qg:seek way="straight" />      <qg:wander speed="16" />    </qg:behavior>  </qg:prefab>  <!-- an enemy made of parts: it keeps its distance from the nearest delver it sees, shoots       at one within range, and wanders while it sees none -->  <qg:prefab name="Archer" tag="enemy" sheet="delvers" frame="29" hitbox="12x14"             ai="behavior" speed="26" sight="150">    <qg:animation name="walk" frames="29,30,29,31" fps="6" />    <qg:behavior>      <qg:keep-distance min="54" max="90" />      <qg:shoot prefab="Arrow" every="90" range="130" sound="twang" />      <qg:wander speed="12" />    </qg:behavior>  </qg:prefab>  <qg:prefab name="Arrow" tag="arrow" sheet="delvers" frame="32" hitbox="6x4"             ai="fly" speed="100" walls="stop" rotate="true" lifetime="180" />  <!-- the game in Portuguese and Spanish (a web page's ?lang=pt, the command line's q-lang, or the system's language) -->    <!-- on a phone: what the keys do, under a finger, in every scene -->  <qg:touch-stick x="40" y="184" />  <qg:touch-button action="jump" label="A" x="220" y="184" />  <qg:language lang="pt" name="Português">    <qg:phrase text="HEARTS" as="CORAÇÕES" />    <qg:phrase text="GEMS" as="GEMAS" />    <qg:phrase text="Play alone" as="Jogar sozinho" />    <qg:phrase text="Play together" as="Jogar junto" />    <qg:phrase text="Continue" as="Continuar" />    <qg:phrase text="Language" as="Idioma" />    <qg:phrase text="Try again" as="Tentar de novo" />    <qg:phrase text="To the title" as="Voltar ao início" />    <qg:phrase text="DOWN TO THE VAULT, ALONE OR WITH A FRIEND" as="ATÉ O COFRE, SOZINHO OU COM UM AMIGO" />    <qg:phrase text="TWO DELVERS, TWO MACHINES. ESCAPE: BACK." as="DOIS EXPLORADORES, DUAS MÁQUINAS. ESC: VOLTAR." />    <qg:phrase text="A SEALED WALL. A LEVER MUST OPEN IT." as="UMA PAREDE SELADA. UMA ALAVANCA DEVE ABRI-LA." />    <qg:phrase text="THE WALL OPENS. THE DEAD WAKE." as="A PAREDE SE ABRE. OS MORTOS DESPERTAM." />    <qg:phrase text="THE CRUSHERS. MIND THEIR TIME." as="OS ESMAGADORES. ATENÇÃO AO TEMPO DELES." />    <qg:phrase text="THE VAULT. TWO LEVERS HOLD IT SHUT." as="O COFRE. DUAS ALAVANCAS O MANTÊM FECHADO." />    <qg:phrase text="ONE MORE LEVER." as="FALTA UMA ALAVANCA." />    <qg:phrase text="THE VAULT IS OPEN." as="O COFRE ESTÁ ABERTO." />    <qg:phrase text="THE VAULT IS YOURS." as="O COFRE É SEU." />    <qg:phrase text="THE CRYPT KEEPS YOU." as="A CRIPTA FICA COM VOCÊ." />      <qg:phrase text="Options" as="Opções" />    <qg:phrase text="OPTIONS" as="OPÇÕES" />    <qg:phrase text="Music" as="Música" />    <qg:phrase text="Sounds" as="Sons" />    <qg:phrase text="Full screen" as="Tela cheia" />    <qg:phrase text="on" as="sim" />    <qg:phrase text="off" as="não" />    <qg:phrase text="Back" as="Voltar" />    <qg:phrase text="Sword" as="Espada" /></qg:language>  <qg:language lang="es" name="Español">    <qg:phrase text="HEARTS" as="CORAZONES" />    <qg:phrase text="GEMS" as="GEMAS" />    <qg:phrase text="Play alone" as="Jugar solo" />    <qg:phrase text="Play together" as="Jugar juntos" />    <qg:phrase text="Continue" as="Continuar" />    <qg:phrase text="Language" as="Idioma" />    <qg:phrase text="Try again" as="Intentar de nuevo" />    <qg:phrase text="To the title" as="Volver al inicio" />    <qg:phrase text="DOWN TO THE VAULT, ALONE OR WITH A FRIEND" as="HASTA LA BÓVEDA, SOLO O CON UN AMIGO" />    <qg:phrase text="TWO DELVERS, TWO MACHINES. ESCAPE: BACK." as="DOS EXPLORADORES, DOS MÁQUINAS. ESC: VOLVER." />    <qg:phrase text="A SEALED WALL. A LEVER MUST OPEN IT." as="UN MURO SELLADO. UNA PALANCA DEBE ABRIRLO." />    <qg:phrase text="THE WALL OPENS. THE DEAD WAKE." as="EL MURO SE ABRE. LOS MUERTOS DESPIERTAN." />    <qg:phrase text="THE CRUSHERS. MIND THEIR TIME." as="LOS APLASTADORES. CUIDA SU RITMO." />    <qg:phrase text="THE VAULT. TWO LEVERS HOLD IT SHUT." as="LA BÓVEDA. DOS PALANCAS LA MANTIENEN CERRADA." />    <qg:phrase text="ONE MORE LEVER." as="FALTA UNA PALANCA." />    <qg:phrase text="THE VAULT IS OPEN." as="LA BÓVEDA ESTÁ ABIERTA." />    <qg:phrase text="THE VAULT IS YOURS." as="LA BÓVEDA ES TUYA." />    <qg:phrase text="THE CRYPT KEEPS YOU." as="LA CRIPTA SE QUEDA CONTIGO." />      <qg:phrase text="Options" as="Opciones" />    <qg:phrase text="OPTIONS" as="OPCIONES" />    <qg:phrase text="Music" as="Música" />    <qg:phrase text="Sounds" as="Sonidos" />    <qg:phrase text="Full screen" as="Pantalla completa" />    <qg:phrase text="on" as="sí" />    <qg:phrase text="off" as="no" />    <qg:phrase text="Back" as="Volver" />    <qg:phrase text="Sword" as="Espada" /></qg:language>  <!-- ===== The title: alone, together, or the saved delve ===== -->  <qg:scene name="title" width="256" height="224" background="#16141e">    <qg:music sound="torchlight" />    <qg:sprite sheet="delvers" frame="0" x="34" y="150" gd:scale="2,2" />    <qg:sprite sheet="delvers" frame="10" x="222" y="150" gd:scale="2,2" gd:flip_h="true" />    <qg:emitter particles="torch" x="34" y="100" />    <qg:emitter particles="torch" x="222" y="100" />    <qg:emitter particles="dust" x="128" y="0" width="256" />    <qg:hud position="top-center" size="32"><qg:text value="{'DELVE'}" /></qg:hud>    <qg:hud position="bottom-center" size="10"><qg:text value="{tr('DOWN TO THE VAULT, ALONE OR WITH A FRIEND')}" /></qg:hud>    <qg:menu position="center">      <qg:button label="Play alone"><qg:goto-scene name="crypt-1" fade="0.4" /></qg:button>      <qg:button label="Play together"><qg:goto-scene name="together" /></qg:button>      <qg:button label="Continue" if="{has_save()}"><qg:continue /></qg:button>      <qg:button label="Options"><qg:goto-scene name="options" /></qg:button>      <qg:button label="{tr('Language') + ': ' + language()}"><qg:next-language /></qg:button>    </qg:menu>  </qg:scene>  <!-- Two machines: one hosts, the other joins its address; the delve starts in crypt-1. -->  <qg:scene name="together" width="256" height="224" background="#16141e">    <qg:music sound="torchlight" />    <qg:hud position="top-center" size="10"><qg:text value="{tr('TWO DELVERS, TWO MACHINES. ESCAPE: BACK.')}" /></qg:hud>    <qg:lobby local="crypt-1" local-label="Play alone" size="12" />    <qg:on-input action="cancel">      <qg:leave />      <qg:goto-scene name="title" />    </qg:on-input>  </qg:scene>  <!-- ===== Crypt 1: a sealed wall, and what waits behind it. Down the stairs to crypt 2. ===== -->  <qg:scene name="crypt-1" width="256" height="224" background="#100e16" seed="1" save="true">    <qg:music sound="crypt" />    <!-- the delve starts here anew: five hearts, no gems, every gem back in its place -->    <q:function name="anew" params=""><qg:reset-items /></q:function>    <q:call function="anew" />    <q:set name="message" value="A SEALED WALL. A LEVER MUST OPEN IT." />    <q:set name="leaving" value="false" type="boolean" />    <q:function name="slay" params="foe">      <qg:play sound="hit" vary="0.15" />      <qg:play sounds="bones1, bones2, bones3" vary="0.1" />      <qg:swap target="foe" prefab="Fallen" />    </q:function>    <q:function name="pull" params="lever">      <qg:play sound="open" pitch="0.75" />      <qg:swap target="lever" prefab="LeverOn" />      <qg:set-tile col="8" row="5" tile="12" />      <qg:set-tile col="8" row="6" tile="12" />      <qg:emit particles="rumble" at="lever" dx="72" dy="-63" />      <!-- the camera goes to show the gap, and back; the dead do not wait for it -->      <qg:camera-to x="153" y="108" zoom="2" seconds="0.4" hold="0.6" pause="false" />      <q:set name="message" value="THE WALL OPENS. THE DEAD WAKE." />    </q:function>    <q:function name="down" params="">      <q:if condition="{not leaving}">        <q:set name="leaving" value="true" />        <qg:goto-scene name="crypt-2" fade="0.5" />      </q:if>    </q:function>    <qg:tilemap tileset="crypt" collision="true">2,2,2,2,2,2,2,2,2,2,2,2,2,22,1,1,1,1,1,1,1,2,1,1,1,1,22,1,1,1,1,1,1,1,3,1,1,1,1,23,1,1,1,1,1,1,1,2,1,1,1,1,32,1,1,1,1,1,1,1,2,1,1,1,1,22,1,1,1,1,1,1,1,2,1,1,1,1,22,1,1,1,1,1,1,1,2,1,1,1,1,22,1,1,1,1,1,1,1,2,1,1,1,1,23,1,1,1,1,1,1,1,2,1,1,1,1,32,1,1,1,1,1,1,1,2,1,1,1,1,22,1,1,1,1,1,1,1,2,1,1,1,1,22,2,2,2,2,2,2,2,2,2,2,2,2,2    </qg:tilemap>    <qg:emitter particles="torch" x="9" y="57" />    <qg:emitter particles="torch" x="9" y="147" />    <qg:emitter particles="torch" x="243" y="57" />    <qg:emitter particles="torch" x="243" y="147" />    <qg:emitter particles="torch" x="153" y="39" />    <qg:character id="p1" controller="topdown" player="1" sheet="delvers" frame="0"                  x="45" y="99" hitbox="12x14" speed="70"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:animation name="idle" frames="0" />      <qg:animation name="walk" frames="1,2" fps="8" />      <qg:animation name="walk-up" frames="3,4" fps="8" />      <qg:animation name="walk-down" frames="5,6" fps="8" />      <qg:animation name="attack" frames="7" />      <qg:animation name="attack-up" frames="8" />      <qg:animation name="attack-down" frames="9" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="lever"><q:call function="pull" args="other" /></qg:on-collision>      <qg:on-collision with="stairs"><q:call function="down" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <qg:character id="p2" controller="topdown" player="2" sheet="delvers" frame="10"                  x="45" y="135" hitbox="12x14" speed="70" if="{net_status() != 'offline'}"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:animation name="idle" frames="10" />      <qg:animation name="walk" frames="11,12" fps="8" />      <qg:animation name="walk-up" frames="13,14" fps="8" />      <qg:animation name="walk-down" frames="15,16" fps="8" />      <qg:animation name="attack" frames="17" />      <qg:animation name="attack-up" frames="18" />      <qg:animation name="attack-down" frames="19" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="lever"><q:call function="pull" args="other" /></qg:on-collision>      <qg:on-collision with="stairs"><q:call function="down" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <qg:camera follow="p1" bounds="tilemap" />    <qg:instance prefab="Lever" name="lever" x="81" y="171" />    <qg:instance prefab="Gem" name="gem-1" x="99" y="45" />    <qg:instance prefab="Gem" name="gem-2" x="117" y="153" />    <qg:instance prefab="Gem" name="gem-3" x="225" y="45" />    <qg:instance prefab="Skeleton" name="skeleton-1" x="190" y="72" />    <qg:instance prefab="Skeleton" name="skeleton-2" x="190" y="144" />    <qg:instance prefab="Stairs" name="stairs" x="225" y="171" />    <qg:hud position="top-left" size="10">      <qg:inventory />      <qg:text bind="message" />    </qg:hud>  </qg:scene>  <!-- ===== Crypt 2: three crushers slide across the way. Down the stairs to crypt 3. ===== -->  <qg:scene name="crypt-2" width="256" height="224" background="#100e16" seed="2" save="true">    <qg:music sound="crypt" />    <q:set name="message" value="THE CRUSHERS. MIND THEIR TIME." />    <q:set name="leaving" value="false" type="boolean" />    <q:function name="slay" params="foe">      <qg:play sound="hit" vary="0.15" />      <qg:play sounds="bones1, bones2, bones3" vary="0.1" />      <qg:emit particles="slain" at="foe" />      <qg:destroy target="foe" />    </q:function>    <q:function name="down" params="">      <q:if condition="{not leaving}">        <q:set name="leaving" value="true" />        <qg:goto-scene name="crypt-3" fade="0.5" />      </q:if>    </q:function>    <qg:tilemap tileset="crypt" collision="true">2,2,2,2,2,2,2,2,2,2,2,2,2,22,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,23,1,1,1,1,1,1,1,1,1,1,1,1,32,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,23,1,1,1,1,1,1,1,1,1,1,1,1,32,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,22,2,2,2,2,2,2,2,2,2,2,2,2,2    </qg:tilemap>    <qg:emitter particles="torch" x="9" y="57" />    <qg:emitter particles="torch" x="9" y="147" />    <qg:emitter particles="torch" x="243" y="57" />    <qg:emitter particles="torch" x="243" y="147" />    <qg:character id="p1" controller="topdown" player="1" sheet="delvers" frame="0"                  x="27" y="99" hitbox="12x14" speed="70"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:animation name="idle" frames="0" />      <qg:animation name="walk" frames="1,2" fps="8" />      <qg:animation name="walk-up" frames="3,4" fps="8" />      <qg:animation name="walk-down" frames="5,6" fps="8" />      <qg:animation name="attack" frames="7" />      <qg:animation name="attack-up" frames="8" />      <qg:animation name="attack-down" frames="9" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="slab" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="stairs"><q:call function="down" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <qg:character id="p2" controller="topdown" player="2" sheet="delvers" frame="10"                  x="27" y="135" hitbox="12x14" speed="70" if="{net_status() != 'offline'}"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:animation name="idle" frames="10" />      <qg:animation name="walk" frames="11,12" fps="8" />      <qg:animation name="walk-up" frames="13,14" fps="8" />      <qg:animation name="walk-down" frames="15,16" fps="8" />      <qg:animation name="attack" frames="17" />      <qg:animation name="attack-up" frames="18" />      <qg:animation name="attack-down" frames="19" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="slab" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="stairs"><q:call function="down" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <!-- the crushers: each slides from one wall to the other and back, for ever, at its own pace -->    <qg:instance prefab="Slab" name="slab-1" x="81" y="27" />    <qg:instance prefab="Slab" name="slab-2" x="135" y="189" />    <qg:instance prefab="Slab" name="slab-3" x="189" y="27" />    <qg:timer after="1">      <qg:tween target="slab-1" property="y" to="189" seconds="1.6" trans="sine" ease="in-out" repeat="-1" yoyo="true" />      <qg:tween target="slab-2" property="y" to="27" seconds="1.2" trans="sine" ease="in-out" repeat="-1" yoyo="true" />      <qg:tween target="slab-3" property="y" to="189" seconds="2" trans="sine" ease="in-out" repeat="-1" yoyo="true" />    </qg:timer>    <qg:instance prefab="Heart" name="heart-1" x="162" y="108" />    <qg:instance prefab="Gem" name="gem-4" x="108" y="189" />    <qg:instance prefab="Gem" name="gem-5" x="162" y="45" />    <qg:instance prefab="Bat" name="bat-1" x="216" y="54" />    <qg:instance prefab="Bat" name="bat-2" x="216" y="171" />    <qg:instance prefab="Stairs" name="stairs" x="225" y="117" />    <qg:hud position="top-left" size="10">      <qg:inventory />      <qg:text bind="message" />    </qg:hud>  </qg:scene>  <!-- ===== Crypt 3: the vault, which two levers keep shut. ===== -->  <!-- The vault is dark (ambient=): what the torches and the delvers' lanterns light, and the walls cast       their shadows. Only seen: the game is the same in the dark. -->  <qg:scene name="crypt-3" width="256" height="224" background="#100e16" seed="3" save="true" ambient="#1c1828">    <qg:music sound="crypt" />    <q:set name="message" value="THE VAULT. TWO LEVERS HOLD IT SHUT." />    <q:set name="pulled" value="0" type="number" />    <q:set name="won" value="false" type="boolean" />    <!-- The warden, the skeleton archer: its fight has a theme of its own, from         when it first sees a delver until it falls (the music changes in the         scene; what is heard only, so the game is the same). -->    <qg:when condition="{distance(archer, p1) &lt; 110 or distance(archer, p2) &lt; 110}">      <qg:music sound="warden" fade="0.5" />    </qg:when>    <q:function name="slay" params="foe">      <qg:play sound="hit" vary="0.15" />      <qg:play sounds="bones1, bones2, bones3" vary="0.1" />      <q:if condition="{foe.name == 'archer'}"><qg:music sound="crypt" fade="2" /></q:if>      <qg:swap target="foe" prefab="Fallen" />    </q:function>    <q:function name="pull" params="lever">      <qg:play sound="open" pitch="0.75" />      <qg:swap target="lever" prefab="LeverOn" />      <q:set name="pulled" value="{pulled + 1}" />      <q:if condition="{pulled == 2}">        <qg:set-tile col="6" row="8" tile="12" />        <qg:set-tile col="7" row="8" tile="12" />        <qg:emit particles="rumble" at="chest" dy="-27" />        <q:set name="message" value="THE VAULT IS OPEN." />      <q:else>        <q:set name="message" value="ONE MORE LEVER." />      </q:else>      </q:if>    </q:function>    <q:function name="treasure" params="it">      <q:if condition="{not won}">        <q:set name="won" value="true" />        <qg:play sound="win" />        <qg:emit particles="treasure" at="it" />        <q:set name="message" value="THE VAULT IS YOURS." />        <qg:goto-scene name="the-end" fade="1.5" />      </q:if>    </q:function>    <qg:tilemap tileset="crypt" collision="true">2,2,2,2,2,2,2,2,2,2,2,2,2,22,1,1,1,1,1,1,1,1,1,1,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,23,1,1,1,1,1,1,1,1,1,1,1,1,32,1,1,2,1,1,1,1,1,1,2,1,1,22,1,1,2,1,1,1,1,1,1,2,1,1,22,1,1,2,1,1,1,1,1,1,2,1,1,22,1,1,1,1,1,1,1,1,1,1,1,1,22,2,2,2,2,3,2,2,3,2,2,2,2,22,2,2,2,2,1,1,1,1,2,2,2,2,22,2,2,2,2,1,1,1,1,2,2,2,2,22,2,2,2,2,2,2,2,2,2,2,2,2,2    </qg:tilemap>    <qg:emitter particles="torch" x="9" y="57" />    <qg:emitter particles="torch" x="243" y="57" />    <qg:emitter particles="torch" x="99" y="147" />    <qg:emitter particles="torch" x="153" y="147" />    <!-- each torch's light, just off its wall, flickering as a flame; and the treasure's glow in the vault -->    <qg:light x="24" y="63" radius="72" color="#ffa850" energy="1.4" flicker="0.25" shadows="true" />    <qg:light x="232" y="63" radius="72" color="#ffa850" energy="1.4" flicker="0.25" shadows="true" />    <qg:light x="99" y="138" radius="64" color="#ffa850" energy="1.4" flicker="0.25" shadows="true" />    <qg:light x="153" y="138" radius="64" color="#ffa850" energy="1.4" flicker="0.25" shadows="true" />    <qg:light x="126" y="176" radius="40" color="#ffd860" energy="1.4" shadows="true" />    <qg:character id="p1" controller="topdown" player="1" sheet="delvers" frame="0"                  x="45" y="45" hitbox="12x14" speed="70"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:light radius="52" color="#fff0d8" shadows="true" />   <!-- a lantern -->      <qg:animation name="idle" frames="0" />      <qg:animation name="walk" frames="1,2" fps="8" />      <qg:animation name="walk-up" frames="3,4" fps="8" />      <qg:animation name="walk-down" frames="5,6" fps="8" />      <qg:animation name="attack" frames="7" />      <qg:animation name="attack-up" frames="8" />      <qg:animation name="attack-down" frames="9" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="lever"><q:call function="pull" args="other" /></qg:on-collision>      <qg:on-collision with="chest"><q:call function="treasure" args="other" /></qg:on-collision>      <qg:on-collision with="arrow"><qg:destroy target="other" /><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <qg:character id="p2" controller="topdown" player="2" sheet="delvers" frame="10"                  x="207" y="45" hitbox="12x14" speed="70" if="{net_status() != 'offline'}"                  attack-action="jump" attack-reach="16" attack-frames="12" attack-sound="hit">      <qg:light radius="52" color="#fff0d8" shadows="true" />   <!-- a lantern -->      <qg:animation name="idle" frames="10" />      <qg:animation name="walk" frames="11,12" fps="8" />      <qg:animation name="walk-up" frames="13,14" fps="8" />      <qg:animation name="walk-down" frames="15,16" fps="8" />      <qg:animation name="attack" frames="17" />      <qg:animation name="attack-up" frames="18" />      <qg:animation name="attack-down" frames="19" />      <qg:on-collision with="enemy" cooldown="60"><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-collision with="lever"><q:call function="pull" args="other" /></qg:on-collision>      <qg:on-collision with="chest"><q:call function="treasure" args="other" /></qg:on-collision>      <qg:on-collision with="arrow"><qg:destroy target="other" /><q:call function="hurt" args="me" /></qg:on-collision>      <qg:on-hit with="enemy"><q:call function="slay" args="other" /></qg:on-hit>    </qg:character>    <qg:instance prefab="Lever" name="lever-west" x="27" y="135" />    <qg:instance prefab="Lever" name="lever-east" x="225" y="135" />    <qg:instance prefab="Chest" name="chest" x="126" y="180" />    <qg:timer after="1">      <qg:tween target="chest" property="y" to="176" seconds="0.8" trans="sine" ease="in-out" repeat="-1" yoyo="true" />    </qg:timer>    <qg:instance prefab="Gem" name="gem-6" x="225" y="27" />    <qg:instance prefab="Gem" name="gem-7" x="126" y="99" />    <qg:instance prefab="Skeleton" name="skeleton-1" x="126" y="63" />    <qg:instance prefab="Skeleton" name="skeleton-2" x="81" y="117" />    <qg:instance prefab="Skeleton" name="skeleton-3" x="171" y="117" />    <qg:instance prefab="Archer" name="archer" x="207" y="81" />    <qg:hud position="top-left" size="10">      <qg:inventory />      <qg:text bind="message" />    </qg:hud>  </qg:scene>  <!-- ===== The end, and the fall ===== -->  <qg:scene name="the-end" width="256" height="224" background="#141020">    <qg:music sound="torchlight" />    <qg:emitter particles="treasure" x="128" y="150" />    <qg:sprite sheet="crypt" frame="7" x="128" y="120" gd:scale="3,3" />    <qg:hud position="top-center" size="16">      <qg:text bind="message" />      <qg:counter item="gem" label="GEMS" />    </qg:hud>    <qg:menu position="bottom-center">      <qg:button label="To the title"><qg:leave /><qg:goto-scene name="title" /></qg:button>    </qg:menu>  </qg:scene>  <qg:scene name="fallen" width="256" height="224" background="#000000">    <qg:emitter particles="dust" x="128" y="0" width="256" />    <qg:hud position="top-center" size="16"><qg:text value="{tr('THE CRYPT KEEPS YOU.')}" /></qg:hud>    <qg:menu position="center">      <!-- alone: back to the start of the crypt where the delver fell (it was saved on entering);           together: from the first crypt, on both machines -->      <qg:button label="Try again">        <q:if condition="{net_status() == 'offline' and has_save()}">          <qg:continue />        <q:else>          <qg:goto-scene name="crypt-1" />        </q:else>        </q:if>      </qg:button>      <qg:button label="To the title"><qg:leave /><qg:goto-scene name="title" /></qg:button>    </qg:menu>  </qg:scene>  <!-- ===== Options: how loud, the full screen, the keys; kept between runs ===== -->  <qg:scene name="options" width="256" height="224" background="#16141e">    <qg:hud position="top-center" size="24"><qg:text value="{tr('OPTIONS')}" /></qg:hud>    <qg:menu position="center" size="12">      <qg:slider label="Music" bus="music" />      <qg:slider label="Sounds" bus="effects" />      <qg:button label="{tr('Full screen') + ': ' + (tr('on') if fullscreen() else tr('off'))}"><qg:fullscreen /></qg:button>      <qg:rebind label="Sword" action="jump" />      <qg:button label="Back"><qg:goto-scene name="title" /></qg:button>    </qg:menu>  </qg:scene></q:application>