<world>
    <textures>
        <texture name="picture1">
	    <file>/cellib/images/to_the_tavern.jpg</file>
	    <keepimage />
        </texture>
    </textures>
    <materials>
	<material name="picture1"> <texture>picture1</texture> </material>
    </materials>
    <sounds>
        <sound name="click" file="/cellib/sounds/click_x.wav" mode3d="disable" />
    </sounds>
    <settings>
        <clearscreen>yes</clearscreen>
        <clearzbuf>yes</clearzbuf>
    </settings>
    <plugins>
        <plugin name="celentity">cel.addons.celentity</plugin>
        <plugin name="xmlscripts">cel.addons.xmlscripts</plugin>
    </plugins>

    <addon plugin="xmlscripts">
        <pcfactory>cel.pcfactory.billboard</pcfactory>
        <pcfactory>cel.pcfactory.properties</pcfactory>
        <pcfactory>cel.pcfactory.timer</pcfactory>

	<!-- *****************************************************
	  -  *****************************************************
	  - This is the puzzle game script.
	  -  *****************************************************
	  -  ***************************************************** -->
	<script name="puzzle_main">
	    <!--
	      - Initialize the puzzle game.
	      - The main puzzle entity maintains various variables to
	      - keep board state:
	      -    - grid<x>_<y>: an 2D array containing the name of the tile entity
	      -      at location x,y. Or '' if this is the empty tile.
	      -    - emptyx, emptyy: the location of the empty tile.
	      -    - allowmove: if true the player can move tiles.
	      -    - shuffle_count: if greater than 0 then we are randomizing the board.
	      -    - speed: a float indicating the speed with which tiles should move.
	      -    - dimension: the board size.
	      -    - tiledim: size of one tile.
	      -    - tiledimuv: size of one tile in texture coordinates.
	      -->
	    <event name="init">
		<!-- Set some defaults -->
		<!--
		<var name="dimension" value="4" />
		<var name="tiledim" value="70000" />
		<var name="tiledimuv" value=".25" />
		<var name="shuffle_count" value="30" />
		-->
		<var name="dimension" value="5" />
		<var name="tiledim" value="56000" />
		<var name="tiledimuv" value=".2" />
		<var name="shuffle_count" value="50" />

		<!-- Create the tiles of the board -->
	        <var name="uvtl" value="[0,0]" />
		<for var="y" start="0" end="?dimension-1">
		    <for var="x" start="0" end="?dimension-1" exec="inittile" />
	        </for>

		<!-- Clear the item at 0,0. This is the empty tile -->
		<property propclass="pc(p0_0,pcbillboard)"
			id="propid(visible)" value="false" />
		<property propclass="pc(p0_0,pcbillboard)"
			id="propid(clickable)" value="false" />
	        <var name="'grid_'+0+'_'+0" value="''" />
	        <var name="emptyx" value="0" />
	        <var name="emptyy" value="0" />

		<var name="speed" value="0.03" />
		<var name="allowmove" value="false" />
		<!-- Start randomizing -->
		<var name="prev_dxdy" value="1" />
		<call event="fast_shuffle" />
	    </event>

	    <!--
	      - Initialize one tile. This will create the entity representing
	      - the tile and it will set it at the right position on the puzzle
	      - board.
	      - This event uses ?x and ?y which should be set outside this routine.
	      - It also uses ?uvtl for the texture mapping coordinates.
	      -->
	    <event name="inittile">
	        <var name="ent" value="'p'+?x+'_'+?y" />
		<print value="'Creating '+?ent" />
		<createentity name="?ent" behaviour="moving_tile" />
		<var name="ent" value="ent(?ent)" />
		<default propclass="pc(?ent,pcbillboard)" />
	        <property id="propid(x)" value="1000+?tiledim*?x" />
	        <property id="propid(y)" value="1000+?tiledim*?y" />
		<var name="tl" value="[?x,?y]*?tiledimuv" />
	        <property id="propid(uv_topleft)" value="?tl" />
	        <property id="propid(uv_botright)" value="?tl+[?tiledimuv,?tiledimuv]" />
		<!-- Set the 2d grid to contain the current entity -->
	        <var name="'grid_'+?x+'_'+?y" value="?ent" />
	    </event>

	    <!--
	      - This routine is responsible for initiating a random move to
	      - randomize the board. The tile that moved will itself call this
	      - routine again if ?shuffle_count > 0. This routine will make sure
	      - that a tile doesn't move to where it was before. It uses
	      - ?prev_dxdy to do that.
	      -->
	    <event name="fast_shuffle">
	    	<!-- Try one of the four possible directions -->
	        <var name="dxdy" value="int(rand(4.0))" />
		<!-- If the direction is the opposite of the previous direction
		     we change it -->
		<var name="dxdy"
		    value="if(?prev_dxdy==(?dxdy^1),(?dxdy+1)%4,?dxdy)" />
		<var name="prev_dxdy" value="?dxdy" />
		<!-- Set ?dx and ?dy based on the four possible outcomes -->
		<if eval="?dxdy&2">
		    <true>
		        <var name="dx" value="0" />
		        <var name="dy" value="if(?dxdy&1,1,-1)" />
		    </true>
		    <false>
		        <var name="dx" value="if(?dxdy&1,1,-1)" />
		        <var name="dy" value="0" />
		    </false>
		</if>
		<!-- Location of the tile we want to move -->
		<var name="bx" value="?emptyx+?dx" />
		<var name="by" value="?emptyy+?dy" />
		<!-- Check if this is a valid location. If so we move it -->
		<if eval="?bx < ?dimension && ?bx >= 0 && ?by < ?dimension && ?by >= 0">
		    <true>
		        <var name="ent" value="?grid[?bx,?by]" />
		        <var entity="?ent" name="dx" value="-?dx" />
		        <var entity="?ent" name="dy" value="-?dy" />
			<call entity="?ent" event="move" />
		    </true>
		    <false>
		    	<!-- Try again -->
		        <call event="fast_shuffle" />
		    </false>
		</if>
	    </event>

	    <!--
	      - Start the game for real.
	      -->
	    <event name="start_game">
		<var name="speed" value="0.01" />
	        <var name="allowmove" value="true" />
	    </event>
	</script>

	<!-- *****************************************************
	  - This script handles all operations on a tile in the puzzle game.
	  -  ***************************************************** -->
        <script name="moving_tile">
	    <!--
	      - Initialize this tile.
	      - It assumes ?puzzle_main.x and ?puzzle_main.y are set to the
	      - location of the tile.
	      -->
	    <event name="init">
	    	<!-- Create timer so we can do smooth movement of this tile -->
	        <createpropclass name="pctimer" />
	        <createpropclass name="pcbillboard" />
		<default propclass="pc(pcbillboard)" />
	        <property id="propid(name)" value="picture1" />
	        <property id="propid(materialname)" value="picture1" />
	        <property id="propid(movable)" value="false" />
	        <property id="propid(clickable)" value="true" />
	        <property id="propid(restack)" value="true" />
	        <property id="propid(width)" value="?puzzle_main.tiledim" />
	        <property id="propid(height)" value="?puzzle_main.tiledim" />
		<var name="rightx" value="?puzzle_main.x" />
		<var name="righty" value="?puzzle_main.y" />
		<var name="curx" value="?rightx" />
		<var name="cury" value="?righty" />
	    </event>

	    <!--
	      - If this tile is moving then this event will be triggered
	      - every frame. Here we check how much time has elapsed and
	      - move the tile accordingly. If the tile has reached its
	      - destination then we call 'stoptimer'.
	      - The global ?puzzle_main.speed variable is used to control
	      - movement speed.
	      -->
	    <event name="pctimer_wakeupframe">
		<bb_move x="1000+intpol(?delta,?intx1,?intx2)*?puzzle_main.tiledim"
			 y="1000+intpol(?delta,?inty1,?inty2)*?puzzle_main.tiledim" />
		<if eval="?delta>=1" true="stoptimer" />
		<var name="delta" value="?delta+?puzzle_main.speed*@elapsedticks" />
	    </event>

	    <!--
	      - The tile has moved its destination. Stop the timer.
	      - If we are in shuffle mode (i.e. randomizing the board) then
	      - we signal the main 'puzzle_main' entity to start moving another
	      - tile. Otherwise we set ?puzzle_main.allowmove to true so that
	      - the player can move another tile.
	      -->
	    <event name="stoptimer">
		<action propclass="pc(pctimer)" id="propid(Clear)" />
		<bb_move x="1000+?curx*?puzzle_main.tiledim"
	        	 y="1000+?cury*?puzzle_main.tiledim" />
		<if eval="?puzzle_main.shuffle_count>0">
		    <true>
		        <var entity="puzzle_main" name="shuffle_count"
				value="?puzzle_main.shuffle_count-1" />
		        <call entity="puzzle_main" event="fast_shuffle" />
		    </true>
		    <false>
		    	<call entity="puzzle_main" event="start_game" />
		    </false>
		</if>
	    </event>

	    <!--
	      - Initiate the move of this tile to the location specified
	      - by local variables ?dx and ?dy. Doing this will disable
	      - other moves.
	      -->
	    <event name="move">
		<var entity="puzzle_main" name="allowmove" value="false" />
		<var entity="puzzle_main" name="emptyx" value="?curx" />
		<var entity="puzzle_main" name="emptyy" value="?cury" />
		<var name="intx1" value="float(?curx)" />
		<var name="inty1" value="float(?cury)" />
		<!-- Make current grid item empty -->
	        <var entity="puzzle_main" name="'grid_'+?curx+'_'+?cury"
			value="''" />
		<var name="curx" value="?curx+?dx" />
		<var name="cury" value="?cury+?dy" />
		<!-- Fill new grid item with current entity -->
	        <var entity="puzzle_main" name="'grid_'+?curx+'_'+?cury"
			value="ent()" />
		<var name="intx2" value="float(?curx)" />
		<var name="inty2" value="float(?cury)" />
		<var name="delta" value="0.0" />
		<action propclass="pc(pctimer)" id="propid(WakeUpFrame)" />
	    </event>

	    <!--
	      - Select this tile. If movement is allowed then this will
	      - check if the empty location is next to this block and if
	      - so it will call 'move' to initiate the movement.
	      -->
	    <event name="pcbillboard_select">
	        <if eval="?puzzle_main.allowmove">
		    <var name="dx" value="?puzzle_main.emptyx-?curx" />
		    <var name="dy" value="?puzzle_main.emptyy-?cury" />
		    <if eval="(abs(?dx)==1&&?dy==0)||(abs(?dy)==1&&?dx==0)">
	    	        <sound name="click" loop="false" />
			<call event="move"/>
		    </if>
		</if>
	    </event>
	</script>

    </addon>

    <addon plugin="celentity" entityname="puzzle_main">
        <behaviour name="puzzle_main" />
    </addon>
</world>

