<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.digitalmzx.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Old-Sckool</id>
	<title>MZXWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.digitalmzx.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Old-Sckool"/>
	<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/Special:Contributions/Old-Sckool"/>
	<updated>2026-06-14T05:50:13Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux&amp;diff=8695</id>
		<title>Compiling MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux&amp;diff=8695"/>
		<updated>2017-06-08T14:57:47Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Instructions]] [[Category:MegaZeux]]&lt;br /&gt;
Compiling any MegaZeux 2.8x source requires a POSIX compatible shell (bash, dash) to be installed.  Download the source .tar.bz2 or .tar.xz and extract it to a new folder.&lt;br /&gt;
&lt;br /&gt;
==Building==&lt;br /&gt;
 ./config.sh&lt;br /&gt;
This will give you help about how to configure MegaZeux.&lt;br /&gt;
&lt;br /&gt;
 ./config.sh --platform unix&lt;br /&gt;
To configure the sources. On OS X, the platform is &amp;quot;darwin&amp;quot;, and on win32 the platform is &amp;quot;win32&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
 make&lt;br /&gt;
This will build MegaZeux from sources. If it fails, you probably don't have one of SDL, libvorbis, libogg, libpng, zlib or the corresponding dev packages installed.&lt;br /&gt;
&lt;br /&gt;
 make install&lt;br /&gt;
This will install MegaZeux to the system.  Do not use for the &amp;quot;unix-devel&amp;quot; platform, which is intended to run straight out of the source directory.&lt;br /&gt;
&lt;br /&gt;
Please see debian/README for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Windows with MSYS2===&lt;br /&gt;
Download and install msys2 (these instructions are for msys2-x86_64-20161025.exe specifically)&lt;br /&gt;
 &lt;br /&gt;
Run mingw64.exe in the msys2 directory. You will be in {MSYS DIRECTORY}\home\{USERNAME}\&lt;br /&gt;
 &lt;br /&gt;
Run the following commands.&lt;br /&gt;
 &lt;br /&gt;
 yes Y | pacman -S git&lt;br /&gt;
 yes Y | pacman -S make&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-zlib&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-gcc&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libpng&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libogg&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libvorbis&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-SDL2&lt;br /&gt;
 git clone https://github.com/AliceLR/megazeux.git&lt;br /&gt;
 cd megazeux&lt;br /&gt;
 ./config.sh --platform win32 --enable-libsdl2&lt;br /&gt;
 make&lt;br /&gt;
&lt;br /&gt;
===Windows with Git Bash and MinGW===&lt;br /&gt;
&lt;br /&gt;
These instructions are intended to help you build and install all of MZX's dependencies from scratch to bin/mingw32/ in your home folder. The format of MZXPREFIX (c: instead of /c, forward slashes) is mandatory. The required dependencies for MZX are [https://www.zlib.net zlib], [http://www.libpng.org/pub/png/libpng.html libpng], [https://www.xiph.org/downloads/ libogg and libvorbis], and one of [https://www.libsdl.org/download-1.2.php SDL 1.2] or [https://www.libsdl.org/download-2.0.php SDL 2.0] (as of GIT/version 2.85, requires the --enable-libsdl2 config.sh flag).&lt;br /&gt;
&lt;br /&gt;
This requires Git installed to C:\Git, and MinGW installed to C:\MinGW. MinGW's bin folder must be on your path. Do not install Git or MinGW to Program Files or any other path with a space in it.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do this first:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;export MZXPREFIX=c:/users/\$(whoami)/bin/mingw32&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 echo &amp;quot;export PATH=\&amp;quot;\$PATH:$MZXPREFIX/bin\&amp;quot;&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 echo &amp;quot;export SDL_STDIO_REDIRECT=no&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 . ~/.bashrc&lt;br /&gt;
 mkdir ~/bin&lt;br /&gt;
 mkdir $MZXPREFIX&lt;br /&gt;
 mkdir $MZXPREFIX/bin&lt;br /&gt;
&lt;br /&gt;
Compiling zlib: one of these two methods may work.&lt;br /&gt;
&lt;br /&gt;
 make -f win32/Makefile.gcc&lt;br /&gt;
 make -f win32/Makefile.gcc install INCLUDE_PATH=$MZXPREFIX/include/ LIBRARY_PATH=$MZXPREFIX/lib/ BINARY_PATH=$MZXPREFIX/bin/&lt;br /&gt;
&lt;br /&gt;
 ./configure --static --64&lt;br /&gt;
 cp Makefile Makefile.old&lt;br /&gt;
 cp win32/Makefile.gcc Makefile&lt;br /&gt;
 make&lt;br /&gt;
 make install INCLUDE_PATH=$MZXPREFIX/include/ LIBRARY_PATH=$MZXPREFIX/lib/ BINARY_PATH=$MZXPREFIX/bin/&lt;br /&gt;
&lt;br /&gt;
Compiling libpng16: libpng folder should be in the same folder as the zlib folder, they should be called &amp;quot;libpng&amp;quot; and &amp;quot;zlib&amp;quot;, and zlib should already be built. For versions other than libpng16, replace the '16'.&lt;br /&gt;
&lt;br /&gt;
 cp scripts/pnglibconf.h.prebuilt pnglibconf.h&lt;br /&gt;
 cp scripts/makefile.gcc makefile&lt;br /&gt;
 make static&lt;br /&gt;
 cp scripts/makefile.msys makefile&lt;br /&gt;
 make libpng-config&lt;br /&gt;
 mkdir $MZXPREFIX/include/libpng16/&lt;br /&gt;
 cp libpng-config $MZXPREFIX/bin/&lt;br /&gt;
 cp libpng.a $MZXPREFIX/lib/libpng16.a&lt;br /&gt;
 cp png.h pngconf.h pnglibconf.h $MZXPREFIX/include/libpng16/&lt;br /&gt;
&lt;br /&gt;
Compiling libogg and libvorbis: these instructions should work for both.&lt;br /&gt;
&lt;br /&gt;
 ./configure --prefix=$MZXPREFIX --disable-shared&lt;br /&gt;
 make&lt;br /&gt;
 make install&lt;br /&gt;
&lt;br /&gt;
Compiling SDL 1.2 and SDL 2.0: these instructions should work for both.&lt;br /&gt;
&lt;br /&gt;
 ./configure --build=mingw32 --prefix=$MZXPREFIX&lt;br /&gt;
 make&lt;br /&gt;
 make install INSTALL=/c/Git/usr/bin/install.exe&lt;br /&gt;
&lt;br /&gt;
Compiling MZX:&lt;br /&gt;
&lt;br /&gt;
 ./config.sh --platform win64 --prefix $MZXPREFIX [other options, i.e. --enable-libsdl2]&lt;br /&gt;
 make&lt;br /&gt;
&lt;br /&gt;
If MZX fails to compile libmodplug due to a previous declaration of Sleep(), edit contrib/libmodplug/src/libmodplug/stdafx.h and comment out line 42:&lt;br /&gt;
&lt;br /&gt;
 //#define sleep(_ms)      Sleep(_ms)&lt;br /&gt;
&lt;br /&gt;
===Ubuntu/Debian===&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install gcc g++&lt;br /&gt;
We need compilers!&lt;br /&gt;
&lt;br /&gt;
 supo apt-get install libsdl1.2-dev libogg-dev libvorbis-dev libpng-dev&lt;br /&gt;
Download our dependencies.&lt;br /&gt;
&lt;br /&gt;
The above instructions should work now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Mac OS X===&lt;br /&gt;
&lt;br /&gt;
You will need to install XCode and optionally MacPorts before continuing.&lt;br /&gt;
&lt;br /&gt;
NOTE: Using MacPorts is not acceptable for official releases!  Use it for personal builds only.&lt;br /&gt;
&lt;br /&gt;
Determine the name of your compiler before continuing; typing 'i686-' or 'powerpc-' and pressing tab twice should be sufficient.  Example output:&lt;br /&gt;
 i686-apple-darwin10-g++-4.2.1 i686-apple-darwin10-gcc-4.2.1&lt;br /&gt;
&lt;br /&gt;
Compile/install dependencies.  If you're using MacPorts:&lt;br /&gt;
 sudo port install libsdl libogg libvorbis libpng&lt;br /&gt;
&lt;br /&gt;
Navigate to the extracted source directory.  If you're building MZX 2.84 and under, please download [https://github.com/AliceLR/megazeux/blob/master/arch/darwin/Makefile.in this updated Makefile.in] and put it in arch/darwin/, otherwise MegaZeux will fail to compile.&lt;br /&gt;
&lt;br /&gt;
Run ./config.sh.  Consider the following flags:&lt;br /&gt;
 --platform darwin   ---------- Mandatory.&lt;br /&gt;
 --disable-x11       ---------- Also mandatory.&lt;br /&gt;
 --disable-utils     ---------- This disables compilation of utilities such as downver and checkres.  This is optional.&lt;br /&gt;
 --enable-release    ---------- Removes debug symbols.  This will make the package smaller if you intend on installing MZX in app form.&lt;br /&gt;
 --prefix /opt/local ---------- Mandatory if you're using MacPorts; omit otherwise.&lt;br /&gt;
&lt;br /&gt;
Make options:&lt;br /&gt;
 ARCH={ your architecture: i686, amd64, ppc, or ppc64 }&lt;br /&gt;
 CROSS_COMPILE_{ X86 or PPC }_CC={ name of your gcc compiler}&lt;br /&gt;
 CROSS_COMPILE_{ X86 or PPC }_CXX={ name of your g++ compiler}&lt;br /&gt;
&lt;br /&gt;
Run make:&lt;br /&gt;
 make ARCH=i686 CROSS_COMPILE_X86_CC=i686-apple-darwin10-gcc-4.2.1 CROSS_COMPILE_X86_CXX=i686-apple-darwin10-g++-4.2.1&lt;br /&gt;
&lt;br /&gt;
Hopefully nothing will go wrong! :)&lt;br /&gt;
&lt;br /&gt;
==Packaging==&lt;br /&gt;
===Mac OS X===&lt;br /&gt;
Make sure there is not a &amp;quot;MegaZeux&amp;quot; volume mounted before continuing.&lt;br /&gt;
&lt;br /&gt;
 rm -r build/&lt;br /&gt;
 make lipo&lt;br /&gt;
 make archive&lt;br /&gt;
A .dmg will appear in build/arch/darwin/.  Please refer to the documentation in arch/darwin/ for more details.&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux_2.8x&amp;diff=8694</id>
		<title>Compiling MegaZeux 2.8x</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux_2.8x&amp;diff=8694"/>
		<updated>2017-05-30T15:12:58Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Compiling MegaZeux 2.8x to Compiling MegaZeux: no reason to bind to specific version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Compiling MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux&amp;diff=8693</id>
		<title>Compiling MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Compiling_MegaZeux&amp;diff=8693"/>
		<updated>2017-05-30T15:12:57Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Compiling MegaZeux 2.8x to Compiling MegaZeux: no reason to bind to specific version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Instructions]]&lt;br /&gt;
Compiling any MegaZeux 2.8x source requires a POSIX compatible shell (bash, dash) to be installed.  Download the source .tar.bz2 or .tar.xz and extract it to a new folder.&lt;br /&gt;
&lt;br /&gt;
==Building==&lt;br /&gt;
 ./config.sh&lt;br /&gt;
This will give you help about how to configure MegaZeux.&lt;br /&gt;
&lt;br /&gt;
 ./config.sh --platform unix&lt;br /&gt;
To configure the sources. On OS X, the platform is &amp;quot;darwin&amp;quot;, and on win32 the platform is &amp;quot;win32&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
 make&lt;br /&gt;
This will build MegaZeux from sources. If it fails, you probably don't have one of SDL, libvorbis, libogg, libpng, zlib or the corresponding dev packages installed.&lt;br /&gt;
&lt;br /&gt;
 make install&lt;br /&gt;
This will install MegaZeux to the system.  Do not use for the &amp;quot;unix-devel&amp;quot; platform, which is intended to run straight out of the source directory.&lt;br /&gt;
&lt;br /&gt;
Please see debian/README for more information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Windows with MSYS2===&lt;br /&gt;
Download and install msys2 (these instructions are for msys2-x86_64-20161025.exe specifically)&lt;br /&gt;
 &lt;br /&gt;
Run mingw64.exe in the msys2 directory. You will be in {MSYS DIRECTORY}\home\{USERNAME}\&lt;br /&gt;
 &lt;br /&gt;
Run the following commands.&lt;br /&gt;
 &lt;br /&gt;
 yes Y | pacman -S git&lt;br /&gt;
 yes Y | pacman -S make&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-zlib&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-gcc&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libpng&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libogg&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-libvorbis&lt;br /&gt;
 yes Y | pacman -S mingw-w64-x86_64-SDL2&lt;br /&gt;
 git clone https://github.com/AliceLR/megazeux.git&lt;br /&gt;
 cd megazeux&lt;br /&gt;
 ./config.sh --platform win32 --enable-libsdl2&lt;br /&gt;
 make&lt;br /&gt;
&lt;br /&gt;
===Windows with Git Bash and MinGW===&lt;br /&gt;
&lt;br /&gt;
These instructions are intended to help you build and install all of MZX's dependencies from scratch to bin/mingw32/ in your home folder. The format of MZXPREFIX (c: instead of /c, forward slashes) is mandatory. The required dependencies for MZX are [https://www.zlib.net zlib], [http://www.libpng.org/pub/png/libpng.html libpng], [https://www.xiph.org/downloads/ libogg and libvorbis], and one of [https://www.libsdl.org/download-1.2.php SDL 1.2] or [https://www.libsdl.org/download-2.0.php SDL 2.0] (as of GIT/version 2.85, requires the --enable-libsdl2 config.sh flag).&lt;br /&gt;
&lt;br /&gt;
This requires Git installed to C:\Git, and MinGW installed to C:\MinGW. MinGW's bin folder must be on your path. Do not install Git or MinGW to Program Files or any other path with a space in it.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do not install Git to Program Files.&lt;br /&gt;
&lt;br /&gt;
Do this first:&lt;br /&gt;
&lt;br /&gt;
 echo &amp;quot;export MZXPREFIX=c:/users/\$(whoami)/bin/mingw32&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 echo &amp;quot;export PATH=\&amp;quot;\$PATH:$MZXPREFIX/bin\&amp;quot;&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 echo &amp;quot;export SDL_STDIO_REDIRECT=no&amp;quot; &amp;gt;&amp;gt; ~/.bashrc&lt;br /&gt;
 . ~/.bashrc&lt;br /&gt;
 mkdir ~/bin&lt;br /&gt;
 mkdir $MZXPREFIX&lt;br /&gt;
 mkdir $MZXPREFIX/bin&lt;br /&gt;
&lt;br /&gt;
Compiling zlib: one of these two methods may work.&lt;br /&gt;
&lt;br /&gt;
 make -f win32/Makefile.gcc&lt;br /&gt;
 make -f win32/Makefile.gcc install INCLUDE_PATH=$MZXPREFIX/include/ LIBRARY_PATH=$MZXPREFIX/lib/ BINARY_PATH=$MZXPREFIX/bin/&lt;br /&gt;
&lt;br /&gt;
 ./configure --static --64&lt;br /&gt;
 cp Makefile Makefile.old&lt;br /&gt;
 cp win32/Makefile.gcc Makefile&lt;br /&gt;
 make&lt;br /&gt;
 make install INCLUDE_PATH=$MZXPREFIX/include/ LIBRARY_PATH=$MZXPREFIX/lib/ BINARY_PATH=$MZXPREFIX/bin/&lt;br /&gt;
&lt;br /&gt;
Compiling libpng16: libpng folder should be in the same folder as the zlib folder, they should be called &amp;quot;libpng&amp;quot; and &amp;quot;zlib&amp;quot;, and zlib should already be built. For versions other than libpng16, replace the '16'.&lt;br /&gt;
&lt;br /&gt;
 cp scripts/pnglibconf.h.prebuilt pnglibconf.h&lt;br /&gt;
 cp scripts/makefile.gcc makefile&lt;br /&gt;
 make static&lt;br /&gt;
 cp scripts/makefile.msys makefile&lt;br /&gt;
 make libpng-config&lt;br /&gt;
 mkdir $MZXPREFIX/include/libpng16/&lt;br /&gt;
 cp libpng-config $MZXPREFIX/bin/&lt;br /&gt;
 cp libpng.a $MZXPREFIX/lib/libpng16.a&lt;br /&gt;
 cp png.h pngconf.h pnglibconf.h $MZXPREFIX/include/libpng16/&lt;br /&gt;
&lt;br /&gt;
Compiling libogg and libvorbis: these instructions should work for both.&lt;br /&gt;
&lt;br /&gt;
 ./configure --prefix=$MZXPREFIX --disable-shared&lt;br /&gt;
 make&lt;br /&gt;
 make install&lt;br /&gt;
&lt;br /&gt;
Compiling SDL 1.2 and SDL 2.0: these instructions should work for both.&lt;br /&gt;
&lt;br /&gt;
 ./configure --build=mingw32 --prefix=$MZXPREFIX&lt;br /&gt;
 make&lt;br /&gt;
 make install INSTALL=/c/Git/usr/bin/install.exe&lt;br /&gt;
&lt;br /&gt;
Compiling MZX:&lt;br /&gt;
&lt;br /&gt;
 ./config.sh --platform win64 --prefix $MZXPREFIX [other options, i.e. --enable-libsdl2]&lt;br /&gt;
 make&lt;br /&gt;
&lt;br /&gt;
If MZX fails to compile libmodplug due to a previous declaration of Sleep(), edit contrib/libmodplug/src/libmodplug/stdafx.h and comment out line 42:&lt;br /&gt;
&lt;br /&gt;
 //#define sleep(_ms)      Sleep(_ms)&lt;br /&gt;
&lt;br /&gt;
===Ubuntu/Debian===&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install gcc g++&lt;br /&gt;
We need compilers!&lt;br /&gt;
&lt;br /&gt;
 supo apt-get install libsdl1.2-dev libogg-dev libvorbis-dev libpng-dev&lt;br /&gt;
Download our dependencies.&lt;br /&gt;
&lt;br /&gt;
The above instructions should work now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Mac OS X===&lt;br /&gt;
&lt;br /&gt;
You will need to install XCode and optionally MacPorts before continuing.&lt;br /&gt;
&lt;br /&gt;
NOTE: Using MacPorts is not acceptable for official releases!  Use it for personal builds only.&lt;br /&gt;
&lt;br /&gt;
Determine the name of your compiler before continuing; typing 'i686-' or 'powerpc-' and pressing tab twice should be sufficient.  Example output:&lt;br /&gt;
 i686-apple-darwin10-g++-4.2.1 i686-apple-darwin10-gcc-4.2.1&lt;br /&gt;
&lt;br /&gt;
Compile/install dependencies.  If you're using MacPorts:&lt;br /&gt;
 sudo port install libsdl libogg libvorbis libpng&lt;br /&gt;
&lt;br /&gt;
Navigate to the extracted source directory.  If you're building MZX 2.84 and under, please download [https://github.com/AliceLR/megazeux/blob/master/arch/darwin/Makefile.in this updated Makefile.in] and put it in arch/darwin/, otherwise MegaZeux will fail to compile.&lt;br /&gt;
&lt;br /&gt;
Run ./config.sh.  Consider the following flags:&lt;br /&gt;
 --platform darwin   ---------- Mandatory.&lt;br /&gt;
 --disable-x11       ---------- Also mandatory.&lt;br /&gt;
 --disable-utils     ---------- This disables compilation of utilities such as downver and checkres.  This is optional.&lt;br /&gt;
 --enable-release    ---------- Removes debug symbols.  This will make the package smaller if you intend on installing MZX in app form.&lt;br /&gt;
 --prefix /opt/local ---------- Mandatory if you're using MacPorts; omit otherwise.&lt;br /&gt;
&lt;br /&gt;
Make options:&lt;br /&gt;
 ARCH={ your architecture: i686, amd64, ppc, or ppc64 }&lt;br /&gt;
 CROSS_COMPILE_{ X86 or PPC }_CC={ name of your gcc compiler}&lt;br /&gt;
 CROSS_COMPILE_{ X86 or PPC }_CXX={ name of your g++ compiler}&lt;br /&gt;
&lt;br /&gt;
Run make:&lt;br /&gt;
 make ARCH=i686 CROSS_COMPILE_X86_CC=i686-apple-darwin10-gcc-4.2.1 CROSS_COMPILE_X86_CXX=i686-apple-darwin10-g++-4.2.1&lt;br /&gt;
&lt;br /&gt;
Hopefully nothing will go wrong! :)&lt;br /&gt;
&lt;br /&gt;
==Packaging==&lt;br /&gt;
===Mac OS X===&lt;br /&gt;
Make sure there is not a &amp;quot;MegaZeux&amp;quot; volume mounted before continuing.&lt;br /&gt;
&lt;br /&gt;
 rm -r build/&lt;br /&gt;
 make lipo&lt;br /&gt;
 make archive&lt;br /&gt;
A .dmg will appear in build/arch/darwin/.  Please refer to the documentation in arch/darwin/ for more details.&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Expressions&amp;diff=8352</id>
		<title>Expressions</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Expressions&amp;diff=8352"/>
		<updated>2013-08-09T03:00:29Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: /* Bitwise Operators */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Expressions''' in [[MegaZeux|MZX]] are specially formatted strings that are mathematically and programatically evaluated when the program runs.  They have two primary functions: First, expressions allow MZX to perform advanced, inline arithmetic on counters in the same way as most other programming languages.  That is, to express a = b + c, instead of having to go through the more cumbersome process of performing each step individually (set &amp;quot;a&amp;quot; to &amp;quot;b&amp;quot;; inc &amp;quot;a&amp;quot; by &amp;quot;c&amp;quot;), this can be done in one simple, easy to read line (set &amp;quot;a&amp;quot; to &amp;quot;('b' + 'c')&amp;quot;).  Second, expressions can be used to recursively nest [[counter interpolation|counter interpolations]], while ampersand interpolation cannot.  That is, a('b('c')'), where c = 3, b3 = 2, and a2 = 1, resolves to 1.  By contrast, a&amp;amp;b&amp;amp;c&amp;amp;&amp;amp; is ambiguous and ultimately resolves to a0c&amp;amp;, which is almost certainly not set to anything.&lt;br /&gt;
&lt;br /&gt;
MZX interprets anything in a string between matching parentheses as a potential expression, and attempts to evaluate it.  Within the expression string, counter values can be interpolated between pairs of ampersands (&amp;lt;tt&amp;gt;&amp;amp;&amp;lt;/tt&amp;gt;) or single quotes (&amp;lt;tt&amp;gt;'&amp;lt;/tt&amp;gt;).  Expressions can also be nested.  Strings between parentheses are evaluated in order from innermost to outermost.  It is also possible to use ampersands within a quoted counter to perform an interpolation, or to nest an expression within a pair of ampersands.  Finally, if the expression is not properly formed and cannot be evaluated, the program behavior falls through and interprets the string as is.  Depending on the context this can have different results, but in the case where the ultimate target value is a counter, this will almost certainly result in a non-existent counter lookup and resolve to 0.  Pay very close attention to this, as typos in expressions and the resultant silent fallthrough are the source of many MZX bugs.&lt;br /&gt;
&lt;br /&gt;
==An In-depth Look At Expressions==&lt;br /&gt;
Expressions consist of a series of symbols joined by operators.  These symbols can be either numeric literals (i.e. 1, 2, 3, 4...), counters (which can be interpolated and nested to any degree), or expressions themselves (e.g. &amp;quot;((1+2)*(3+4))&amp;quot;).  As explained before, expressions and counter interpolations are evaluated from innermost to outermost until the entire expression is resolved.  It is important to note that expressions ALWAYS resolve to numeric values, which is a crucial difference from the behavior of ampersand interpolation.  That is to say, they cannot be used to return the value of strings, ('$string') will not function as expected and will return 0.  &amp;amp;$string&amp;amp; must be used instead.&lt;br /&gt;
&lt;br /&gt;
Expressions can accept a number of different operators, which can be divided into three groups.  One final note before we dive into them, however: operators in expressions have no concept of precedence.  They are always executed in order from left to right, regardless of category or what you learned in math class.  With that in mind, be sure to enclose any parts of the expression that require a different order of operations within parentheses.&lt;br /&gt;
===Mathematical Operators===&lt;br /&gt;
* &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt; '''Addition'''.  Add the first value to the second and return the result.&lt;br /&gt;
* &amp;lt;tt&amp;gt;-&amp;lt;/tt&amp;gt; '''Subtraction'''.  Subtract the second value from the first and return the result.  This is also the unary negative; in the case where there is no left-hand value, this negates the right-hand value.  This will take precedence over the preceding operator (if any), and is one of the exceptions to the rule of no precedence.&lt;br /&gt;
* &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt; '''Multiplication'''.  Multiply the first and second values and return the result.&lt;br /&gt;
* &amp;lt;tt&amp;gt;/&amp;lt;/tt&amp;gt; '''Division'''.  Divide the first value by the second and return the integer part of the result (MZX has no floating point numbers).&lt;br /&gt;
* &amp;lt;tt&amp;gt;%&amp;lt;/tt&amp;gt; '''Modulo'''.  Most simply understood as dividing the first value by the second and returning the remainder.  However, this is a formal mathematical modulo operation, and works differently from the modulo command originally provided by MZX.  &amp;quot;(q%m)&amp;quot; always returns a value between 0 and m-1, inclusive, for positive values of m.  For negative values of m, the return is regular but more complicated.  q%m = -(-q%-m), except where the result would be 0, in which case it is normalized to m.  If this doesn't make sense to you, then don't use a negative modulus, there's very little reason to ever do so.&lt;br /&gt;
* &amp;lt;tt&amp;gt;^&amp;lt;/tt&amp;gt; '''Power'''.  Raise the first value to the power of the second value and return the result.&lt;br /&gt;
===Comparison Operators===&lt;br /&gt;
All comparison operators perform a logical comparison on their parameters, and return 0 for false and 1 for true.&lt;br /&gt;
* &amp;lt;tt&amp;gt;= &amp;lt;/tt&amp;gt; '''Equality'''.  Compare the first value to the second and return true if and only if they are equal.  This is NOT an assignment operator, expressions by themselves have no operators that cause side-effects.&lt;br /&gt;
* &amp;lt;tt&amp;gt;!=&amp;lt;/tt&amp;gt; '''Inequality'''.  Compare the first value to the second and return true if and only if they are not equal.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;lt; &amp;lt;/tt&amp;gt; '''Less-than'''.  Compare the first and second values and return true if and only if the first is less than the second.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;lt;=&amp;lt;/tt&amp;gt; '''Less-than-or-equal'''.  Compare the first and second values and return true if and only if the first is less than or equal to the second.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;gt; &amp;lt;/tt&amp;gt; '''Greater-than'''.  Compare the first and second values and return true if and only if the first is greater than the second.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;gt;=&amp;lt;/tt&amp;gt; '''Greater-than-or-equal'''.  Compare the first and second values and return true if and only if the first is greater than or equal to the second.&lt;br /&gt;
===Bitwise Operators===&lt;br /&gt;
MZX expressions have no logical, boolean operators like many other languages do.  There is no logical and, or logical not.  This is primarily because expressions have no concept of boolean values; all symbols must resolve to integers, and lack of precedence means that all values must be interoperable.  As a result, while it is possible to simulate logical operations using 0 to represent false and 1 to represent true (as the comparison operators do), return values for these operators are not limited to those two options.&lt;br /&gt;
* &amp;lt;tt&amp;gt;a &amp;lt;/tt&amp;gt; '''Bitwise and'''.  AND each respective bit in the first value with each respective bit in the second to obtain a new value, and return the result.  (42 a 27) = b101010 &amp;amp; b011011 = b001010 = 10.&lt;br /&gt;
* &amp;lt;tt&amp;gt;o &amp;lt;/tt&amp;gt; '''Bitwise or'''.  OR each respective bit in the first value with each respective bit in the second to obtain a new value, and return the result.  (42 o 27) = b101010 | b011011 = b111011 = 59.&lt;br /&gt;
* &amp;lt;tt&amp;gt;x &amp;lt;/tt&amp;gt; '''Bitwise xor'''.  XOR each respective bit in the first value with each respective bit in the second to obtain a new value, and return the result.  (42 x 27) = b101010 ^ b011011 = b110001 = 49.&lt;br /&gt;
* &amp;lt;tt&amp;gt;~ &amp;lt;/tt&amp;gt; '''Bitwise not'''.  NOT (i.e. one's complement) the right-hand value and return the result.  This is a unary operator and takes precedence, like the unary negative (two's complement).  ~42 = ~b101010 = b...11010101 = -43.  Be especially careful with your assumptions about this operator when trying to use it as a logical not.  ~0 is NOT 1, but -1.  ~1 is NOT 0, but -2.  You will have to modify the result of a comparison accordingly if you want to logically negate it.  This CAN be done by chaining unary operators like so: -~-(42 &amp;lt; 27) returns 1.  However, it is highly recommended that you construct comparisons to avoid this confusing syntax (i.e. simply (42 &amp;gt;= 27) is much clearer).&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;lt;&amp;lt;&amp;lt;/tt&amp;gt; '''Left-shift'''.  Bitshift the first value left by the number of bits specified in the second value.  This is effectively the same as a*(2^b), but incurs much less computational overhead.  (42 &amp;lt;&amp;lt; 2) = b101010 &amp;lt;&amp;lt; 2 = b10101000 = 168.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt; '''Right-shift'''.  Bitshift the first value right by the number of bits specified in the second value.  This is effectively the same as a/(2^b) for all positive numbers, but incurs much less computational overhead.  (42 &amp;gt;&amp;gt; 2) = b101010 &amp;gt;&amp;gt; 2 = b1010 = 10.&lt;br /&gt;
See the article on [[bitwise math]] for more information on how to use these operators.&lt;br /&gt;
* &amp;lt;tt&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;lt;/tt&amp;gt; '''Arithmetic Right-shift'''.  Bitshift the first value right by the number of bits specified in the second value, while preserving the sign bit.  This is effectively the same as a/(2^b) for both positive and negative numbers, but incurs much less computational overhead.  (42 &amp;gt;&amp;gt; 2) = b101010 &amp;gt;&amp;gt; 2 = b1010 = 10.&lt;br /&gt;
See the article on [[bitwise math]] for more information on how to use these operators.&lt;br /&gt;
&lt;br /&gt;
==Advanced Applications==&lt;br /&gt;
Advanced users of MZX often employ expressions to circumvent the limitations and clunkiness of robotic.  We've already shown, for instance, how expressions can be used to condense a long string of mathematical operations (inc, dec, multiply, divide, etc.) into a single line (e.g. set &amp;quot;a&amp;quot; to &amp;quot;('b'+'c'/('d'-'f'))&amp;quot;).  Here are some more complicated tricks.&lt;br /&gt;
===Multiple Conditions in a Single If===&lt;br /&gt;
If support has always been very limited in MZX.  Not only does the lack of codeblocks require each if statement to branch to another label, but the fact that only one condition can be evaluated per command forces a complicated spaghetti structure of gotos and labels when more than one condition must be checked simultaneously.  At least, it did before expressions.  Now, through the use of expressions, a series of comparisons can evaluated as a block, with boolean logic applied, all in a single statement.  For example, testing whether the player is within a certain defined rectangle on the board can now be done in a single statement:&lt;br /&gt;
 if &amp;quot;(('playerx'&amp;gt;='zone_min_x')a('playerx'&amp;lt;='zone_max_x')a('playery'&amp;gt;='zone_min_y')a('playery'&amp;lt;='zone_max_y'))&amp;quot; = 1 then &amp;quot;in_zone&amp;quot;&lt;br /&gt;
The external &amp;quot;= 1&amp;quot; is the raw robotic conditional test for whether the expression evaluates to true or not.  We can use bitwise operators on comparisons as if they were logical operators, because the values of 0 and 1 differ in their representation by only a single bit, and all operations will return acceptable, expected values as if they were true booleans.&lt;br /&gt;
===Ad-hoc If-Else Statements===&lt;br /&gt;
Very often in more fully featured languages, there are cases where a variable is set to one value if a condition evaluates one way, and another value if not.  For example:&lt;br /&gt;
 if (x &amp;gt; 0) {&lt;br /&gt;
   y = 42;&lt;br /&gt;
 } else {&lt;br /&gt;
   y = 27;&lt;br /&gt;
 }&lt;br /&gt;
MZX possesses no conceptually easy way to perform this simple control-flow operation.  Historically this was managed with a construct like this:&lt;br /&gt;
 if &amp;quot;x&amp;quot; &amp;gt; 0 then &amp;quot;S&amp;quot;&lt;br /&gt;
 set &amp;quot;y&amp;quot; to 27&lt;br /&gt;
 goto &amp;quot;S2&amp;quot;&lt;br /&gt;
 : &amp;quot;S&amp;quot;&lt;br /&gt;
 set &amp;quot;y&amp;quot; to 42&lt;br /&gt;
 : &amp;quot;S2&amp;quot;&lt;br /&gt;
 ...&lt;br /&gt;
This is clunky, and pollutes the label namespace, as new labels must be created for each such situation in the robot.  Expressions provide an alternative solution, which while not any less clunky (in fact it is significantly more convoluted and difficult to understand), does not require any labels and fits on a single line.  It works like this:&lt;br /&gt;
 set &amp;quot;y&amp;quot; to &amp;quot;( (('x' &amp;gt; 0) * 42) + (('x' &amp;lt;= 0) * 27) )&amp;quot;&lt;br /&gt;
Or, as it is often stripped of any unnecessary spacing and clarifying parentheses:&lt;br /&gt;
 set &amp;quot;y&amp;quot; to &amp;quot;(('x'&amp;gt;0*42)+('x'&amp;lt;=0*27))&amp;quot;&lt;br /&gt;
This works because the comparison operators return integers, not booleans, and in particular return 0 or 1.  They can therefore be inserted into a mathematical expression to cause certain values to become 0 and other values to remain, depending on the condition.  Here, when x &amp;gt; 0, the expression evaluates to ((1*42) + (0*27)).  When x &amp;lt;= 0, the expression becomes ((0*42) + (1*27)).  This principle can be extended to incorporate as many cases as will fit in a single line.  We can also take advantage of the zero return to abbreviate the expression in cases where zero is the desired result.  For example:&lt;br /&gt;
 set &amp;quot;x&amp;quot; to &amp;quot;('x'-5&amp;gt;0*('x'-5))&amp;quot;&lt;br /&gt;
This will decrease x by 5, but not past 0.  If the value would be less than zero, or if x is already less than zero, then it will become zero.&lt;br /&gt;
&lt;br /&gt;
==Important Notes==&lt;br /&gt;
* All expressions return integer values.  If you try to interpolate a string value within an expression, MZX will attempt to numerically evaluate that string.  If the string represents a number (e.g. set &amp;quot;$string&amp;quot; to &amp;quot;12345&amp;quot;), then the result will be that number, but usually the result will simply be 0.  You CAN interpolate a string as part of a counter name, such as &amp;lt;tt&amp;gt;set &amp;quot;get&amp;quot; to &amp;quot;('&amp;amp;$anarray&amp;amp;_&amp;amp;anindex&amp;amp;')&amp;quot;&amp;lt;/tt&amp;gt;, but the expression has to evaluate to a number.&lt;br /&gt;
* Double check your expressions to make sure that all parentheses and quotes have matching pairs.  If they are mismatched, the expression will almost certainly fail to evaluate, and will be treated as a raw string.  This usually results in the entire string evaluating as 0, and causes code to simply not work as expected, but in subtle and hard to track ways.  Generally, a value that is supposed to be changing will not change.  MZX gives you no help in syntax highlighting, since expressions are just grafted on to strings.  So, mistyped expressions should be one of the first things you check for in non-working code.&lt;br /&gt;
* When an expression is used in a parameter that would usually accept a counter or value, and the entire string provided for that parameter is an expression, then the result of the evaluated expression will be treated as a literal value, not as a counter name, even though it is contained inside of a string.  Or as an example, if the counter named &amp;quot;four&amp;quot; is set to 4, then &amp;lt;tt&amp;gt;set &amp;quot;ctr&amp;quot; to &amp;quot;('four')&amp;quot;&amp;lt;/tt&amp;gt; will be the same as &amp;lt;tt&amp;gt;set &amp;quot;ctr&amp;quot; to 4&amp;lt;/tt&amp;gt;, and NOT &amp;lt;tt&amp;gt;set &amp;quot;ctr&amp;quot; to &amp;quot;4&amp;quot;&amp;lt;/tt&amp;gt;.  This should seem like common sense, because it generally is the natural expectation when you want to evaluate some complicated expression and assign it to a counter.  It is noteworthy because it is another difference in the behavior of expressions versus ampersand interpolation.  &amp;lt;tt&amp;gt;set &amp;quot;ctr&amp;quot; to &amp;quot;&amp;amp;four&amp;amp;&amp;quot;&amp;lt;/tt&amp;gt; WILL try to set counter to some counter named &amp;quot;4&amp;quot;, which probably doesn't exist.  Of course, the correct way to do something like the previous example is to not use expressions or ampersands at all, but it is simply intended to demonstrate a key difference in expression behavior.&lt;br /&gt;
* Mathematical counters like sin#, abs#, and sqrt# can be used freely in expressions, but remember that they are counters and not operators, and must be properly enclosed in quotes to function.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Subroutines&amp;diff=8190</id>
		<title>Subroutines</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Subroutines&amp;diff=8190"/>
		<updated>2013-01-21T05:52:18Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: /* Quirks and Special Notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Subroutines''' are callable sections of [[Robotic]] code, somewhat like functions but not as fully featured.  They are accessed the same way as labels, and as such can't explicitly accept parameters or return values, like true functions could.  Even so, they are an extremely useful way of organizing and managing Robotic, and are a very real extension of [[MZX]] capabilities, not just a shortcut for cleaner code.  Subroutines were added in MZX version 2.65&lt;br /&gt;
===How To Use===&lt;br /&gt;
Subroutines are basically labels with advanced functionality; any label beginning with the character '#' is treated as a subroutine.  They can be called from any place in Robotic as a label might be, including goto, send, if statements, failure branches (e.g. take 4 GEMS &amp;quot;#toopoor&amp;quot;), and the '?' textbox command (see quirks below).  Subroutines are different from normal labels in that each robot has a call stack that keeps track of which line was being executed when a subroutine is called.  Using the special subroutine label &amp;quot;#return&amp;quot; sends a robot one level up its call stack, to the code it was previously executing.  Since it is a stack, subroutine calls can be arbitrarily nested.  One other special subroutine label, &amp;quot;#top&amp;quot;, sends the robot to the very top of the stack, where the first subroutine was called.&lt;br /&gt;
&lt;br /&gt;
This is best understood through an example.&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;I am a robot with subroutines.&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#sub1&amp;quot;&lt;br /&gt;
 goto &amp;quot;#sub2&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;The end.&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;#sub1&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;This is subroutine 1.  It calls:&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#suba&amp;quot;&lt;br /&gt;
 goto &amp;quot;#subb&amp;quot;&lt;br /&gt;
 goto &amp;quot;#subc&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;This line is never seen.&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#sub2&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;This is subroutine 2.  It calls:&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#subb&amp;quot;&lt;br /&gt;
 goto &amp;quot;#suba&amp;quot;&lt;br /&gt;
 goto &amp;quot;#subd&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;This line IS seen.&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#suba&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine A&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#subb&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine B&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#subc&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine C&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#top&amp;quot;&lt;br /&gt;
 : &amp;quot;#subd&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine D&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#write&amp;quot;&lt;br /&gt;
 write overlay c0f &amp;quot;&amp;amp;$str&amp;amp;&amp;quot; at 0 &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
This produces the following output, written to the overlay.&lt;br /&gt;
 I am a robot with subroutines.&lt;br /&gt;
 This is subroutine 1.  It calls:&lt;br /&gt;
 Subroutine A&lt;br /&gt;
 Subroutine B&lt;br /&gt;
 Subroutine C&lt;br /&gt;
 This is subroutine 2.  It calls:&lt;br /&gt;
 Subroutine B&lt;br /&gt;
 Subroutine A&lt;br /&gt;
 Subroutine D&lt;br /&gt;
 This line IS seen.&lt;br /&gt;
 The end.&lt;br /&gt;
Besides demonstrating the function of subroutine nesting and repeated calling, this example shows how to practically write a piece of code to perform a specific function.  In this case, a short subroutine to write a string to the next available overlay row.  It also demonstrates the use of a [[string]] (or a counter) as an implicit parameter, so that subroutines can be used somewhat like functions.&lt;br /&gt;
&lt;br /&gt;
===Quirks and Special Notes===&lt;br /&gt;
&lt;br /&gt;
*When subroutines were first introduced, they required the robot's call stack to be explicitly initialized.  For this reason, in games made between version 2.65 and the [[MZX#SDL port|port]], robots that use subroutines contain lines like this:&lt;br /&gt;
 . &amp;quot;#*-1-2-3&amp;quot;&lt;br /&gt;
:The MZX interpreter would use the first comment string in the robot beginning with #* as a static call stack, storing the jump locations in that string in two bytes each.  The &amp;quot;-1-2-3...&amp;quot; portion of the string was a convention to remind the programmer how many levels deep the stack was, and that any subroutine nesting beyond that point would break the code.  Since the port, each robot's stack has been dynamically handled internally by MZX, and can be arbitrarily large.&lt;br /&gt;
*When a robot sends itself to a subroutine (including when it uses a send or a send &amp;quot;all&amp;quot; command to do so), the stored return point is the command after the one which triggered the send.  Otherwise a goto would cause an infinite loop on return, which would not be very useful.  When a robot sends ANOTHER robot to a subroutine, the stored return point in that robot is the command it is currently on and would have executed otherwise.  Otherwise there would be errors with subroutines causing robots to skip commands.&lt;br /&gt;
*When robots are sent to several subroutines during the same cycle, they react to all of them, in the reverse order in which they were received.  This is a natural side-effect of the way cross-robot label sending and subroutines are handled, and is actually a very powerful feature.  Basically what happens is when a robot is sent to a label, its current command is changed to be that label.  When it is sent to multiple labels at the same time, the last label it received will be the one it ultimately executes.  But when a robot is sent to a subroutine, it stores its current command location on the stack before moving to the new label.  So when it receives multiple subroutine calls at the same time, it stores all of them on the stack, and then starts executing from the last subroutine received.  Each goto &amp;quot;#return&amp;quot; moves up the stack to the previous subroutine received, until all of them are executed.  Try this example with two robots, to see this in action:&lt;br /&gt;
 . &amp;quot;@robot1&amp;quot;&lt;br /&gt;
 send &amp;quot;robot2&amp;quot; &amp;quot;#sub1&amp;quot;&lt;br /&gt;
 send &amp;quot;robot2&amp;quot; &amp;quot;#sub2&amp;quot;&lt;br /&gt;
 send &amp;quot;robot2&amp;quot; &amp;quot;#sub3&amp;quot;&lt;br /&gt;
 send &amp;quot;robot2&amp;quot; &amp;quot;#sub2&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 ---------------------&lt;br /&gt;
 . &amp;quot;@robot2&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;#sub1&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine 1&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#sub2&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine 2&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#sub3&amp;quot;&lt;br /&gt;
 set &amp;quot;$str&amp;quot; &amp;quot;Subroutine 3&amp;quot;&lt;br /&gt;
 goto &amp;quot;#write&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#write&amp;quot;&lt;br /&gt;
 write overlay c0f &amp;quot;&amp;amp;$str&amp;amp;&amp;quot; at 0 &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
:This results in the following printed to the overlay:&lt;br /&gt;
 Subroutine 2&lt;br /&gt;
 Subroutine 3&lt;br /&gt;
 Subroutine 2&lt;br /&gt;
 Subroutine 1&lt;br /&gt;
*When a robot is sent to a subroutine when the program is processing a command that takes multiple cycles to complete (&amp;quot;&amp;lt;tt&amp;gt;go south for 5&amp;lt;/tt&amp;gt;&amp;quot; for example), even if that command runs for only a single cycle, the command will be re-executed from the beginning when returning from that subroutine. This leads to one major drawback: since wait is a command that takes multiple cycles to complete.  Execution does not move to the next command until the robot has finished waiting.  Because the most common way to end a cycle is &amp;quot;&amp;lt;tt&amp;gt;wait for 1&amp;lt;/tt&amp;gt;&amp;quot;, a robot sent to a subroutine during this cycle break will return from that subroutine at the beginning of the wait command, and wait again.  So, a robot running a continuous [[engine]] loop will be interrupted for a cycle every time it is told to handle another task.  This is unlikely to be changed any time soon.  A few solutions have been proposed to get around this (making a specific exception for wait 1, adding an &amp;quot;end cycle&amp;quot; command, etc.). The best solution found is to use the command &amp;quot;&amp;lt;tt&amp;gt;cycle 1&amp;lt;/tt&amp;gt;&amp;quot;, as it ends the cycle without ending program execution, and has a similar form to wait 1.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7985</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7985"/>
		<updated>2012-10-03T09:22:20Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For a comprehensive tutorial on sprites, see [[Sprite (Tutorial)]].&amp;lt;!--don't know how to do this properly--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[PUT color Sprite param # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite_Colliding pNN # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite p?? # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
===Instantiation===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_X]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_Y]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_HEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_WIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
===Collision===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CWIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CHEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CLIST]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_CLISTn]] (read-only)''' &lt;br /&gt;
&lt;br /&gt;
'''[[SPR_COLLISIONS]] (read-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CCHECK]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_NUM]]'''&lt;br /&gt;
&lt;br /&gt;
===Graphical===&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_YORDER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OFF]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAID]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAY]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_STATIC]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_VLAYER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SWAP]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7984</id>
		<title>Board</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7984"/>
		<updated>2012-10-03T09:20:17Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: /* Limitations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''Board''' is basically a playing field for which the game can take place in.&lt;br /&gt;
&lt;br /&gt;
==Limitations==&lt;br /&gt;
*Boards can range in size from 1x1 to a massive 32767x32767&lt;br /&gt;
**Extremely large boards will consume a massive block of memory. A board with the maximum dimensions would consume over 3 GB of memory, not including the overlay.&lt;br /&gt;
**The board scan is a somewhat expensive routine that scans every square of the board every cycle for built-ins. The larger the board, the bigger the performance impact it can have on your game on slower computers. &lt;br /&gt;
*For a few [[Built-in|built-in objects]], there is a limit to how many can be placed on one board.&lt;br /&gt;
**All boards must have one and only one instance of the player object.&lt;br /&gt;
**Robots and scrolls are both capped to 255 per board&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7699</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7699"/>
		<updated>2011-02-23T20:52:46Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Playing Background Music==&lt;br /&gt;
===World Editor===&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N editor command allows you to set the default music for a particular board. The default music will loop for as long as the player remains on the board. If two or more boards share the same song, and the game swaps between them, MegaZeux will not reload the song. You can also use Shift+8 or the Numpad * to set the board's default music to a wildcard, which essentially tells MegaZeux to continue playing the current music (if any).&lt;br /&gt;
&lt;br /&gt;
===Robotic===&lt;br /&gt;
The other way to add music to a game is through Robotic. The [[MOD &amp;quot;file&amp;quot;]] command set's the current board's music to the chosen file. You can also set the board's default music to a wildcard by using MOD &amp;quot;*&amp;quot;, which does exactly what it does while in edit mode.&lt;br /&gt;
&lt;br /&gt;
==Adjusting The Background Music==&lt;br /&gt;
There are also a number of commands that can be used to control the volume of the board music. The [[VOLUME #]] command allows you to directly set the volume of the playing song, from 0 (silent) to 255. [[MOD FADE # #]] allows you to fade the volume to a given value within a given number of cycles. Lastly, instead of calling MOD &amp;quot;file&amp;quot; (which plays the sound file at the default volume) you can dynamically fade songs in and out with [[MOD FADE IN &amp;quot;file&amp;quot;]] and [[MOD FADE OUT]]. You can figure out when MOD FADE OUT has finished fading out the current board music with [[WAIT MOD FADE]], which forces the robot to wait until MOD FADE OUT completes.&lt;br /&gt;
&lt;br /&gt;
Finally, you can use the [[END MOD]] command to terminate the current background song.&lt;br /&gt;
&amp;lt;!--I honestly don't know what use there is to [[MOD SAM # #]].--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sound Effects==&lt;br /&gt;
No game can really be considered complete without a decent assortment of sound effects. There are two distinct ways you can insert sound effects into MegaZeux.&lt;br /&gt;
&lt;br /&gt;
===PC Speaker===&lt;br /&gt;
By default, [[built-ins]] use an emulated [[PC speaker|PCS]] sound-effects. These can be modified with the [[ALT-F]] Editor Command.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Built-ins&amp;diff=7698</id>
		<title>Built-ins</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Built-ins&amp;diff=7698"/>
		<updated>2011-02-23T20:41:21Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Redirected page to Built-in&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Built-in]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7697</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7697"/>
		<updated>2011-02-23T20:39:02Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Playing Background Music==&lt;br /&gt;
===World Editor===&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N editor command allows you to set the default music for a particular board. The default music will loop for as long as the player remains on the board. If two or more boards share the same song, and the game swaps between them, MegaZeux will not reload the song. You can also use Shift+8 or the Numpad * to set the board's default music to a wildcard, which essentially tells MegaZeux to continue playing the current music (if any).&lt;br /&gt;
&lt;br /&gt;
===Robotic===&lt;br /&gt;
The other way to add music to a game is through Robotic. The [[MOD &amp;quot;file&amp;quot;]] command set's the current board's music to the chosen file. You can also set the board's default music to a wildcard by using MOD &amp;quot;*&amp;quot;, which does exactly what it does while in edit mode.&lt;br /&gt;
&lt;br /&gt;
==Adjusting The Background Music==&lt;br /&gt;
There are also a number of commands that can be used to control the volume of the board music. The [[VOLUME #]] command allows you to directly set the volume of the playing song, from 0 (silent) to 255. [[MOD FADE # #]] allows you to fade the volume to a given value within a given number of cycles. Lastly, instead of calling MOD &amp;quot;file&amp;quot; (which plays the sound file at the default volume) you can dynamically fade songs in and out with [[MOD FADE IN &amp;quot;file&amp;quot;]] and [[MOD FADE OUT]]. You can figure out when MOD FADE OUT has finished fading out the current board music with [[WAIT MOD FADE]], which forces the robot to wait until MOD FADE OUT completes.&lt;br /&gt;
&lt;br /&gt;
Finally, you can use the [[END MOD]] command to terminate the current background song.&lt;br /&gt;
&amp;lt;!--I honestly don't know what use there is to [[MOD SAM # #]].--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sound Effects==&lt;br /&gt;
No game can really be considered complete without a decent assortment of sound effects. There are two distinct ways you can insert sound effects into MegaZeux.&lt;br /&gt;
&lt;br /&gt;
===PC Speaker===&lt;br /&gt;
By default, [[built-ins]] use an emulated [[PC speaker|PCS]] sound-effects. These can be modified with the [[ALT-F]] Editor Command&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7696</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7696"/>
		<updated>2011-02-23T19:45:49Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Playing Background Music==&lt;br /&gt;
===World Editor===&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N editor command allows you to set the default music for a particular board. The default music will loop for as long as the player remains on the board. If two or more boards share the same song, and the game swaps between them, MegaZeux will not reload the song. You can also use Shift+8 or the Numpad * to set the board's default music to a wildcard, which essentially tells MegaZeux to continue playing the current music (if any).&lt;br /&gt;
&lt;br /&gt;
===Robotic===&lt;br /&gt;
The other way to add music to a game is through Robotic. The [[MOD &amp;quot;file&amp;quot;]] command set's the current board's music to the chosen file. You can also set the board's default music to a wildcard by using MOD &amp;quot;*&amp;quot;, which does exactly what it does while in edit mode.&lt;br /&gt;
&lt;br /&gt;
==Adjusting The Background Music==&lt;br /&gt;
There are also a number of commands that can be used to control the volume of the board music. The [[VOLUME #]] command allows you to directly set the volume of the playing song, from 0 (silent) to 255. [[MOD FADE # #]] allows you to fade the volume to a given value within a given number of cycles. Lastly, instead of calling MOD &amp;quot;file&amp;quot; (which plays the sound file at the default volume) you can dynamically fade songs in and out with [[MOD FADE IN &amp;quot;file&amp;quot;]] and [[MOD FADE OUT]]. You can figure out when MOD FADE OUT has finished fading out the current board music with [[WAIT MOD FADE]], which forces the robot to wait until MOD FADE OUT completes.&lt;br /&gt;
&lt;br /&gt;
Finally, you can use the [[END MOD]] command to terminate the current background song&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--I honestly don't know what use there is to [[MOD SAM # #]].--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sound Effects==&lt;br /&gt;
No game can really be considered complete without a decent assortment of sound effects. There are two distinct ways you can insert sound effects into MegaZeux.[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Category:Command&amp;diff=7695</id>
		<title>Category:Command</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Category:Command&amp;diff=7695"/>
		<updated>2011-02-18T01:45:18Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;List of MegaZeux's Commands&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;List of MegaZeux's Commands&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=MESSAGE_ROW_(command)&amp;diff=7694</id>
		<title>MESSAGE ROW (command)</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=MESSAGE_ROW_(command)&amp;diff=7694"/>
		<updated>2011-02-18T01:44:39Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''MESSAGE ROW #''', '''SET MESG COLUMN #''', and '''CENTER MESG''' are commands which let the programmer change the on-screen position of the [[Message Row]], which can be used to make dialogue or messages appear to be coming from somewhere besides the bottom row of the screen, or to position a status bar.&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
 . &amp;quot;putting the message row at the top of the screen and displaying two lines of text&amp;quot;&lt;br /&gt;
 message row is 0&lt;br /&gt;
 set mesg column to 3&lt;br /&gt;
 * &amp;quot;~fHELLO,\nWORLD!&amp;quot;&lt;br /&gt;
 wait for 50&lt;br /&gt;
 . &amp;quot;now, we return the message row to its default settings and clear it&amp;quot;&lt;br /&gt;
 clear mesg&lt;br /&gt;
 message row is 24&lt;br /&gt;
 center mesg&lt;br /&gt;
&lt;br /&gt;
==Supplementary Commands==&lt;br /&gt;
===* &amp;quot;string&amp;quot;===&lt;br /&gt;
[[* &amp;quot;string&amp;quot;|See main article.]]&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]][[Category:Command]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Category:Tutorial&amp;diff=7693</id>
		<title>Category:Tutorial</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Category:Tutorial&amp;diff=7693"/>
		<updated>2011-02-18T01:42:22Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;Tutorials for MegaZeux&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Tutorials for MegaZeux&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7692</id>
		<title>Sprite (Tutorial)</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7692"/>
		<updated>2011-02-18T01:41:55Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Despite the mystery and trepidation that generally surrounds them, '''[[Sprite|sprites]]''' are not that hard to work with and are designed to be easy to use, with the right program model.  Two common and effective models, which can be used together or alone depending on the requirements of the engine, are the '''sprite-layer model''' and the '''sprite-object model'''.  The structure of your code will depend on the application and the model being used, but there are some basics to cover first.&lt;br /&gt;
__NOTOC__ &lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid black; font-size: 1; display: table; padding: 1em&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;'''Contents'''&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[#Sprite Tutorial|Sprite Tutorial]]&lt;br /&gt;
:[[#S1|1 The Basics: Drawing Sprites]]&lt;br /&gt;
::[[#E1.1|Exercise 1.1: Making a sprite based player]]&lt;br /&gt;
::[[#E1.2|Exercise 1.2: Improving and generalizing the code]]&lt;br /&gt;
:[[#S1a|1a The Not So Basics: Sprite Collision]]&lt;br /&gt;
::[[#E1.3|Exercise 1.3: Adding basic collision detection]]&lt;br /&gt;
:[[#S2|2 The Sprite-Object Model: Active Collision]]&lt;br /&gt;
::[[#E2.1|Exercise 2.1: Keys and doors with sprites]]&lt;br /&gt;
::[[#E2.2|Exercise 2.2: Keeping track of sprites on the board]]&lt;br /&gt;
::[[#E2.3|Exercise 2.3: Moving the player sprite between boards]]&lt;br /&gt;
::[[#E2.4|Exercise 2.4: Finishing touches, fixing the scrolling]]&lt;br /&gt;
:[[#S3|3 The Sprite-Layer Model: Working With Layers]]&lt;br /&gt;
::[[#E3.1|Exercise 3.1: Creating a status bar]]&lt;br /&gt;
::[[#E3.2|Exercise 3.2: Bullets as a layer (framework)]]&lt;br /&gt;
::[[#E3.3|Exercise 3.3: Bullets as a layer (implementation)]]&lt;br /&gt;
::[[#E3.4|Exercise 3.4: Interacting with the rest of the game]]&lt;br /&gt;
&lt;br /&gt;
[[#External Links|External Links]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{a|S1}}&lt;br /&gt;
===The Basics: Drawing Sprites===&lt;br /&gt;
All sprites, regardless of their function, require some basic initialization and setup before they can be used.  First, you need to set aside space on the board (or the [[Vlayer]]) for the sprite source image.  You don't even have to put anything there yet, some advanced techniques construct the image data dynamically.  But you need a block of space that is going to be used for sprite data.  Next, all sprites need initialization code somewhere that designates this area.&lt;br /&gt;
 set &amp;quot;spr#_refx&amp;quot; to XCOORD      ''These counters specify the x coordinate, y coordinate,''&lt;br /&gt;
 set &amp;quot;spr#_refy&amp;quot; to YCOORD      ''width, and height of the bounding rectangle for the source image''&lt;br /&gt;
 set &amp;quot;spr#_width&amp;quot; to WIDTH      ''Replace # with the number of the sprite, from 0 to 255.''&lt;br /&gt;
 set &amp;quot;spr#_height&amp;quot; to HEIGHT    ''Counter interpolation is acceptable and in fact common for this.''&lt;br /&gt;
Finally, all sprites need to be placed somewhere in order to be viewed.  While &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot; counters do exist, and they can be written to place and move the sprite, we recommend you treat them as read-only and use the &amp;quot;put&amp;quot; command for readability and clarity of purpose:&lt;br /&gt;
 put c?? Sprite # at X Y        ''# is the number of the sprite to be placed, as a parameter.  Can be a counter.''&lt;br /&gt;
{{a|E1.1}}&lt;br /&gt;
====Exercise 1.1: Making a sprite based player====&lt;br /&gt;
A common application for sprites is to have all actors in the game, including the player, be represented by sprites.  This lends itself well to a sprite-object model, but we'll come to that later.  Our first exercise will be to make a player sprite that can be moved around with the arrow keys.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, start editing a new world, and draw a customblock smiley face on the board.  It doesn't really matter what it looks like, or where it is, but for the sake of example put it at (80,0) off the right edge of the screen, and make it 3x3 characters large.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Create a new robot called &amp;quot;sprite&amp;quot; to handle the sprite drawing and moving code.  I like to put my control robots in a horizontal line starting at (1,0), but again, it really doesn't matter.  The very first line of the robot should be &amp;quot;lockplayer&amp;quot;, just to keep the player from moving around.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Let's use sprite 0 for our player.  So, the next 4 commands should be:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr0_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr0_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr0_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr0_height&amp;quot; to 3&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a control loop that draws the sprite and handles input.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite p00 at &amp;quot;x&amp;quot; &amp;quot;y&amp;quot;&lt;br /&gt;
: if uppressed then &amp;quot;up&amp;quot;&lt;br /&gt;
: if leftpressed then &amp;quot;left&amp;quot;&lt;br /&gt;
: if rightpressed then &amp;quot;right&amp;quot;&lt;br /&gt;
: if downpressed then &amp;quot;down&amp;quot;&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that x and y will default to 0 since they haven't been used yet.  It's generally a good idea to keep this information in a pair of local counters and initialize them along with the rest of the sprite data.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, you just need code to modify the values of &amp;quot;x&amp;quot; and &amp;quot;y&amp;quot; for each label &amp;quot;up&amp;quot;, &amp;quot;left&amp;quot;, &amp;quot;right&amp;quot;, and &amp;quot;down&amp;quot;.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: dec &amp;quot;y&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And the rest should be obvious: inc &amp;quot;y&amp;quot; by 1 for &amp;quot;down&amp;quot;, dec &amp;quot;x&amp;quot; by 1 for &amp;quot;left&amp;quot;, and inc &amp;quot;x&amp;quot; by 1 for &amp;quot;right&amp;quot;.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.1|Example 1.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E1.2}}&lt;br /&gt;
====Exercise 1.2: Improving and generalizing the code====&lt;br /&gt;
That's it, you can now test your world and move the sprite around.  You'll notice that the sprite gets &amp;quot;stuck&amp;quot; if you move it off the top or left of the board, and disappears off the bottom right.  That's because we didn't do any bounds checking.  In fact, there are a lot of improvements we can make to this code before we move on.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First let's make the sprite initialization dynamic.  This may seem like more work now, but it'll make things much easier when you want to play with a lot of objects later, and decide that you need to reallocate sprite numbers.  We'll declare local counters for the sprite draw location while we're at it.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to 3&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;We also need some bounds checking.  I prefer to define variables for zone boundaries, but we'll use constants with [[expressions]] for now.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: : &amp;quot;down&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that &amp;quot;local3&amp;quot; is &amp;quot;y&amp;quot;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You also probably noticed that the previous movement routine favored certain directions over others; you can fix this by turning the label calls into [[subroutines]] (with diagonal movement as a free bonus!)&amp;lt;tt&amp;gt;&lt;br /&gt;
: if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One pitfall that comes with using subroutines for movement like this is that it's possible to get the sprite stuck on corners as you move it.  This is because the sprite position is not updated after the sprite counters are changed, but only after every move direction has been checked.  One way to fix this is to just use the spr#_x and spr#_y counters instead of local counters, since those are directly tied to sprite position.  But for reasons we'll discuss later, I recommend against this, or at least keeping copies of them in local counters.  The other way is to make sure the sprite is updated (i.e. drawn) after each move.  This is accomplished most easily through subroutines as well:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for every location where the sprite needs updating, that is at the end of all movement subroutines and within the main loop, call the subroutine &amp;quot;#draw&amp;quot; with a goto.  In fact, it's not really even necessary to call this in every iteration of the main loop if it's called on movement.  It only needs to be called once after all the sprite counters have been initialized.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Since this is our player sprite, it would be nice if we could get the screen scrolling to act like it.  Fortunately there's a really easy way to do this without having to work out a bunch of bothersome math.  Just put the following functional counter in your #draw subroutine, after you draw the sprite:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Really simple, and another good reason to have a separate subroutine for the drawing code, since that makes it easy to update and augment.  You can now expand the board area and bounds checking beyond the confines of the viewport.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This leaves us with this final code:&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.2|Example 1.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S1a}}&lt;br /&gt;
===The Not So Basics: Sprite Collision===&lt;br /&gt;
So we can now draw a sprite and move it around the screen.  This is great, but except for some very limited cases is not particularly useful for gameplay.  Simple bounds checking is easy enough to implement, but what if we want to have our player sprite move around inside a defined terrain, with walls and solid objects and impassible barriers?  Worse, what if we want to interact with the environment, or with other sprites?  Designing this from scratch would involve doing a lot of checking for [[customblocks]], a way to figure out which sprite is at a specific location, and depending on the size of the sprite being moved, would require checking multiple locations each time in order to ensure consistency.  It would be difficult to make the system general enough to be transplantable from game to game, and if you did manage it it would be hard to read and understand the code.&lt;br /&gt;
&lt;br /&gt;
Fortunately, MZX provides a way to do all that work with one statement:&lt;br /&gt;
 if c?? Sprite_colliding p## at X Y then LABEL   ''p## is the number of the sprite you want to move, X and Y are relative coordinates.''&lt;br /&gt;
One of the reasons people find this simple command so difficult to use is that they don't understand what it actually does.  The first important requirement is that the sprite being moved define a collision rectangle.  This should be done along with the other sprite initialization counters like so:&lt;br /&gt;
 set &amp;quot;spr#_cx&amp;quot; to X             ''These X and Y coordinates are relative values.''&lt;br /&gt;
 set &amp;quot;spr#_cy&amp;quot; to Y             ''That means you set them relative to (0,0) as the top left corner of the sprite.''&lt;br /&gt;
 set &amp;quot;spr#_cwidth&amp;quot; to WIDTH     ''So if you want the collision rectangle to be the same size and area as the sprite itself,''&lt;br /&gt;
 set &amp;quot;spr#_cheight&amp;quot; to HEIGHT   ''cx and cy should both be 0, and cwidth and cheight should be the same as width and height.''&lt;br /&gt;
Most people understand this much.  What often gets confused is that the Sprite_colliding object in the if statement is NOT this collision rectangle.  Nor does it directly represent the collision rectangle of another sprite, though it is necessary for other sprites to have collision rectangles in order for collision to work.  But there isn't an actual sprite_colliding object anywhere on the board, this is simply the syntax used to call collision detection for a sprite in advance of movement.  The command says &amp;quot;if I hypothetically move this sprite (specified by the parameter) X by Y from its current location, will it collide with anything.&amp;quot;  And then it branches depending on whether the answer is true or false.&lt;br /&gt;
&lt;br /&gt;
The two key points about X and Y are that they are ''relative'' to the sprite's current location, and they specify the ''movement'' of the sprite, not the position of something else.  The color term is co-opted to perform a non-intuitive task of specifying relative versus absolute movement.  c?? means that X and Y are relative values, and is what you will normally want to use.  c00 (or any other absolute color) make X and Y absolute coordinates, but again the statement checks to see what would happen if you put the sprite at that location, not for the presence of some other object at that location.  This is vital to understand, since without it you will probably try to do much more work than you need to do, and will probably achieve unexpected and incorrect results for your efforts.&lt;br /&gt;
&lt;br /&gt;
{{a|E1.3}}&lt;br /&gt;
====Exercise 1.3: Adding basic collision detection====&lt;br /&gt;
Let's see if we can't improve our player sprite code and turn it into something you might actually want to use in a game.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, take that board you were working on and draw some walls on it.  Sprite collision detection only works with customblocks and other sprites, so in any game where you want to use sprite collision, all of your collidable scenery should be customblock.  But if you're really interested in advanced MZX programming and artwork, you should already be doing this anyway.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;In order to create the illusion of depth and a 3/4 camera angle, we'll define the collision rectangle as being only the bottom row of the sprite.  The sprite dimensions are 3x3, so that means:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 2&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Update each of your movement subroutines to include a collision check along with the bounds check:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, going along with that 3/4 camera thing, you will generally want game sprites farther down the screen to appear &amp;quot;in front&amp;quot; of sprites above them.  Sprites have a globally applicable drawing mode to handle this very thing:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_yorder&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that this counter is global to all sprites, and is not a per-sprite counter.  You can stick it anywhere you like, but it makes the most sense to put it in the global robot.  We will discuss how to use layer-like sprites with yorder later.  For now, all you need to know is that this makes sprites draw in order of position from the top of the screen to the bottom, instead of in order of their sprite numbers.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it!  That's really all you have to do!&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.3|Example 1.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S2}}&lt;br /&gt;
===The Sprite-Object Model: Active Collision===&lt;br /&gt;
It's wonderful and all that we can make sprites not do something (i.e. move) if they collide.  But what if we want to make them do something else instead?  What if we want that thing to be different depending on the object of the collision?  When you perform a collision check with &amp;quot;if sprite_colliding&amp;quot;, it has the side effect of populating an array-like construct that details what, if anything, was collided with.  This array is called &amp;quot;spr_clist&amp;quot;, its length is stored in the counter &amp;quot;spr_collisions&amp;quot;, and it is accessed as pseudo-arrays usually are in MZX, through counter interpolation.  Here is a typical and flexible collision handler:&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;        ''This will only goto labels that actually exist, making it easily pluggable.''&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;  ''This will send to a robot named with the same number as the colliding sprite.''&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;                ''Don't forget about the loop termination quirk, where the terminator is inclusive.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Short circuits whatever else would have been done had collision not happened.''&lt;br /&gt;
 : &amp;quot;#collide-1&amp;quot;                                 ''-1 is the background, meaning the sprite collided with a customblock.''&lt;br /&gt;
 * &amp;quot;~fOuch, I bumped into a wall!&amp;quot;              ''Normally you wouldn't bother with this label though, since a wall is a wall.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Continues collision handling.  Remember, subroutines go on a call stack.''&lt;br /&gt;
The send command is the beginning of understanding sprites with an object model, where each sprite is bound to code in a robot specific to that sprite, so that everything relevant to that sprite (including counters you may create) can be accessed with a single number.  Here, we use that number to send the sprite (and I find it useful to make no distinction between the sprite and the robot controlling it) a touch label.&lt;br /&gt;
&lt;br /&gt;
You should devise and maintain a convention for what robots that control sprites should be called.  &amp;quot;sprite#&amp;quot; or &amp;quot;spr#&amp;quot; are normal, or you could just reference them by number.  In order to make things as code driven as possible, so that you only have to change a single line to reassign a sprite number in a robot, you should do this dynamically in your robot setup with a rename command.  And there's some other stuff you can do to make it easy to move sprites around just by moving the robots that control them.&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;   ''This makes things very dynamic, since you can copy the same robot around the board with no changes''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;     ''and make multiple copies of the sprite.  Setting local2 and local3 based on the robot's position''&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;     ''means that you don't have to configure the initial sprite placement, either.  Then you can move the''&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0            ''robot into a robot bank at the top of the board, and the unique value of local ensures you won't''&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;             ''overwrite anything.  But this is not always appropriate, sometimes you'll want to choose a specific ID''&lt;br /&gt;
&lt;br /&gt;
{{a|E2.1}}&lt;br /&gt;
====Exercise 2.1: Keys and doors with sprites====&lt;br /&gt;
Now that we have an idea of how to make our sprite player touch things, let's create some things for him to touch.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, the player needs a collision handler.  You can use the one we just discussed with no modification (though you may want to take out the #collide-1 label since that's just to demonstrate how to do something special based on what you collided with).  You'll also need to change the target label for the collision check to &amp;quot;collision&amp;quot;:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And so on.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You need to create some key objects and some door objects, at least one of each, but creating more than one will be really, really easy.  Each of these will be sprites, and each of them will have a robot in control.  First, draw some graphics over with the player source you had before.  Remember what their parameters are.  If you want to do something REALLY cool, create a list of constants and put it in the global robot to keep track of these numbers for you.  This way, if you ever change them, or do something like making your sprites vlayer based, you'll have a much easier time of things since you'll only have to change the global robot.  In any case, use what you've learned about sprites so far to create a robot called &amp;quot;key&amp;quot; with a dynamic initialization routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to XCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to YCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to WIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to HEIGHT&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to CX&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to CY&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to CWIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to CHEIGHT&lt;br /&gt;
: put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Of course you'll need to provide your own values for those counters, and as I've said, I really recommend assigning them to constant counters whose values you set all in one place.  It makes things much easier later, when you want to change the way things are done.  Also notice that in addition to reading the coordinates of the key based on where you put the robot, it also reads the color of the key and draws the sprite accordingly.  This means we can use exactly the same robot code for different colored keys, without changing a thing except the color of the robot itself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now you need a &amp;quot;:touch&amp;quot; label.  In the case of a key, if you touch it you just collect the key and it disappears.  So we need a counter to keep track of the key, and we need to make the sprite disappear.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&lt;br /&gt;
What we've done here is increment a counter that is unique to the color of the key.  This means we can collect more than one of the same color key, and open just as many doors.  The spr#_off counter is a special functional counter which turns off sprite drawing and sprite collision when it is set to something.  It does NOT set the sprite's counters to zero, though.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy that key robot and make a door robot out of it.  I'm serious, the changes you'll be making are so slight that they don't warrant starting from scratch.  Just change the values of the sprite initialization to suit, and change the behavior in the touch routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
We perform a simple check to make sure that the player collected a key that is the same color as this door.  Other than that, it's a mirror image of the key's touch routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy those two robots all over the board.  You may actually want to do this with copyrobot commands, so that you only have to change the code in one place, when you need to change it.  Or, if you want to be clever, save the robot code into a [[file access|file]] and load from that.  Whatever you do, put a bunch of copies of the key and door code onto your board, using as many different colors as you like.  Now play around with it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.1|Example 2.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.2|}}&lt;br /&gt;
====Exercise 2.2: Keeping track of sprites on the board====&lt;br /&gt;
So far, the only time we've needed to have sprites talk to other sprites or refer to them by ID is when they collided, and then the numbers are provided for us.  But suppose we want to know which sprite is the player and where it is, so that we can allow another robot controlling another sprite (like an enemy) to target it?  Or what if we want to have the same sprite run around the board stealing keys (we'll actually do this in an upcoming example)?  It'll need to know where they are too.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;For the player, this is simple enough, we can just have the following line in our initialization:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Can't get much easier than that.  But for keys and doors, we need to be a little bit more clever, since there can be arbitrarily many of those.  Just using their color (local4) as an identifier isn't enough, since that might not be unique on the board, and besides that we'd like a solution to enumerate a list of things.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;First, in the global robot, initialize a couple of counters to keep track of the number of keys and doors on the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;num_doors&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Then in the key init code (and similarly for the door code), add each key to the end of a list and advance the counter:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;num_keys&amp;quot; by 1 &amp;lt;/tt&amp;gt;&lt;br /&gt;
We also store the sprite's position in the list and attach it to the sprite, double linking them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Why bother spending overhead on this, and making this counter public?  So that we can easily prune the list when the player collects a key or opens a door.  Here's a neat trick to quickly remove an item from an array without leaving a hole:&amp;lt;tt&amp;gt;&lt;br /&gt;
: dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
Let's pause here and explain what we've just done in more detail.  First, we create a list of sprite/robot ids (they're the same in our system, remember).   We populate this list by first setting the length of the list to zero, and adding each item to the end of the list as its robot gets executed.  We also know that these items are subject to being removed from the list of active sprites in certain game situations.  Now we can set things up such that the list will be automatically regenerated if we leave the board and come back (more on that in the next example).  But when we start using lists to keep track of lots of objects that get added to and deleted from the list a lot (e.g. bullets), we'll really appreciate having a way to perform those add and delete operations in constant time, while limiting the time to iterate over the list down to the number of currently active items.&amp;lt;br&amp;gt;&lt;br /&gt;
The key observation that makes the above trick work is that the list doesn't need to be sorted.  So all we need to do to deal with the hole left by a deleted list item is find another item to put in the hole.  And there's always an item at the end of the list, even if it's the very item we're deleting.  We tell the sprite at the end of the list that it's list position (spr#_lpos) is now the position of the item we're deleting (this is why that counter needed to be public).  And then we tell the list that the id at that position is now the id at the end of the list.  Finally we decrease the length of the list (it's safe to do this first as shown in the code because the data doesn't actually go anywhere), effectively removing the last item on the list.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;li&amp;gt;This exercise has largely been in preparation for things to come.  But in order to demonstrate its usefulness quickly, let's create a simple debug robot to print the status of all of our sprites on the board.&amp;lt;tt&amp;gt;&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyt&amp;quot;&lt;br /&gt;
: [ &amp;quot;The player is sprite &amp;amp;playersprite&amp;amp;, located at (('spr&amp;amp;playersprite&amp;amp;_x'), ('spr&amp;amp;playersprite&amp;amp;_y')).&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_keys&amp;quot; &amp;lt;= 0 then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: [ &amp;quot;Key sprite #&amp;amp;local&amp;amp; is located at (('spr('keysprite&amp;amp;local&amp;amp;')_x'), ('spr('keysprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_keys&amp;quot; then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_doors&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: [ &amp;quot;Door sprite #&amp;amp;local&amp;amp; is located at (('spr('doorsprite&amp;amp;local&amp;amp;')_x'), ('spr('doorsprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_doors&amp;quot; then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Just copy this into a new robot (put it somewhere other than the top row of the board) and press 'T' to access it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
[[Sprite Code Examples#Example 2.2|Example 2.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.3|}}&lt;br /&gt;
====Exercise 2.3: Moving the player sprite between boards====&lt;br /&gt;
Almost any real game is going to involve more than one board (single board content management via [[MZM|MZMs]] aside).  However, successfully managing sprites across multiple boards requires some overhead and foresight.  Before we go any further, we need to address one of the major gotchas of sprites, which is that you have 256 of them to use in the entire GAME, not per board.  This means that, especially for a dynamic sprite system, you need a way to ensure that sprites are kept consistent and in the same places across boards.  &lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;What this generally means is that we want to have the sprite initialization happen every time you load the board, implying the use of :justentered.  But there are also parts of our sprite initialization code that we want to happen only one time, like setting the initial sprite position by using the initial robot position and then moving the robot.  Fortunately there's a simple trick for pulling this off:&amp;lt;tt&amp;gt;&lt;br /&gt;
: . &amp;quot;One time execution code goes here.&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: . &amp;quot;Static initialization code goes here (sprite ref and collision box among others).&amp;quot;&lt;br /&gt;
: . &amp;quot;Fallthrough to main program loop.&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember your robotic, a pipe is a pre-zapped label.  This should be applied to the global robot as well, for sprite list setup.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course there are things, especially for sprites that are going to move around, that must be preserved on a board change but which are subject to change.  This is the reason I suggested the use of &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; to keep track of sprite position, instead of &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot;.  But the player needs a system that doesn't simply preserve its position on each board, but which accurately sets its position based on where it was on the previous board.  This means that the player sprite needs to use global counters instead of local counters.  So do a search and replace on &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; in the player robot (CTRL+R is your friend) for counters like &amp;quot;player_x&amp;quot; and &amp;quot;player_y&amp;quot;.  Then add this code to the one time execution segment of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The reason for the locals as temps will become clear in a moment.  Now add this code to the board init section:&amp;lt;tt&amp;gt;&lt;br /&gt;
: lockscroll&lt;br /&gt;
: set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
: set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
: put player 0 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
Now you can us the player object itself to mark the start position of the player sprite, and be able to test from that position on any board.  We lock scrolling because of what we do with the player in the next step, to prevent the viewport from jumping around.  It no longer really matters where you put the player robot, as long as you don't put it in the top row (for safety reasons, since all the sprite robots move to that line and it might get overwritten before it moves).  Also note the use of &amp;quot;player_x&amp;quot; instead of &amp;quot;playerx&amp;quot;, since &amp;quot;playerx&amp;quot; and &amp;quot;playery&amp;quot; are built-in and read-only.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to know when the sprite moves off the board.  Fortunately bounds checking allows us to do just that.  For each movement routine, add a sprite counter that tells which direction the sprite last moved, and then route the bounds check to a label that sends the global robot a message, like so:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;lt;= &amp;quot;bminy&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we're going to use a nice little shortcut so that we can keep track of board adjacencies with the standard MZX system instead of writing another data structure to do it.  All it requires is that the four corners of each board you use it on be empty.  That's because we're going to use the player object itself to move between boards, instead of using teleport player.  Write each edge# method similar to this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: . &amp;quot;North&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('bmaxy'-'spr_p_h')&amp;quot;&lt;br /&gt;
: . &amp;quot;That is, the bottom of the sprite playing field minus the height of the player sprite.&amp;quot;&lt;br /&gt;
: put player 0 0&lt;br /&gt;
: . &amp;quot;Use board_w-1 and board_h-1 to move south and east.&amp;quot;&lt;br /&gt;
: move player NORTH&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The idea here is to set temp counters to the expected location of the player sprite on the next board, then move the actual player to that board.  We don't use the actual counters so that if the move fails (there is no board in that direction), nothing happens to the sprite.  But if the move succeeds, the justentered label will be triggered and the values will be committed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Obviously for this to work right, those &amp;quot;bminy&amp;quot; and &amp;quot;bmaxy&amp;quot; counters need to actually exist.  They also need to be the same across all boards; if the boards need to have different dimensions you will need a more complex system.  But for this simple case, just add those to the one-time code of the global.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
You can use whatever values you like, of course, at this point it's more up to the requirements of your game than anything else.  You can and should replace all hard-coded values in the player bounds checking with these counters, as seen above.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final thing remains to be done, and that's to make sure all the sprites being used at the time of the board transition are turned OFF. We may have done a lot of work to make sure sprites can initialize properly each time the board loads, but if we don't destroy them before moving to another board then any sprites that don't get reinitialized will hang around.  Now it would be possible to just loop through all 256 sprites and turn them all off to be safe, but that may not always be optimal, and besides that this is a perfect application for those lists we made earlier.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_doors'-1)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Stick this at the front of the global board init, and it'll be the first thing executed when a board loads.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That's really all that needs to be done at this point.  Test it out by creating a few interlinked boards and spread your doors and keys across them.  You'll need to copy the sprite source data between the boards too.  (Writing an [[MZM#MZM Tutorial|MZM loader]] for this into the global robot is left as an exercise to the reader.  I actually recommend using the vlayer to store them though, and we'll do this in the next step, so brush up on the [[vlayer#VLayer Tutorial|vlayer tutorial]] for more info.)&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.3|Example 2.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.4}}&lt;br /&gt;
====Exercise 2.4: Finishing touches, fixing the scrolling====&lt;br /&gt;
Before we wrap up this section for good, there's a bit of cleanup work we need to do.  Most pressing, and something you will have noticed by now unless your boards are all the same size as the bounding area for your sprite playing field, is that the simple directions I gave you for scrolling the viewport don't work right, or not the way you'd really want them to. If your sprite images are still on the board, you probably want them to not be visible; you'd like the &amp;quot;board&amp;quot; that the player sprite moves on to stop before you get to things that are off the screen.  There are really only two ways to handle this: either put nothing on the board that is not intended to be seen (i.e. use the vlayer and some other tricks), or use complicated math to clamp the viewport to the edges of the playing area, to prevent the player from seeing things that are not intended to be seen.&lt;br /&gt;
&lt;br /&gt;
I wrestled with how to present this material for close to a year, since there are just so many problems with it.  One problem is that it's mostly just necessary busywork, tying off loose ends so that the engine functions more smoothly; it doesn't really fit in with the flow of the tutorial, but it really needs to be done now before we proceed to the next major section.  Another problem is that doing things in an easily pluggable way that only involves adding a few lines in key places requires some very complex [[expressions|expression hacking]] that just isn't appropriate to teach in a tutorial about sprites; while doing it in a way that is easy to understand requires more additions and modifications than I'd really like.  So ultimately I've decided to give you as many options as possible.  If you want to skip as much of this nonsense as possible and get right on to the sprite-layer model, just follow step 1 to get your sprites on the vlayer, and step 1a to deal with the details of only doing that.  If you want to go the whole nine yards, the rest of the steps will show you, in order of necessity, how to tweak the engine to handle scrolling inside of a bounded area.  You can stop following them whenever you're satisfied with the results.  And if you're interested in my preferred method for doing this, the last step will show you the expressions for compressing 50 lines of code into 5.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, one thing that absolutely must happen before we move on to sprite layers is that we start using the vlayer for sprites.  If nothing else, we don't want to have to set aside broad swaths of space on each board for sprites that are as large as the playing area itself.  So, export your sprite image data to something like &amp;quot;sprites.mzm&amp;quot;, and add the following line to the one-time code of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You'll also need to adjust all the coordinate constants for the sprites appropriately, by subtracting 80 from the refx coordinates.  So for example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_p_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_d_x&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr_k_x&amp;quot; to 6&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, all sprite robots need a line in their board init to reference them from the vlayer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;ol type=&amp;quot;a&amp;quot;&amp;gt;&amp;lt;li&amp;gt;If this is the only step you want to take, there are a few more small things to do.  First, make sure the board size, and the dimensions specified by bminx, bmaxx, bminy, and bmaxy, are the same.  The easiest way to do this is to set them in the global robot directly based on the board settings:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to &amp;quot;board_w&amp;quot;&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to &amp;quot;board_h&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You will then need to draw overlay artwork on the areas of the board where the robots will reside (i.e. the top row) and in the top-left and bottom-right corners where the player can be.  Finally, to accomodate this, all sprites that might move into these areas (notably the player) need to have this line added to their setup:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_overlaid&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
This will ensure that the sprites appear over the overlay you've drawn, with the drawback that you won't be able to draw overlay to appear above them.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to correct the scrolling.  The easiest way to conceptualize this is to create a subroutine for each boundary that resets the viewport to line up with that edge, and then to call those subroutines each time the current scrolling code causes the viewport to cross any boundary.  The subroutines will all go at the end the player robot, and will be called conditionally inside of the &amp;quot;#draw&amp;quot; subroutine, right after the &amp;lt;tt&amp;gt;spr#_setview&amp;lt;/tt&amp;gt; line.  So for example, the left edge works like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;lt; &amp;quot;bminx&amp;quot; then &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;bminx&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The right edge requires a little bit more, since we need to take the width of the viewport into account:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;gt; &amp;quot;('bmaxx'-'vw')&amp;quot; then &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;('bmaxx'-'vw')&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The other two edges are basically the same, with different counters in the appropriate places.  Of course, the counter vw, and its brother vh (for viewport width and viewport height) need to exist.  MZX doesn't have built-in counters to read these values, so we need to set them ourselves, in the global robot one-time code:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;vh&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
This allows them to be easily changed later, in case we decide we want the viewport to be smaller than the full screen.  As a final step, so that the player and robots don't have to be covered up with overlay, we want to make sure the playing area for the sprites has at least a character of margin around it, for the player and robots to live in and move around.  This means that bminx and bminy should both be changed to 1, at least, and bmaxx and bmaxy should both be at least one less than the width and height of the board.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;There will be a minor problem with a visible scroll snap when you move from board to board.  This is because the board draws before any of the robots on it run, so the scroll correction code in the player robot will only take effect after the board has been drawn once.  To fix this, we'll put some corrective code into the only robot that runs before the screen is drawn: the global robot.  The basic idea here is that, similar to how we move the player to the opposite side of the playing field every time we change boards, we'll do the same with the viewport.  We'll use &amp;quot;local4&amp;quot; and &amp;quot;local5&amp;quot; as carry-over counters for this purpose.  First, in the board init, right after the lockscroll command:&amp;lt;tt&amp;gt;&lt;br /&gt;
: scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for each of the :edge# routines, we set these counters, similarly to the way the clamping routines worked in the last step.  So for moving north, we want the screen to end up on the bottom edge:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('bmaxy'-'vh')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Similar additions apply to the other routines.  Finally, we want local4 and local5 to have values on the first board.  We could perform the same complicated scroll correction routine the player robot uses to make sure the viewport is inside the playing area, but that's really a waste of code for something that's only ever going to be used once at the very beginning of the game.  So we'll just set them in the one-time code based on the initial scroll location:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The put player command is an interesting one, since it consumes a cycle only if it actually causes the player to move.  But this does mean that there will be an extra cycle of delay whenever we move south or east, since then the player DOES have to move to the opposite end of the board.  This isn't that important, but as long as we're cleaning up loose ends, we might as well handle this.  Similar to the scroll correction we did before, we will set up subroutines to move the real player object to the correct edge of the board, based on the location of the player sprite, and then call them conditionally in a loop.  This way, the player will always be at the correct location in advance.  So, after the global board setup, instead of just ending the program, create a loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playerloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;playerloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then create the subroutines and if calls.  To check if the player is on the left side of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_x&amp;quot; &amp;lt; &amp;quot;('bminx'+'bmaxx'/2)&amp;quot; then &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: put player at 0 &amp;quot;playery&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Or for the bottom of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;gt; &amp;quot;('bminy'+'bmaxy'/2)&amp;quot; then &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: put player at &amp;quot;playerx&amp;quot; &amp;quot;('board_h'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expression used in the comparison is a simple midpoint calculation for the board playing area.  All you have to do now is remove the put player commands from the edge handlers, since the player will already be in the right place to move when they're called.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The subroutine system is pretty easy to understand and works just fine, but I personally don't like to use it when I don't have to, just to save on commands.  Instead, when I have a situation that involves setting one value to a choice of two or three values depending on some condition, I like to cram all the logic into an expression that will execute in one command.  This is purely a preference on my part, it doesn't make the code that much more efficient and it certainly doesn't make it more readable.  But it does make it shorter.  So in the case of scroll correction, this is what I do:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns what was 16 lines into three; it would be one, but the expressions are so complicated that they won't fit side by side in one line.  The first two lines there can also be applied at the beginning of the global robot to local4 and local5, instead of simply &amp;quot;scrolledx&amp;quot; and &amp;quot;scrolledy&amp;quot;, to more accurately set the initial location of the viewport.&amp;lt;br&amp;gt;&lt;br /&gt;
Then, for moving the player around, I use this construct:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put player at &amp;quot;('bminx'+'bmaxx'/2&amp;lt;'player_x'*('board_w'-1))&amp;quot; &amp;quot;('bminy'+'bmaxy'/2&amp;lt;'player_y'*('board_h'-1))&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns those 16 lines into a single line, without the need for any intermediate steps.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This concludes the section on sprites as objects.  It got a little sidetracked at the end, but this is all necessary maintenance work if you want to use sprites as objects in a full-fledged game.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.4|Example 2.4 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S3}}&lt;br /&gt;
===The Sprite-Layer Model: Working With Layers===&lt;br /&gt;
Understanding sprites as layers is not really that complex a concept to grasp.  The basic idea dates back to MZX feature requests for having multiple overlays or underlays in the game, so that you could use different layers to handle different tasks.  The feature was rejected as is, but sprites can fill this role just fine.  Up till now we've thought of sprites as relatively small objects linked to specific actors in the game.  Now, we'll be using sprites as very large objects that can cover the whole screen or even the whole board.  Instead of placing a small sprite at a location on the board to change what the player sees, we will paint image data onto a large sprite to accomplish the same thing.&lt;br /&gt;
&lt;br /&gt;
There are a few useful status commands for working with layer-like sprites&lt;br /&gt;
 set &amp;quot;spr#_vlayer&amp;quot; to 1    ''Sets the sprite to get its image data from the vlayer instead of the board.''&lt;br /&gt;
 set &amp;quot;spr#_overlaid&amp;quot; to 1  ''Makes the sprite appear over the overlay. Ideal if using the overlay in a traditional way.''&lt;br /&gt;
 set &amp;quot;spr#_static&amp;quot; to 1    ''Makes the sprite display relative to the viewport, rather than the board, like a static overlay.''&lt;br /&gt;
Using the vlayer is especially important for layer sprites.  At this point it becomes completely impractical to set aside as much empty space on every board in the game as is necessary to accomodate all of the graphical data used by them.  Painting the sprite on top of the overlay can also be useful if you are using the overlay to draw static things on top of the normal game action, like trees or houses, but you want something special to appear above everything, like a status bar or a message box.  And very often, it is worth combining this with the static command, so that you don't have to figure out where to redraw the sprite every time the screen moves.&lt;br /&gt;
&lt;br /&gt;
There are also a few important things to consider when working with large sprites, and when combining them with the gameplay engine we're building.  The first is that character 32, the space, is not drawn in a sprite, just like it isn't drawn on the overlay.  This is pretty essential if you're going to have a sprite that covers the whole screen, space-wise, and still want to see what's beneath it.  Another is that sprites have an absolute maximum width and height of 255.  If you try to make a sprite larger than that, the practical dimensions will just wrap back around to 0, modulo 256.  Because we're using layer sprites as a window into the vlayer, we never actually NEED a sprite to be larger than 80x25 characters, and there are plenty of ways to work with them to stay inside this constraint.  But since it's often easier, for a layer that covers the entire board, to just place the layer on the board, we'll assume for the purposes of this tutorial that you won't be using a board or sprites larger than 255 in either dimension.&lt;br /&gt;
&lt;br /&gt;
Finally, one important catch that comes up when we try to use a layer sprite in conjunction with a system that uses spr_yorder to draw game objects correctly, is how to get the layer to appear on top of all the other sprites in the game, or to change its order relative to other layers.  After all, a sprite drawn over the whole screen is going to have a y-coordinate lower than any sprite object in the game, right?  Fortunately for us, spr_yorder doesn't calculate its draw order based on spr#_y values, but on spr#_cy values.  Since we almost never want sprites that are suppose to appear above all game objects to collide with those game objects, this means that we can co-opt this counter as a view order marker.  Setting it to extreme negative values will make it appear below every other sprite in the game.  Setting it to extreme positive ones will make it appear above everything.  It may require some tweaking to get working exactly right when combined with other layers, since the values are still taken as offsets from the sprite's position on the board, but it's a serviceable workaround.&lt;br /&gt;
&lt;br /&gt;
{{a|E3.1}}&lt;br /&gt;
====Exercise 3.1: Creating a status bar====&lt;br /&gt;
For our first foray into layer sprites, let's do something fairly simple to create, but that epitomizes the most basic purpose of layers: a status bar.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;Before anything else, we need to draw the base template for the status bar.  This can be done mostly however you like, but it should at least have locations to draw health, ammo, and collected keys, and the locations and sizes of the places for drawing to these areas should be recorded as constants in the global robot.  Here are the constants and sizes I'll be using:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;lyr_s_x&amp;quot; to 0   ''meaning layer-statusbar-refx''&lt;br /&gt;
: set &amp;quot;lyr_s_y&amp;quot; to 3   ''layer-statusbar-refy''&lt;br /&gt;
: set &amp;quot;lyr_s_w&amp;quot; to 50  ''layer-statusbar-width''&lt;br /&gt;
: set &amp;quot;lyr_s_h&amp;quot; to 2   ''layer-statusbar-height''&lt;br /&gt;
: set &amp;quot;lyr_sh_x&amp;quot; to 10 ''layer-statusbar-health-refx''&lt;br /&gt;
: set &amp;quot;lyr_sh_y&amp;quot; to 3  ''layer-statusbar-health-refy''&lt;br /&gt;
: set &amp;quot;lyr_sh_w&amp;quot; to 25 ''layer-statusbar-health-width''&lt;br /&gt;
: set &amp;quot;lyr_sh_h&amp;quot; to 1  ''layer-statusbar-health-height''&lt;br /&gt;
: set &amp;quot;lyr_sa_x&amp;quot; to 43 ''layer-statusbar-ammo-refx''&lt;br /&gt;
: set &amp;quot;lyr_sa_y&amp;quot; to 3  ''layer-statusbar-ammo-refy''&lt;br /&gt;
: set &amp;quot;lyr_sa_w&amp;quot; to 5  ''layer-statusbar-ammo-width''&lt;br /&gt;
: set &amp;quot;lyr_sa_h&amp;quot; to 1  ''layer-statusbar-ammo-height''&lt;br /&gt;
: set &amp;quot;lyr_sk_x&amp;quot; to 8  ''layer-statusbar-keys-refx''&lt;br /&gt;
: set &amp;quot;lyr_sk_y&amp;quot; to 4  ''layer-statusbar-keys-refy''&lt;br /&gt;
: set &amp;quot;lyr_sk_w&amp;quot; to 40 ''layer-statusbar-keys-width''&lt;br /&gt;
: set &amp;quot;lyr_sk_h&amp;quot; to 1  ''layer-statusbar-keys-height''&amp;lt;/tt&amp;gt;&lt;br /&gt;
The final result should look something like this, 50 characters wide, 2 high, with room for labels and a 2 character margin on each side:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;display:table&amp;quot;&amp;gt;| Health: =========================  Ammo: 00000 |&lt;br /&gt;
| Keys: ________________________________________ |&amp;lt;/pre&amp;gt;&lt;br /&gt;
Save it as a new MZM, statusbar.mzm, and then have the global robot load it along with sprites.mzm:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a robot to handle drawing our layer.  This starts out in the same basic way as all sprite robots have so far:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;('vw'-'lyr_s_w'/2)&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: . &amp;quot;These are the initial x/y coordinates for the sprite, though they'll change later.&amp;quot;&lt;br /&gt;
: . &amp;quot;The expression for the x coordinate is a midpoint formula that places the sprite in the center of the viewport&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: set &amp;quot;statusbar&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_static&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_s_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_s_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_s_h&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 500&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 0&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
All of the principles used here, including the new ones like spr&amp;amp;local&amp;amp;_static and using spr&amp;amp;local&amp;amp;_cy to fix the display order, should already be familiar to you if you've been following the tutorial.  We set the other collision counters to 0 in order to make sure they're off; remember, this sprite number could have belonged to something else on another board.  By the same token, don't forget to add a line to turn off the statusbar sprite on board transitions, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That got the sprite drawing, but now we need it to display something meaningful, instead of just looking pretty.  First, let's set up a main program loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: . &amp;quot;The easiest way to redraw the status bar is to reload the base image from the MZM.&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: goto &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then we need to flesh out each of those subroutines.  Health is the easiest to do: we need a bar of filled health as long as the space in the status bar, so draw a line of red 25 characters long next to the other sprites, and re-export sprites.mzm.  Make sure to add constants for this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_sh_x&amp;quot; to 8  ''meaning sprite-statusbar-health-refx, for the sprite image to copy onto the layer''&lt;br /&gt;
: set &amp;quot;spr_sh_y&amp;quot; to 0  ''sprite-statusbar-health-refy''&amp;lt;/tt&amp;gt;&lt;br /&gt;
To draw the health, we'll simply copy a portion of this bar based on the value of 'health' and 'maxhealth' (you'll have to set maxhealth to something yourself).  This leads to:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: copy block &amp;quot;#&amp;amp;spr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_sh_y&amp;amp;&amp;quot; for &amp;quot;('health'*'lyr_sh_w'/'maxhealth')&amp;quot; &amp;quot;lyr_sh_h&amp;quot; to &amp;quot;#&amp;amp;lyr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_sh_y&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now for the ammo.  The easiest way to read this out of a counter and onto the vlayer is to convert the counter into a string.  MZX will do this for you without having to write a conversion routine.  We would like to write that string directly to the vlayer, but unfortunately MZX doesn't support that operation in a convenient way right now (though it may in the future).  We could write it to some off-screen space on the overlay and then copy it, but depending on how you set up the board scrolling in the last section, you may not have any off-screen space.  So we'll just have to loop through the string.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: set &amp;quot;$ammo&amp;quot; to &amp;quot;&amp;amp;ammo&amp;amp;&amp;quot;&lt;br /&gt;
: . &amp;quot;Ampersands are required, so that we don't just draw 'ammo' on the screen.&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;vch('lyr_sa_x'+'loopcount'),('lyr_sa_y')&amp;quot; to &amp;quot;$ammo.&amp;amp;loopcount&amp;amp;&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('$ammo.length'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we don't do any checking for the length of the ammo string.  We could do this, but it would involve adding some complex expressions that are outside of this tutorial's scope, and is left as an exercise to the reader.  Instead, simply take care not to let the player's ammo exceed 99999.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, the keys.  Remember that the information for these is not stored in the built-in MZX key handling, but in counters we defined ourselves, 'key_#' for each color.  To draw the keys, we'll loop through these counters and test whether they're set or not.  This is a fairly complicated routine, and involves keeping track of the key color and the current draw location, and aborting the loop before we draw too many keys to fit on the status bar.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;keynext&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: if &amp;quot;local5&amp;quot; &amp;gt;= &amp;quot;lyr_sk_w&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
: set &amp;quot;vch('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to 12&lt;br /&gt;
: set &amp;quot;vco('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to &amp;quot;local4&amp;quot;&lt;br /&gt;
: inc &amp;quot;local5&amp;quot; by 1&lt;br /&gt;
: loop for &amp;quot;('key_&amp;amp;local4&amp;amp;'-1)&amp;quot;&lt;br /&gt;
: : &amp;quot;keynext&amp;quot;&lt;br /&gt;
: inc &amp;quot;local4&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local4&amp;quot; &amp;lt; 256 then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that 12 is the character of the key graphic; this could easily be changed.  Also understand that this is a fairly inefficient routine, and will take around 1000 commands to execute.  We could create some data structures to greatly improve on this time, but that would involve maintenance and a lot of extra effort.  Instead, this is the time to go ahead and set the 'commands' counter to something reasonably high, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Two last things before we're done: the status bar necessarily covers up parts of the playing area that we might like to see.  There are two things we can do to help with this.  One is to move the status bar to the opposite side of the screen if the player gets too close to it.  The other is to allow the player to toggle the display on and off.  Neither of these is that hard to do, so we'll take them both in order.  To move the sprite, create a #draw subroutine in the main loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;('spr&amp;amp;playersprite&amp;amp;_y'-'scrolledy')&amp;quot; &amp;gt;= &amp;quot;('vh'-'spr_p_h'/2)&amp;quot; then &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('vh'-'lyr_s_h')&amp;quot;&lt;br /&gt;
: : &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Basically, as long as the player remains in the lower half of the screen, the status bar will be on top.  If the player moves into the top of the screen, the status bar will move to the bottom.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;To turn the status bar on and off, we'll simply use a classic zap/restore toggle with the :keyenter label.  This is very basic stuff that should be familiar to most people already. We'll have the sprite start in the off state each time the board initializes.  So instead of placing the sprite and going to the draw loop, do this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 255&lt;br /&gt;
: goto &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: zap &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Since the status bar is now replacing the default enter menu, make sure to have the global robot turn that off by setting 'enter_menu' to 0.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That does it for our status bar.  You'll want to add in some test code and make use of the counter debugger to see that the various elements are reporting their numbers correctly, but you can take this robot and drop it on every screen on which you want to have a status bar.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.1|Example 3.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.2}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.2: Bullets as a layer (framework)====&lt;br /&gt;
Our next exercise is the most complicated individual piece of the engine yet: adding bullets and shooting to the game.  There's no easy way to break it into pieces, but it'll really take at least two exercises to fully explain.  So I'll do the best I can and break it into a framework phase, where we'll construct the basic skeleton for the code and explain what each part is going to do, and an implementation phase, where we'll implement each of the main subroutines and explain how they work.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, we need our basic sprite handler robot preamble.  You've written this thing several times already, but let's go over it again.  We need a one-time execution section that sets a counter based on the robot id, renames the robot based on it, and moves the robot to the robot bank (this part is not strictly necessary but we'll do it anyway):&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
We need a separator to prevent this code from happening more than once, and have the code after it happen every time the board loads:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
And we need some basic sprite initialization and placement:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playerbullets&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_pb_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_pb_h&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; &amp;quot;bminx&amp;quot; &amp;quot;bminy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We'll get to collision in a little bit, since it's going to be done a little bit differently than normal.  For now, we want to set up for a layer sprite that's going to fit snugly on top of the board's playing area.  And of course we make sure to create a reference counter for the sprite (playerbullets).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course we're going to need to set up the global robot to manage some of these counters, which are going to correspond to areas on the vlayer.  One thing we're going to need is an actual image for the player's bullets, separate from the layer the bullets get drawn on.  So add that to sprites.mzm and note its location, and then add some counters to global:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_pb_x&amp;quot; to 9&lt;br /&gt;
: set &amp;quot;spr_pb_y&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_pb_w&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr_pb_h&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;lyr_pb_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;lyr_pb_y&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;lyr_pb_w&amp;quot; to &amp;quot;('bmaxx'-'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;('bmaxy'-'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Another important thing we're going to need is a blank MZM the size of the layer, to use as a way to clear all of the bullets and redraw them.  You could go to the trouble of exporting this by hand, or you could do it the smart way and just have the global robot make it for you.  The vlayer consists of empty space by default, so we can just export an appropriately sized piece of it to make a blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;lyr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_pb_y&amp;amp;&amp;quot; for &amp;quot;lyr_pb_w&amp;quot; &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;@blank.mzm&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, we want to make sure the bullet sprite gets turned off between boards, so that its number can be properly reassigned if it changes.  Remember where the global robot section that performs this task is?&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playerbullets&amp;amp;_off&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now that we've got that out of the way, we need to figure out how bullets are going to work.  The idea is to have them all drawn on a layer that fits over the board, and to keep track of important stats for each bullet in an array.  For now these are basically position and velocity, where velocity will be effectively limited to moving in one of the four cardinal directions.  Our engine will work in a loop that will:&lt;br /&gt;
# Add any new bullets to the layer&lt;br /&gt;
# Move all of the bullets on the layer&lt;br /&gt;
# Check for bullet collisions with other sprites or walls&lt;br /&gt;
# Remove all bullets that have collided or moved off the screen&lt;br /&gt;
# Redraw the layer&lt;br /&gt;
As we've discussed before, the easiest way to tackle something like this is to break it down into component tasks.  So we'll make a loop that executes a bunch of subroutines in order:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#add&amp;quot;&lt;br /&gt;
: goto &amp;quot;#move&amp;quot;&lt;br /&gt;
: goto &amp;quot;#check&amp;quot;&lt;br /&gt;
: goto &amp;quot;#remove&amp;quot;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This loop will change somewhat when we actually implement these routines, but this is the basic idea.  Go ahead and add the label stubs for the subroutines, too.  For example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: . &amp;quot;TODO&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step: we're going to need to maintain a list of bullets on the layer, and we're going to need an interface to add to and remove from that list.  The easiest way to do this is to have a list of bullets to add and another list of bullets to remove, which are processed by each subroutine.  The player robot will add bullets to the add list when the player fires, and the bullet robot itself will add them to the remove list when they collide with something or move off the board.  The implementation is a little complicated and we'll discuss it in the next exercise, but for now, we should make sure the length of each list is set to 0 each time the board loads, so that we can start fresh.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This is all the set up we really need to do.  Running the code at this point won't do a single thing, but the framework is now in place for implementation.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.2|Example 3.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.3}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.3: Bullets as a layer (implementation)====&lt;br /&gt;
Now we come to the meat of the engine.  We can't really build this incrementally, but we can take each part individually since we've divided it up into distinct subroutines.  So that's just what we'll do.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt; First, the #add routine.  We're going to add a flag to a list (pbullets_add) each time the player fires a bullet, and then this routine will process that list every cycle, adding a set of bullet parameters based on the flag.  The flag we're going to use is the ID of the sprite that fired it (i.e. the player), and you might ask why we would even bother with a list at all and not just have a &amp;quot;bulletfired&amp;quot; flag that the player engine sets when it wants to shoot, or even a subroutine of its own to send.  The reason is because I prefer to generalize engines whenever possible; this engine in particular will be easy to use to handle multiple bullets from multiple enemies simultaneously with no problem at all.  Regardless, at this point we're not really concerned with how bullets get added to the add list, just with processing that list.  The list is of the form &amp;lt;tt&amp;gt;pbullets_add#&amp;lt;/tt&amp;gt; and has a length of &amp;lt;tt&amp;gt;pbullets_add&amp;lt;/tt&amp;gt;, and all of these values will be correct at the beginning of the routine.  So our subroutine is primarily a loop that processes this list:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_add'-1)&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we clear the add list once we're done, to prevent from processing the same stuff again next cycle.  New bullets will get added on top of the old.&amp;lt;br&amp;gt;&lt;br /&gt;
Now, each value in the list is a sprite ID (all the same ID in fact, but this will be a general case for later).  This means we have access to a host of information about a particular sprite, thanks to the object-oriented approach we've been following before with counter names, and the default sprite counters in general.  Notably, we have access to a set of coordinates and dimensions for the sprite (to help us decide where to put the bullet), and in the case of the player access to the last direction it moved (to help us decide which way the bullet should be firing).  We'll capture this reference out of the list into a temporary local counter, for easier access:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_add&amp;amp;loopcount&amp;amp;&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We also have a list of bullets containing various stats, which is referenced using the form &amp;lt;tt&amp;gt;pbullets#_stat&amp;lt;/tt&amp;gt;, and is &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; in length.  With zero indexing, this means we can add on to the end of the list by using &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; as an index.  Or more to the point:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_width'/2 + 'spr&amp;amp;local2&amp;amp;_x' - 'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_height'/2 + 'spr&amp;amp;local2&amp;amp;_y' - 'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expressions are a bit scary, but the basic idea is to put the bullet at the x/y coordinate of the player sprite, plus an offset to put it into the center of the sprite (half of the dimensions), and minus the offset for the location of the playing area relative to the actual board.  The reason for the last part is so that the bullets' x/y coordinates treat the 0,0 as the top-left of the playing area, since that's how the bullet sprite is placed.  The velocities are trickier: we want to translate a direction code (0 = north, 1 = south, 2 = west, 3 = east) into an x and y velocity component (we'll stick with -1, 0, and 1 for now, no need to get too fancy).  Remember that the counter for this is &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt;.  So the easiest way to do this is with a case structure, as follows:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#add('spr&amp;amp;local2&amp;amp;_lastmove')&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#add0&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullest&amp;amp;pbullets&amp;amp;_vy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Make sure to add four corresponding subroutines to the end of the program, out of the way of other code execution.  For your edification, I've left my two-line expression solution to this in the example code.&amp;lt;br&amp;gt;&lt;br /&gt;
Finally, we need to make sure the length of the bullet list is updated.&amp;lt;tt&amp;gt;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;quot; by 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
And we're done with this subroutine.  The game can now process a list of bullets and add them to our list.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Next, the move routine.  Moving is fairly simple in concept, except for one catch that we'll get to momentarily.  The gist is to process each bullet in the bullet list and add its velocity to its current location.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#move&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vx&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vy&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The catch is that bullets can move all the way off the playing field, in which case they need to be removed, or they'll end up being drawn on parts of the vlayer we'd like not to draw on.  We could handle this check in the #check routine along with collision, but it's still going to need handling, so we'll just do it here, next to the stuff it relates to.&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;(('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;lt;'lyr_pb_w')a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;lt;'lyr_pb_h'))&amp;quot; = 1 then &amp;quot;movenext&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;movenext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This block goes right before the end of the loop, after the bullet location counters have been updated.  The expression looks long and scary but this is actually an expression usage worth learning, since all it is is a bunch of conditional statements joined together with the AND operator.  Basically, if the bullet is still inside the defined playing area, the commands to remove it are skipped.  Removal is going to work much the same way adding does, with a list of bullets to remove.  Except in this case, the list contains indexes into the main bullet list.  In any case, that's all for the movement routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If it seems that all we've been doing so far is a bunch of abstract bookkeeping on numbers, the #check routine actually gets us back into the realm of sprites.  Here, we'll use the collision functionality provided by sprites to check each bullet and get a collision list for message sending with a minimum of fuss.  That means that the collision values need to be set for the layer first, for each bullet:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#check&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_pb_h&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This makes sure that we're dealing with a collision rectangle for each bullet on the layer, and can process them in turn.  Then, the actual collision is triggered:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_clist&amp;quot; to 1&lt;br /&gt;
: if &amp;quot;spr_collisions&amp;quot; &amp;lt;= 0 then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;checknext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here, I've decided to do things inline and short-circuit to the end of the loop, since I plan to use that label for something else in a moment.  Collision could also be done with a subroutine, of course, this is just how it happened to fall out when I originally wrote the engine.  Notice also that we're using the same removal method as before.&amp;lt;br&amp;gt;&lt;br /&gt;
We would be done with this here, except that we also need to do something about the sprite or sprites the bullet is colliding with.  This is just our basic collision handler loop, stuck in the middle:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;collide&amp;quot;&lt;br /&gt;
: if &amp;quot;spr_clist&amp;amp;local2&amp;amp;&amp;quot; = &amp;quot;playersprite&amp;quot; then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: send &amp;quot;spr('spr_clist&amp;amp;local2&amp;amp;')&amp;quot; to &amp;quot;playershot&amp;quot;&lt;br /&gt;
: inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local2&amp;quot; &amp;lt; &amp;quot;spr_collisions&amp;quot; then &amp;quot;collide&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Unfortunately we can't use a default loop structure since we're already in the middle of one, so we continue using local2 as a temp counter.  Notice in particular the breakout condition for when the bullet is colliding with the player.  This is done specifically to deal with the fact that each player bullet starts its life ''inside'' of the player, according to our #add routine.  We could do this differently, but this is an easy hack to get around that and prevent removing the bullet prematurely.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The #remove routine functions on a list of references to bullets to remove, as we've already seen.  This is to avoid the perils of deleting items from the bullet list in place, while we're iterating through it.  I have actually thought of an interesting way to do just that without negative side effects, but I'm not sure enough of it yet to use it in this tutorial, so I'm sticking with something I know will work.  In any case, removing a bullet from the bullet list will work much the same way as removing a key from the list of key sprites: we grab the bullet from the end of the list and put it into the location of the bullet to be removed.  In order to do this without risking serious malfunction though, we need to process the bullet list backwards.  That is, we need to remove bullets starting from the same end of the list that we're replacing them from, or we'll risk having a reference to a bullet that is no longer the same, or does not even exist, by the time we've gotten to the end.  Since replacing from the front is prohibitively complicated and costly to do, the easiest solution is to process the remove list backwards, since it's already sorted in ascending order.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#remove&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: dec &amp;quot;pbullets&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_remove('pbullets_remove'-'loopcount'-1)&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_remove'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember how we did the keys, we decrease the size of the list at the beginning so that we can have an easy reference to the end of the list, instead of the end of the list plus one.  The numbers don't actually go anywhere, so it doesn't matter if we decrease the length at the beginning or the end of the removal.  And as you can see, local2 is set to count backwards through the values in the remove list, which are indexes into the main bullet list.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_x&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_y&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vx&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vy&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This is the actual removal step, and as before simply involves some counters into others.  The only difference here is that there are more of them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Very near the end now, all we have left is the #draw routine.  Drawing is going to take care of all of the things necessary to repaint the layer, based on the numbers we've spent so much time setting up.  The first task is to wipe the layer clean with the blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, a loop for each of the bullets, to move the bullet image onto the layer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: loop start&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;spr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_pby&amp;quot; for &amp;quot;spr_pb_w&amp;quot; &amp;quot;spr_pb_h&amp;quot; to &amp;quot;#('lyr_pb_x'+'pbullets&amp;amp;loopcount&amp;amp;_x')&amp;quot; &amp;quot;#('lyr_pb_y'+'pbullets&amp;amp;loopcount&amp;amp;_y')&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, the end of the drawing, which for display purposes involves setting the &amp;lt;tt&amp;gt;spr#_cy&amp;lt;/tt&amp;gt; value so that bullets appear under everything:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You may wonder what this means for collision, if drawing happens afterwards, and whether collision will happen a cycle late.  But the default behavior for sprites is to collide with anything overlapping the collision rectangle, regardless of whether there is actually anything in it.  This can be changed with the &amp;lt;tt&amp;gt;spr#_ccheck&amp;lt;/tt&amp;gt; counter so that either character 32 (setting 1) or any empty character (setting 2) does NOT cause a collision, but for our purposes here that's not what we want.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step remains, and that's to revisit the main loop that actually calls all of the subroutines.  The astute reader will have noticed that the remove routine relies on having a sorted list, which the iterative approach in the move and check routines provides; but that there are two iterations to take into account, one for moving and one for collision checking, and so the list will not necessarily be completely sorted.  The simple way around this is to call #remove twice, once after #move and once after #check.&amp;lt;br&amp;gt;&lt;br /&gt;
The other snag is that the nature of the MZX loop structure always performs the loop once, even if there's nothing inside that we want to loop through.  This means that in the cases of empty lists, we don't want to call the subroutines at all.  Fortunately this is fairly easy to guard against:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_add&amp;quot; &amp;gt; 0 then &amp;quot;#add&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#move&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#check&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
There is, however, one thing that we do want to happen no matter what, and that's for the layer to be cleared and the collision set off the board when the last bullet disappears.  With that in mind, grab both of those commands out of the draw routine, and put them in the main loop instead:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it.  The engine still won't be doing anything, but it's no longer because there isn't any code behind it.  Instead, it's because there's nothing using the engine yet.  We'll cover that next in the section wrap up.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.3|Example 3.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.4}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.4: Interacting with the rest of the game====&lt;br /&gt;
After all of that setup, actually integrating the engine into the game is so simple it barely merits an exercise of its own.  In fact I'm considering moving all of this back into the framework exercise, since it would fit there and only take up a couple steps.  But for now, let's just finish this out.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;The first thing we need is a way to let the player shoot something.  Going with the standard MZX gameplay mechanic, this means the player robot needs to handle spacebar when an arrow key is pressed..  Simply add this line to each of the movement subroutines (#up, #down, etc.):&amp;lt;tt&amp;gt;&lt;br /&gt;
: if spacepressed then &amp;quot;shoot&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that the add routine is going to use the &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt; counter to determine which way the bullet should fire, so make sure this check happens after that gets set.  Then, set up the :shoot branch:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;amp;pbullets_add&amp;amp;&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_add&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This short-circuits the rest of the movement routine; the player can't move when spacebar is pressed now, only shoot.  Note that we don't have to send the bullet robot any sort of label, we just add an item to the list that we know will get processed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That gets the bullet engine rolling on the input side, and you can actually use it now and see it in action.  Output is even simpler: much like the player engine sends other sprites to :touch labels when it collides with them, the bullet engine sends them a :playershot label.  To see this in action, open up your key or door robot and add something like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playershot&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('local4'%16)&amp;quot;&lt;br /&gt;
: * &amp;quot;~&amp;amp;+local5&amp;amp;Ouch, you shot me!&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The extra step is an easy way to use the door's or key's color for the message, interpolating &amp;amp;+counter&amp;amp; returns a hexadecimal value.  Remember that local4 is the color of the key or door.  Unfortunately this can't be used with expressions, hence the need for an extra temp counter to extract the foreground color from the background.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Finally, to round it all off, let's actually tie the shooting to the value of the ammo counter.  That way, we can watch the ammo count down on the status bar when we shoot, and prevent from shooting when we're out of ammo.  Don't underestimate the usefulness of MZX's more specialized commands; here, the &amp;lt;tt&amp;gt;take&amp;lt;/tt&amp;gt; command provides exactly the functionality we need:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: take 1 AMMOS else &amp;quot;#return&amp;quot;&lt;br /&gt;
: ...&amp;lt;/tt&amp;gt;&lt;br /&gt;
Don't forget to have the global robot give the player some ammo up front, or this will stop you from shooting anything.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's all for now.  We're starting to have the beginnings of a really solid engine, all it really needs now are some enemies.  So we'll focus on that (and some other things) in the next section.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.4|Example 3.4 Code]]&lt;br /&gt;
&lt;br /&gt;
==External Links==&lt;br /&gt;
[http://www.digitalmzx.net/faq/sprite.html Saike's Sprite Tutorial] - Slightly out of date with regards to other MZX features.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]][[Category:Tutorial]]&lt;br /&gt;
{{stub}}&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=SWAP_WORLD_%22file%22&amp;diff=7691</id>
		<title>SWAP WORLD &quot;file&quot;</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=SWAP_WORLD_%22file%22&amp;diff=7691"/>
		<updated>2011-02-18T01:40:58Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Swap world''' is a MegaZeux command that swaps the current MZX world with the one stated. Its syntax is ''SWAP WORLD &amp;quot;filename&amp;quot;''.&lt;br /&gt;
&lt;br /&gt;
In the earlier days of MegaZeux, having large MZX worlds could cause instability, so it was often necessary to partition large games into several worlds even before hitting MZX's board limit. Upon swapping worlds, all &amp;quot;state&amp;quot; information in the current world will be thrown out, essentially resetting that world to its original state. However, all of the values for global counters are retained. This is often exploited to quickly and easily &amp;quot;reset&amp;quot; levels, as swapping a world to itself is valid. (The best-known example of this is [[MZX Combat Trainer]].)&lt;br /&gt;
&lt;br /&gt;
The existence of this command is why no '''load_world''' function [[counter]] exists.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]] [[Category:Command]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Swap_world&amp;diff=7690</id>
		<title>Swap world</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Swap_world&amp;diff=7690"/>
		<updated>2011-02-18T01:40:14Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Swap world to SWAP WORLD &amp;quot;file&amp;quot;: Current ideology is that commands reflect the help file's syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[SWAP WORLD &amp;quot;file&amp;quot;]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=SWAP_WORLD_%22file%22&amp;diff=7689</id>
		<title>SWAP WORLD &quot;file&quot;</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=SWAP_WORLD_%22file%22&amp;diff=7689"/>
		<updated>2011-02-18T01:40:14Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Swap world to SWAP WORLD &amp;quot;file&amp;quot;: Current ideology is that commands reflect the help file's syntax&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Swap world''' is a MegaZeux command that swaps the current MZX world with the one stated. Its syntax is ''SWAP WORLD &amp;quot;filename&amp;quot;''.&lt;br /&gt;
&lt;br /&gt;
In the earlier days of MegaZeux, having large MZX worlds could cause instability, so it was often necessary to partition large games into several worlds even before hitting MZX's board limit. Upon swapping worlds, all &amp;quot;state&amp;quot; information in the current world will be thrown out, essentially resetting that world to its original state. However, all of the values for global counters are retained. This is often exploited to quickly and easily &amp;quot;reset&amp;quot; levels, as swapping a world to itself is valid. (The best-known example of this is [[MZX Combat Trainer]].)&lt;br /&gt;
&lt;br /&gt;
The existence of this command is why no '''load_world''' function [[counter]] exists.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7688</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7688"/>
		<updated>2011-02-18T01:28:33Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Adding Music==&lt;br /&gt;
&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N editor command allows you to set the default music for a particular board. The default music will loop for as long as the player remains on the board. If two or more boards share the same song, and the game swaps between them, MegaZeux will not reload the song. You can also use Shift+8 or the Numpad * to set the board's default music to a wildcard, which essentially tells MegaZeux to continue playing the current music (if any).&lt;br /&gt;
&lt;br /&gt;
The other way to add music to a game is through Robotic. The [[MOD &amp;quot;file&amp;quot;]] command set's the current board's music to the chosen file. You can also set the board's default music to a wildcard by using MOD &amp;quot;*&amp;quot;, which does exactly what it does while in edit mode.&lt;br /&gt;
&lt;br /&gt;
There are also a number of commands that can be used to control the volume of the board music. [[VOLUME #]] allows you to directly set the volume of the playing song, from 0 (silent) to 255. [[MOD FADE # #]] allows you to fade the volume to a given value within a given number of cycles. Lastly, instead of calling MOD &amp;quot;file&amp;quot; (which plays the sound file at the default volume) you can dynamically fade songs in and out with [[MOD FADE IN &amp;quot;file&amp;quot;]] and [[MOD FADE OUT]]. You can figure out when MOD FADE OUT has finished fading out the current board music with [[WAIT MOD FADE]], which forces the robot to wait until MOD FADE OUT completes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[END MOD]]&lt;br /&gt;
&lt;br /&gt;
I honestly don't know what use there is to [[MOD SAM # #]].&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7687</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7687"/>
		<updated>2011-02-16T20:45:15Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Adding Music==&lt;br /&gt;
&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N editor command allows you to set the default music for a particular board. The default music will loop for as long as the player remains on the board. If two or more boards share the same song, and the game swaps between them, MegaZeux will not reload the song. You can also use Shift+8 or the Numpad * to set the board's default music to a wildcard, which essentially tells MegaZeux to continue playing the current music (if any).&lt;br /&gt;
&lt;br /&gt;
The other way to add music to a game is through Robotic. The [[MOD &amp;quot;file&amp;quot;]] command set's the current board's music to the chosen file. You can also set the board's default music to a wildcard by using MOD &amp;quot;*&amp;quot;&lt;br /&gt;
[[Categories:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7685</id>
		<title>Sound in MegaZeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sound_in_MegaZeux&amp;diff=7685"/>
		<updated>2011-02-14T20:55:30Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;==Major Supported Formats== *MOD *S3M *XM *IT *WAV *GDM ==Adding Music==  The simplest way to add music to a game is through the world editor. The Alt+N command allows yo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Major Supported Formats==&lt;br /&gt;
*[[MOD]]&lt;br /&gt;
*S3M&lt;br /&gt;
*XM&lt;br /&gt;
*IT&lt;br /&gt;
*WAV&lt;br /&gt;
*[[GDM]]&lt;br /&gt;
==Adding Music==&lt;br /&gt;
&lt;br /&gt;
The simplest way to add music to a game is through the world editor. The Alt+N command allows you to link a sound file to a particular board. Then during runtime, any boards that share a s  then select the sound file&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7684</id>
		<title>Message Box</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7684"/>
		<updated>2011-02-13T07:15:40Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Box''' is essentially a dialog box that displays text. They can be displayed either through the interaction between the [[Player]] and a Scroll or Sign, or can be displayed programmatically through robotic. Message Boxes created through robotic can also display options, which can be selected by scrolling down to them and hitting enter, which makes it easy to create shops driven by the Message Box.&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[. &amp;quot;@string&amp;quot;]]''' - The message box will display the name of the calling robot as a title when it's drawn.&lt;br /&gt;
&lt;br /&gt;
'''[[test|[ &amp;quot;string&amp;quot;]]''' &lt;br /&gt;
&lt;br /&gt;
'''[[&amp;amp; &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[% &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[? &amp;quot;label&amp;quot; &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[? &amp;quot;counter&amp;quot; &amp;quot;label&amp;quot; &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLARROW COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLBASE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLCORNER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLPOINTER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLTITLE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7683</id>
		<title>Message Box</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7683"/>
		<updated>2011-02-09T21:39:19Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Box''' is essentially a dialog box that displays text. They can be displayed either through the interaction between the [[Player]] and a Scroll or Sign, or can be displayed programmatically through robotic. Message Boxes created through robotic can also display options, which can be selected by scrolling down to them and hitting enter, which makes it easy to create shops driven by the Message Box.&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[test| [ &amp;quot; &amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLARROW COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLBASE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLCORNER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLPOINTER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLTITLE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7682</id>
		<title>Message Box</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Box&amp;diff=7682"/>
		<updated>2011-02-09T20:54:12Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;The '''Message Box''' is a dialog box that can be used to display text  ==Commands== ''' [ &amp;quot; &amp;quot;'''  '''SCROLLARROW COLOR (color)'''  '''SCROLLBASE COLOR (color)''...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Box''' is a dialog box that can be used to display text&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[test| [ &amp;quot; &amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLARROW COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLBASE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLCORNER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLPOINTER COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLTITLE COLOR (color)]]'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Built-in&amp;diff=7681</id>
		<title>Built-in</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Built-in&amp;diff=7681"/>
		<updated>2011-02-07T20:29:40Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''built-in''' is any feature native to MegaZeux that does not necessarily have to be managed with robotic. However, when one mentions the &amp;quot;use of built-ins&amp;quot; within a MegaZeux game, the built-ins they are usually refering to is the set of board objects (Players, Snakes, Scrolls, Doors, etc.) that have their own scripts managed by MegaZeux itself.&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Built-in&amp;diff=7680</id>
		<title>Built-in</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Built-in&amp;diff=7680"/>
		<updated>2011-02-07T19:53:40Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;A '''built-in''' is any feature native to MegaZeux that does not have to be&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''built-in''' is any feature native to MegaZeux that does not have to be&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7679</id>
		<title>Board</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7679"/>
		<updated>2011-02-07T19:53:30Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''Board''' is basically a playing field for which the game can take place in.&lt;br /&gt;
&lt;br /&gt;
==Limitations==&lt;br /&gt;
*Boards can range in size from 1x1 to a massive 32767x32767&lt;br /&gt;
**Extremely large boards will consume a massive block of memory. A board with the maximum dimensions would consume over 3 GB of memory.&lt;br /&gt;
**The BoardScan is a somewhat expensive routine that scans every square of the board every cycle for built-ins. The larger the board, the bigger the performance impact it can have on your game on slower computers. A good rule of thumb is to try to make boards not much larger than 1000x1000 in area.&lt;br /&gt;
*For a few [[Built-in|built-in objects]], there is a limit to how many can be placed on one board.&lt;br /&gt;
**All boards must have one and only one instance of the player object.&lt;br /&gt;
**Robots and scrolls are capped to 255 per board&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7678</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7678"/>
		<updated>2011-02-07T19:36:33Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For a comprehensive tutorial on sprites, see [[Sprite (Tutorial)]].&amp;lt;!--don't know how to do this properly--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[PUT color Sprite param # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite_Colliding pNN # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite p?? # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
===Instantiation===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_X]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_Y]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_HEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_WIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CWIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CHEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CLIST]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_CLISTn]] (read-only)''' &lt;br /&gt;
&lt;br /&gt;
'''[[SPR_COLLISIONS]] (read-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CCHECK]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_NUM]]'''&lt;br /&gt;
&lt;br /&gt;
===Graphical===&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_YORDER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OFF]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAID]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAY]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_STATIC]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_VLAYER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SWAP]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7677</id>
		<title>Sprite (Tutorial)</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7677"/>
		<updated>2011-02-07T19:33:08Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Despite the mystery and trepidation that generally surrounds them, '''[[Sprite|sprites]]''' are not that hard to work with and are designed to be easy to use, with the right program model.  Two common and effective models, which can be used together or alone depending on the requirements of the engine, are the '''sprite-layer model''' and the '''sprite-object model'''.  The structure of your code will depend on the application and the model being used, but there are some basics to cover first.&lt;br /&gt;
__NOTOC__ &lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid black; font-size: 1; display: table; padding: 1em&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;'''Contents'''&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[#Sprite Tutorial|Sprite Tutorial]]&lt;br /&gt;
:[[#S1|1 The Basics: Drawing Sprites]]&lt;br /&gt;
::[[#E1.1|Exercise 1.1: Making a sprite based player]]&lt;br /&gt;
::[[#E1.2|Exercise 1.2: Improving and generalizing the code]]&lt;br /&gt;
:[[#S1a|1a The Not So Basics: Sprite Collision]]&lt;br /&gt;
::[[#E1.3|Exercise 1.3: Adding basic collision detection]]&lt;br /&gt;
:[[#S2|2 The Sprite-Object Model: Active Collision]]&lt;br /&gt;
::[[#E2.1|Exercise 2.1: Keys and doors with sprites]]&lt;br /&gt;
::[[#E2.2|Exercise 2.2: Keeping track of sprites on the board]]&lt;br /&gt;
::[[#E2.3|Exercise 2.3: Moving the player sprite between boards]]&lt;br /&gt;
::[[#E2.4|Exercise 2.4: Finishing touches, fixing the scrolling]]&lt;br /&gt;
:[[#S3|3 The Sprite-Layer Model: Working With Layers]]&lt;br /&gt;
::[[#E3.1|Exercise 3.1: Creating a status bar]]&lt;br /&gt;
::[[#E3.2|Exercise 3.2: Bullets as a layer (framework)]]&lt;br /&gt;
::[[#E3.3|Exercise 3.3: Bullets as a layer (implementation)]]&lt;br /&gt;
::[[#E3.4|Exercise 3.4: Interacting with the rest of the game]]&lt;br /&gt;
&lt;br /&gt;
[[#External Links|External Links]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{a|S1}}&lt;br /&gt;
===The Basics: Drawing Sprites===&lt;br /&gt;
All sprites, regardless of their function, require some basic initialization and setup before they can be used.  First, you need to set aside space on the board (or the [[Vlayer]]) for the sprite source image.  You don't even have to put anything there yet, some advanced techniques construct the image data dynamically.  But you need a block of space that is going to be used for sprite data.  Next, all sprites need initialization code somewhere that designates this area.&lt;br /&gt;
 set &amp;quot;spr#_refx&amp;quot; to XCOORD      ''These counters specify the x coordinate, y coordinate,''&lt;br /&gt;
 set &amp;quot;spr#_refy&amp;quot; to YCOORD      ''width, and height of the bounding rectangle for the source image''&lt;br /&gt;
 set &amp;quot;spr#_width&amp;quot; to WIDTH      ''Replace # with the number of the sprite, from 0 to 255.''&lt;br /&gt;
 set &amp;quot;spr#_height&amp;quot; to HEIGHT    ''Counter interpolation is acceptable and in fact common for this.''&lt;br /&gt;
Finally, all sprites need to be placed somewhere in order to be viewed.  While &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot; counters do exist, and they can be written to place and move the sprite, we recommend you treat them as read-only and use the &amp;quot;put&amp;quot; command for readability and clarity of purpose:&lt;br /&gt;
 put c?? Sprite # at X Y        ''# is the number of the sprite to be placed, as a parameter.  Can be a counter.''&lt;br /&gt;
{{a|E1.1}}&lt;br /&gt;
====Exercise 1.1: Making a sprite based player====&lt;br /&gt;
A common application for sprites is to have all actors in the game, including the player, be represented by sprites.  This lends itself well to a sprite-object model, but we'll come to that later.  Our first exercise will be to make a player sprite that can be moved around with the arrow keys.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, start editing a new world, and draw a customblock smiley face on the board.  It doesn't really matter what it looks like, or where it is, but for the sake of example put it at (80,0) off the right edge of the screen, and make it 3x3 characters large.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Create a new robot called &amp;quot;sprite&amp;quot; to handle the sprite drawing and moving code.  I like to put my control robots in a horizontal line starting at (1,0), but again, it really doesn't matter.  The very first line of the robot should be &amp;quot;lockplayer&amp;quot;, just to keep the player from moving around.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Let's use sprite 0 for our player.  So, the next 4 commands should be:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr0_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr0_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr0_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr0_height&amp;quot; to 3&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a control loop that draws the sprite and handles input.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite p00 at &amp;quot;x&amp;quot; &amp;quot;y&amp;quot;&lt;br /&gt;
: if uppressed then &amp;quot;up&amp;quot;&lt;br /&gt;
: if leftpressed then &amp;quot;left&amp;quot;&lt;br /&gt;
: if rightpressed then &amp;quot;right&amp;quot;&lt;br /&gt;
: if downpressed then &amp;quot;down&amp;quot;&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that x and y will default to 0 since they haven't been used yet.  It's generally a good idea to keep this information in a pair of local counters and initialize them along with the rest of the sprite data.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, you just need code to modify the values of &amp;quot;x&amp;quot; and &amp;quot;y&amp;quot; for each label &amp;quot;up&amp;quot;, &amp;quot;left&amp;quot;, &amp;quot;right&amp;quot;, and &amp;quot;down&amp;quot;.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: dec &amp;quot;y&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And the rest should be obvious: inc &amp;quot;y&amp;quot; by 1 for &amp;quot;down&amp;quot;, dec &amp;quot;x&amp;quot; by 1 for &amp;quot;left&amp;quot;, and inc &amp;quot;x&amp;quot; by 1 for &amp;quot;right&amp;quot;.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.1|Example 1.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E1.2}}&lt;br /&gt;
====Exercise 1.2: Improving and generalizing the code====&lt;br /&gt;
That's it, you can now test your world and move the sprite around.  You'll notice that the sprite gets &amp;quot;stuck&amp;quot; if you move it off the top or left of the board, and disappears off the bottom right.  That's because we didn't do any bounds checking.  In fact, there are a lot of improvements we can make to this code before we move on.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First let's make the sprite initialization dynamic.  This may seem like more work now, but it'll make things much easier when you want to play with a lot of objects later, and decide that you need to reallocate sprite numbers.  We'll declare local counters for the sprite draw location while we're at it.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to 3&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;We also need some bounds checking.  I prefer to define variables for zone boundaries, but we'll use constants with [[expressions]] for now.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: : &amp;quot;down&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that &amp;quot;local3&amp;quot; is &amp;quot;y&amp;quot;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You also probably noticed that the previous movement routine favored certain directions over others; you can fix this by turning the label calls into [[subroutines]] (with diagonal movement as a free bonus!)&amp;lt;tt&amp;gt;&lt;br /&gt;
: if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One pitfall that comes with using subroutines for movement like this is that it's possible to get the sprite stuck on corners as you move it.  This is because the sprite position is not updated after the sprite counters are changed, but only after every move direction has been checked.  One way to fix this is to just use the spr#_x and spr#_y counters instead of local counters, since those are directly tied to sprite position.  But for reasons we'll discuss later, I recommend against this, or at least keeping copies of them in local counters.  The other way is to make sure the sprite is updated (i.e. drawn) after each move.  This is accomplished most easily through subroutines as well:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for every location where the sprite needs updating, that is at the end of all movement subroutines and within the main loop, call the subroutine &amp;quot;#draw&amp;quot; with a goto.  In fact, it's not really even necessary to call this in every iteration of the main loop if it's called on movement.  It only needs to be called once after all the sprite counters have been initialized.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Since this is our player sprite, it would be nice if we could get the screen scrolling to act like it.  Fortunately there's a really easy way to do this without having to work out a bunch of bothersome math.  Just put the following functional counter in your #draw subroutine, after you draw the sprite:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Really simple, and another good reason to have a separate subroutine for the drawing code, since that makes it easy to update and augment.  You can now expand the board area and bounds checking beyond the confines of the viewport.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This leaves us with this final code:&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.2|Example 1.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S1a}}&lt;br /&gt;
===The Not So Basics: Sprite Collision===&lt;br /&gt;
So we can now draw a sprite and move it around the screen.  This is great, but except for some very limited cases is not particularly useful for gameplay.  Simple bounds checking is easy enough to implement, but what if we want to have our player sprite move around inside a defined terrain, with walls and solid objects and impassible barriers?  Worse, what if we want to interact with the environment, or with other sprites?  Designing this from scratch would involve doing a lot of checking for [[customblocks]], a way to figure out which sprite is at a specific location, and depending on the size of the sprite being moved, would require checking multiple locations each time in order to ensure consistency.  It would be difficult to make the system general enough to be transplantable from game to game, and if you did manage it it would be hard to read and understand the code.&lt;br /&gt;
&lt;br /&gt;
Fortunately, MZX provides a way to do all that work with one statement:&lt;br /&gt;
 if c?? Sprite_colliding p## at X Y then LABEL   ''p## is the number of the sprite you want to move, X and Y are relative coordinates.''&lt;br /&gt;
One of the reasons people find this simple command so difficult to use is that they don't understand what it actually does.  The first important requirement is that the sprite being moved define a collision rectangle.  This should be done along with the other sprite initialization counters like so:&lt;br /&gt;
 set &amp;quot;spr#_cx&amp;quot; to X             ''These X and Y coordinates are relative values.''&lt;br /&gt;
 set &amp;quot;spr#_cy&amp;quot; to Y             ''That means you set them relative to (0,0) as the top left corner of the sprite.''&lt;br /&gt;
 set &amp;quot;spr#_cwidth&amp;quot; to WIDTH     ''So if you want the collision rectangle to be the same size and area as the sprite itself,''&lt;br /&gt;
 set &amp;quot;spr#_cheight&amp;quot; to HEIGHT   ''cx and cy should both be 0, and cwidth and cheight should be the same as width and height.''&lt;br /&gt;
Most people understand this much.  What often gets confused is that the Sprite_colliding object in the if statement is NOT this collision rectangle.  Nor does it directly represent the collision rectangle of another sprite, though it is necessary for other sprites to have collision rectangles in order for collision to work.  But there isn't an actual sprite_colliding object anywhere on the board, this is simply the syntax used to call collision detection for a sprite in advance of movement.  The command says &amp;quot;if I hypothetically move this sprite (specified by the parameter) X by Y from its current location, will it collide with anything.&amp;quot;  And then it branches depending on whether the answer is true or false.&lt;br /&gt;
&lt;br /&gt;
The two key points about X and Y are that they are ''relative'' to the sprite's current location, and they specify the ''movement'' of the sprite, not the position of something else.  The color term is co-opted to perform a non-intuitive task of specifying relative versus absolute movement.  c?? means that X and Y are relative values, and is what you will normally want to use.  c00 (or any other absolute color) make X and Y absolute coordinates, but again the statement checks to see what would happen if you put the sprite at that location, not for the presence of some other object at that location.  This is vital to understand, since without it you will probably try to do much more work than you need to do, and will probably achieve unexpected and incorrect results for your efforts.&lt;br /&gt;
&lt;br /&gt;
{{a|E1.3}}&lt;br /&gt;
====Exercise 1.3: Adding basic collision detection====&lt;br /&gt;
Let's see if we can't improve our player sprite code and turn it into something you might actually want to use in a game.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, take that board you were working on and draw some walls on it.  Sprite collision detection only works with customblocks and other sprites, so in any game where you want to use sprite collision, all of your collidable scenery should be customblock.  But if you're really interested in advanced MZX programming and artwork, you should already be doing this anyway.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;In order to create the illusion of depth and a 3/4 camera angle, we'll define the collision rectangle as being only the bottom row of the sprite.  The sprite dimensions are 3x3, so that means:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 2&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Update each of your movement subroutines to include a collision check along with the bounds check:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, going along with that 3/4 camera thing, you will generally want game sprites farther down the screen to appear &amp;quot;in front&amp;quot; of sprites above them.  Sprites have a globally applicable drawing mode to handle this very thing:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_yorder&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that this counter is global to all sprites, and is not a per-sprite counter.  You can stick it anywhere you like, but it makes the most sense to put it in the global robot.  We will discuss how to use layer-like sprites with yorder later.  For now, all you need to know is that this makes sprites draw in order of position from the top of the screen to the bottom, instead of in order of their sprite numbers.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it!  That's really all you have to do!&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.3|Example 1.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S2}}&lt;br /&gt;
===The Sprite-Object Model: Active Collision===&lt;br /&gt;
It's wonderful and all that we can make sprites not do something (i.e. move) if they collide.  But what if we want to make them do something else instead?  What if we want that thing to be different depending on the object of the collision?  When you perform a collision check with &amp;quot;if sprite_colliding&amp;quot;, it has the side effect of populating an array-like construct that details what, if anything, was collided with.  This array is called &amp;quot;spr_clist&amp;quot;, its length is stored in the counter &amp;quot;spr_collisions&amp;quot;, and it is accessed as pseudo-arrays usually are in MZX, through counter interpolation.  Here is a typical and flexible collision handler:&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;        ''This will only goto labels that actually exist, making it easily pluggable.''&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;  ''This will send to a robot named with the same number as the colliding sprite.''&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;                ''Don't forget about the loop termination quirk, where the terminator is inclusive.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Short circuits whatever else would have been done had collision not happened.''&lt;br /&gt;
 : &amp;quot;#collide-1&amp;quot;                                 ''-1 is the background, meaning the sprite collided with a customblock.''&lt;br /&gt;
 * &amp;quot;~fOuch, I bumped into a wall!&amp;quot;              ''Normally you wouldn't bother with this label though, since a wall is a wall.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Continues collision handling.  Remember, subroutines go on a call stack.''&lt;br /&gt;
The send command is the beginning of understanding sprites with an object model, where each sprite is bound to code in a robot specific to that sprite, so that everything relevant to that sprite (including counters you may create) can be accessed with a single number.  Here, we use that number to send the sprite (and I find it useful to make no distinction between the sprite and the robot controlling it) a touch label.&lt;br /&gt;
&lt;br /&gt;
You should devise and maintain a convention for what robots that control sprites should be called.  &amp;quot;sprite#&amp;quot; or &amp;quot;spr#&amp;quot; are normal, or you could just reference them by number.  In order to make things as code driven as possible, so that you only have to change a single line to reassign a sprite number in a robot, you should do this dynamically in your robot setup with a rename command.  And there's some other stuff you can do to make it easy to move sprites around just by moving the robots that control them.&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;   ''This makes things very dynamic, since you can copy the same robot around the board with no changes''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;     ''and make multiple copies of the sprite.  Setting local2 and local3 based on the robot's position''&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;     ''means that you don't have to configure the initial sprite placement, either.  Then you can move the''&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0            ''robot into a robot bank at the top of the board, and the unique value of local ensures you won't''&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;             ''overwrite anything.  But this is not always appropriate, sometimes you'll want to choose a specific ID''&lt;br /&gt;
&lt;br /&gt;
{{a|E2.1}}&lt;br /&gt;
====Exercise 2.1: Keys and doors with sprites====&lt;br /&gt;
Now that we have an idea of how to make our sprite player touch things, let's create some things for him to touch.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, the player needs a collision handler.  You can use the one we just discussed with no modification (though you may want to take out the #collide-1 label since that's just to demonstrate how to do something special based on what you collided with).  You'll also need to change the target label for the collision check to &amp;quot;collision&amp;quot;:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And so on.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You need to create some key objects and some door objects, at least one of each, but creating more than one will be really, really easy.  Each of these will be sprites, and each of them will have a robot in control.  First, draw some graphics over with the player source you had before.  Remember what their parameters are.  If you want to do something REALLY cool, create a list of constants and put it in the global robot to keep track of these numbers for you.  This way, if you ever change them, or do something like making your sprites vlayer based, you'll have a much easier time of things since you'll only have to change the global robot.  In any case, use what you've learned about sprites so far to create a robot called &amp;quot;key&amp;quot; with a dynamic initialization routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to XCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to YCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to WIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to HEIGHT&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to CX&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to CY&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to CWIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to CHEIGHT&lt;br /&gt;
: put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Of course you'll need to provide your own values for those counters, and as I've said, I really recommend assigning them to constant counters whose values you set all in one place.  It makes things much easier later, when you want to change the way things are done.  Also notice that in addition to reading the coordinates of the key based on where you put the robot, it also reads the color of the key and draws the sprite accordingly.  This means we can use exactly the same robot code for different colored keys, without changing a thing except the color of the robot itself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now you need a &amp;quot;:touch&amp;quot; label.  In the case of a key, if you touch it you just collect the key and it disappears.  So we need a counter to keep track of the key, and we need to make the sprite disappear.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&lt;br /&gt;
What we've done here is increment a counter that is unique to the color of the key.  This means we can collect more than one of the same color key, and open just as many doors.  The spr#_off counter is a special functional counter which turns off sprite drawing and sprite collision when it is set to something.  It does NOT set the sprite's counters to zero, though.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy that key robot and make a door robot out of it.  I'm serious, the changes you'll be making are so slight that they don't warrant starting from scratch.  Just change the values of the sprite initialization to suit, and change the behavior in the touch routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
We perform a simple check to make sure that the player collected a key that is the same color as this door.  Other than that, it's a mirror image of the key's touch routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy those two robots all over the board.  You may actually want to do this with copyrobot commands, so that you only have to change the code in one place, when you need to change it.  Or, if you want to be clever, save the robot code into a [[file access|file]] and load from that.  Whatever you do, put a bunch of copies of the key and door code onto your board, using as many different colors as you like.  Now play around with it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.1|Example 2.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.2|}}&lt;br /&gt;
====Exercise 2.2: Keeping track of sprites on the board====&lt;br /&gt;
So far, the only time we've needed to have sprites talk to other sprites or refer to them by ID is when they collided, and then the numbers are provided for us.  But suppose we want to know which sprite is the player and where it is, so that we can allow another robot controlling another sprite (like an enemy) to target it?  Or what if we want to have the same sprite run around the board stealing keys (we'll actually do this in an upcoming example)?  It'll need to know where they are too.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;For the player, this is simple enough, we can just have the following line in our initialization:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Can't get much easier than that.  But for keys and doors, we need to be a little bit more clever, since there can be arbitrarily many of those.  Just using their color (local4) as an identifier isn't enough, since that might not be unique on the board, and besides that we'd like a solution to enumerate a list of things.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;First, in the global robot, initialize a couple of counters to keep track of the number of keys and doors on the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;num_doors&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Then in the key init code (and similarly for the door code), add each key to the end of a list and advance the counter:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;num_keys&amp;quot; by 1 &amp;lt;/tt&amp;gt;&lt;br /&gt;
We also store the sprite's position in the list and attach it to the sprite, double linking them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Why bother spending overhead on this, and making this counter public?  So that we can easily prune the list when the player collects a key or opens a door.  Here's a neat trick to quickly remove an item from an array without leaving a hole:&amp;lt;tt&amp;gt;&lt;br /&gt;
: dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
Let's pause here and explain what we've just done in more detail.  First, we create a list of sprite/robot ids (they're the same in our system, remember).   We populate this list by first setting the length of the list to zero, and adding each item to the end of the list as its robot gets executed.  We also know that these items are subject to being removed from the list of active sprites in certain game situations.  Now we can set things up such that the list will be automatically regenerated if we leave the board and come back (more on that in the next example).  But when we start using lists to keep track of lots of objects that get added to and deleted from the list a lot (e.g. bullets), we'll really appreciate having a way to perform those add and delete operations in constant time, while limiting the time to iterate over the list down to the number of currently active items.&amp;lt;br&amp;gt;&lt;br /&gt;
The key observation that makes the above trick work is that the list doesn't need to be sorted.  So all we need to do to deal with the hole left by a deleted list item is find another item to put in the hole.  And there's always an item at the end of the list, even if it's the very item we're deleting.  We tell the sprite at the end of the list that it's list position (spr#_lpos) is now the position of the item we're deleting (this is why that counter needed to be public).  And then we tell the list that the id at that position is now the id at the end of the list.  Finally we decrease the length of the list (it's safe to do this first as shown in the code because the data doesn't actually go anywhere), effectively removing the last item on the list.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;li&amp;gt;This exercise has largely been in preparation for things to come.  But in order to demonstrate its usefulness quickly, let's create a simple debug robot to print the status of all of our sprites on the board.&amp;lt;tt&amp;gt;&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyt&amp;quot;&lt;br /&gt;
: [ &amp;quot;The player is sprite &amp;amp;playersprite&amp;amp;, located at (('spr&amp;amp;playersprite&amp;amp;_x'), ('spr&amp;amp;playersprite&amp;amp;_y')).&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_keys&amp;quot; &amp;lt;= 0 then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: [ &amp;quot;Key sprite #&amp;amp;local&amp;amp; is located at (('spr('keysprite&amp;amp;local&amp;amp;')_x'), ('spr('keysprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_keys&amp;quot; then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_doors&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: [ &amp;quot;Door sprite #&amp;amp;local&amp;amp; is located at (('spr('doorsprite&amp;amp;local&amp;amp;')_x'), ('spr('doorsprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_doors&amp;quot; then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Just copy this into a new robot (put it somewhere other than the top row of the board) and press 'T' to access it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
[[Sprite Code Examples#Example 2.2|Example 2.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.3|}}&lt;br /&gt;
====Exercise 2.3: Moving the player sprite between boards====&lt;br /&gt;
Almost any real game is going to involve more than one board (single board content management via [[MZM|MZMs]] aside).  However, successfully managing sprites across multiple boards requires some overhead and foresight.  Before we go any further, we need to address one of the major gotchas of sprites, which is that you have 256 of them to use in the entire GAME, not per board.  This means that, especially for a dynamic sprite system, you need a way to ensure that sprites are kept consistent and in the same places across boards.  &lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;What this generally means is that we want to have the sprite initialization happen every time you load the board, implying the use of :justentered.  But there are also parts of our sprite initialization code that we want to happen only one time, like setting the initial sprite position by using the initial robot position and then moving the robot.  Fortunately there's a simple trick for pulling this off:&amp;lt;tt&amp;gt;&lt;br /&gt;
: . &amp;quot;One time execution code goes here.&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: . &amp;quot;Static initialization code goes here (sprite ref and collision box among others).&amp;quot;&lt;br /&gt;
: . &amp;quot;Fallthrough to main program loop.&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember your robotic, a pipe is a pre-zapped label.  This should be applied to the global robot as well, for sprite list setup.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course there are things, especially for sprites that are going to move around, that must be preserved on a board change but which are subject to change.  This is the reason I suggested the use of &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; to keep track of sprite position, instead of &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot;.  But the player needs a system that doesn't simply preserve its position on each board, but which accurately sets its position based on where it was on the previous board.  This means that the player sprite needs to use global counters instead of local counters.  So do a search and replace on &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; in the player robot (CTRL+R is your friend) for counters like &amp;quot;player_x&amp;quot; and &amp;quot;player_y&amp;quot;.  Then add this code to the one time execution segment of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The reason for the locals as temps will become clear in a moment.  Now add this code to the board init section:&amp;lt;tt&amp;gt;&lt;br /&gt;
: lockscroll&lt;br /&gt;
: set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
: set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
: put player 0 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
Now you can us the player object itself to mark the start position of the player sprite, and be able to test from that position on any board.  We lock scrolling because of what we do with the player in the next step, to prevent the viewport from jumping around.  It no longer really matters where you put the player robot, as long as you don't put it in the top row (for safety reasons, since all the sprite robots move to that line and it might get overwritten before it moves).  Also note the use of &amp;quot;player_x&amp;quot; instead of &amp;quot;playerx&amp;quot;, since &amp;quot;playerx&amp;quot; and &amp;quot;playery&amp;quot; are built-in and read-only.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to know when the sprite moves off the board.  Fortunately bounds checking allows us to do just that.  For each movement routine, add a sprite counter that tells which direction the sprite last moved, and then route the bounds check to a label that sends the global robot a message, like so:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;lt;= &amp;quot;bminy&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we're going to use a nice little shortcut so that we can keep track of board adjacencies with the standard MZX system instead of writing another data structure to do it.  All it requires is that the four corners of each board you use it on be empty.  That's because we're going to use the player object itself to move between boards, instead of using teleport player.  Write each edge# method similar to this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: . &amp;quot;North&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('bmaxy'-'spr_p_h')&amp;quot;&lt;br /&gt;
: . &amp;quot;That is, the bottom of the sprite playing field minus the height of the player sprite.&amp;quot;&lt;br /&gt;
: put player 0 0&lt;br /&gt;
: . &amp;quot;Use board_w-1 and board_h-1 to move south and east.&amp;quot;&lt;br /&gt;
: move player NORTH&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The idea here is to set temp counters to the expected location of the player sprite on the next board, then move the actual player to that board.  We don't use the actual counters so that if the move fails (there is no board in that direction), nothing happens to the sprite.  But if the move succeeds, the justentered label will be triggered and the values will be committed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Obviously for this to work right, those &amp;quot;bminy&amp;quot; and &amp;quot;bmaxy&amp;quot; counters need to actually exist.  They also need to be the same across all boards; if the boards need to have different dimensions you will need a more complex system.  But for this simple case, just add those to the one-time code of the global.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
You can use whatever values you like, of course, at this point it's more up to the requirements of your game than anything else.  You can and should replace all hard-coded values in the player bounds checking with these counters, as seen above.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final thing remains to be done, and that's to make sure all the sprites being used at the time of the board transition are turned OFF. We may have done a lot of work to make sure sprites can initialize properly each time the board loads, but if we don't destroy them before moving to another board then any sprites that don't get reinitialized will hang around.  Now it would be possible to just loop through all 256 sprites and turn them all off to be safe, but that may not always be optimal, and besides that this is a perfect application for those lists we made earlier.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_doors'-1)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Stick this at the front of the global board init, and it'll be the first thing executed when a board loads.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That's really all that needs to be done at this point.  Test it out by creating a few interlinked boards and spread your doors and keys across them.  You'll need to copy the sprite source data between the boards too.  (Writing an [[MZM#MZM Tutorial|MZM loader]] for this into the global robot is left as an exercise to the reader.  I actually recommend using the vlayer to store them though, and we'll do this in the next step, so brush up on the [[vlayer#VLayer Tutorial|vlayer tutorial]] for more info.)&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.3|Example 2.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.4}}&lt;br /&gt;
====Exercise 2.4: Finishing touches, fixing the scrolling====&lt;br /&gt;
Before we wrap up this section for good, there's a bit of cleanup work we need to do.  Most pressing, and something you will have noticed by now unless your boards are all the same size as the bounding area for your sprite playing field, is that the simple directions I gave you for scrolling the viewport don't work right, or not the way you'd really want them to. If your sprite images are still on the board, you probably want them to not be visible; you'd like the &amp;quot;board&amp;quot; that the player sprite moves on to stop before you get to things that are off the screen.  There are really only two ways to handle this: either put nothing on the board that is not intended to be seen (i.e. use the vlayer and some other tricks), or use complicated math to clamp the viewport to the edges of the playing area, to prevent the player from seeing things that are not intended to be seen.&lt;br /&gt;
&lt;br /&gt;
I wrestled with how to present this material for close to a year, since there are just so many problems with it.  One problem is that it's mostly just necessary busywork, tying off loose ends so that the engine functions more smoothly; it doesn't really fit in with the flow of the tutorial, but it really needs to be done now before we proceed to the next major section.  Another problem is that doing things in an easily pluggable way that only involves adding a few lines in key places requires some very complex [[expressions|expression hacking]] that just isn't appropriate to teach in a tutorial about sprites; while doing it in a way that is easy to understand requires more additions and modifications than I'd really like.  So ultimately I've decided to give you as many options as possible.  If you want to skip as much of this nonsense as possible and get right on to the sprite-layer model, just follow step 1 to get your sprites on the vlayer, and step 1a to deal with the details of only doing that.  If you want to go the whole nine yards, the rest of the steps will show you, in order of necessity, how to tweak the engine to handle scrolling inside of a bounded area.  You can stop following them whenever you're satisfied with the results.  And if you're interested in my preferred method for doing this, the last step will show you the expressions for compressing 50 lines of code into 5.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, one thing that absolutely must happen before we move on to sprite layers is that we start using the vlayer for sprites.  If nothing else, we don't want to have to set aside broad swaths of space on each board for sprites that are as large as the playing area itself.  So, export your sprite image data to something like &amp;quot;sprites.mzm&amp;quot;, and add the following line to the one-time code of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You'll also need to adjust all the coordinate constants for the sprites appropriately, by subtracting 80 from the refx coordinates.  So for example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_p_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_d_x&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr_k_x&amp;quot; to 6&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, all sprite robots need a line in their board init to reference them from the vlayer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;ol type=&amp;quot;a&amp;quot;&amp;gt;&amp;lt;li&amp;gt;If this is the only step you want to take, there are a few more small things to do.  First, make sure the board size, and the dimensions specified by bminx, bmaxx, bminy, and bmaxy, are the same.  The easiest way to do this is to set them in the global robot directly based on the board settings:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to &amp;quot;board_w&amp;quot;&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to &amp;quot;board_h&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You will then need to draw overlay artwork on the areas of the board where the robots will reside (i.e. the top row) and in the top-left and bottom-right corners where the player can be.  Finally, to accomodate this, all sprites that might move into these areas (notably the player) need to have this line added to their setup:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_overlaid&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
This will ensure that the sprites appear over the overlay you've drawn, with the drawback that you won't be able to draw overlay to appear above them.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to correct the scrolling.  The easiest way to conceptualize this is to create a subroutine for each boundary that resets the viewport to line up with that edge, and then to call those subroutines each time the current scrolling code causes the viewport to cross any boundary.  The subroutines will all go at the end the player robot, and will be called conditionally inside of the &amp;quot;#draw&amp;quot; subroutine, right after the &amp;lt;tt&amp;gt;spr#_setview&amp;lt;/tt&amp;gt; line.  So for example, the left edge works like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;lt; &amp;quot;bminx&amp;quot; then &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;bminx&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The right edge requires a little bit more, since we need to take the width of the viewport into account:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;gt; &amp;quot;('bmaxx'-'vw')&amp;quot; then &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;('bmaxx'-'vw')&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The other two edges are basically the same, with different counters in the appropriate places.  Of course, the counter vw, and its brother vh (for viewport width and viewport height) need to exist.  MZX doesn't have built-in counters to read these values, so we need to set them ourselves, in the global robot one-time code:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;vh&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
This allows them to be easily changed later, in case we decide we want the viewport to be smaller than the full screen.  As a final step, so that the player and robots don't have to be covered up with overlay, we want to make sure the playing area for the sprites has at least a character of margin around it, for the player and robots to live in and move around.  This means that bminx and bminy should both be changed to 1, at least, and bmaxx and bmaxy should both be at least one less than the width and height of the board.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;There will be a minor problem with a visible scroll snap when you move from board to board.  This is because the board draws before any of the robots on it run, so the scroll correction code in the player robot will only take effect after the board has been drawn once.  To fix this, we'll put some corrective code into the only robot that runs before the screen is drawn: the global robot.  The basic idea here is that, similar to how we move the player to the opposite side of the playing field every time we change boards, we'll do the same with the viewport.  We'll use &amp;quot;local4&amp;quot; and &amp;quot;local5&amp;quot; as carry-over counters for this purpose.  First, in the board init, right after the lockscroll command:&amp;lt;tt&amp;gt;&lt;br /&gt;
: scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for each of the :edge# routines, we set these counters, similarly to the way the clamping routines worked in the last step.  So for moving north, we want the screen to end up on the bottom edge:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('bmaxy'-'vh')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Similar additions apply to the other routines.  Finally, we want local4 and local5 to have values on the first board.  We could perform the same complicated scroll correction routine the player robot uses to make sure the viewport is inside the playing area, but that's really a waste of code for something that's only ever going to be used once at the very beginning of the game.  So we'll just set them in the one-time code based on the initial scroll location:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The put player command is an interesting one, since it consumes a cycle only if it actually causes the player to move.  But this does mean that there will be an extra cycle of delay whenever we move south or east, since then the player DOES have to move to the opposite end of the board.  This isn't that important, but as long as we're cleaning up loose ends, we might as well handle this.  Similar to the scroll correction we did before, we will set up subroutines to move the real player object to the correct edge of the board, based on the location of the player sprite, and then call them conditionally in a loop.  This way, the player will always be at the correct location in advance.  So, after the global board setup, instead of just ending the program, create a loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playerloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;playerloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then create the subroutines and if calls.  To check if the player is on the left side of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_x&amp;quot; &amp;lt; &amp;quot;('bminx'+'bmaxx'/2)&amp;quot; then &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: put player at 0 &amp;quot;playery&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Or for the bottom of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;gt; &amp;quot;('bminy'+'bmaxy'/2)&amp;quot; then &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: put player at &amp;quot;playerx&amp;quot; &amp;quot;('board_h'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expression used in the comparison is a simple midpoint calculation for the board playing area.  All you have to do now is remove the put player commands from the edge handlers, since the player will already be in the right place to move when they're called.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The subroutine system is pretty easy to understand and works just fine, but I personally don't like to use it when I don't have to, just to save on commands.  Instead, when I have a situation that involves setting one value to a choice of two or three values depending on some condition, I like to cram all the logic into an expression that will execute in one command.  This is purely a preference on my part, it doesn't make the code that much more efficient and it certainly doesn't make it more readable.  But it does make it shorter.  So in the case of scroll correction, this is what I do:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns what was 16 lines into three; it would be one, but the expressions are so complicated that they won't fit side by side in one line.  The first two lines there can also be applied at the beginning of the global robot to local4 and local5, instead of simply &amp;quot;scrolledx&amp;quot; and &amp;quot;scrolledy&amp;quot;, to more accurately set the initial location of the viewport.&amp;lt;br&amp;gt;&lt;br /&gt;
Then, for moving the player around, I use this construct:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put player at &amp;quot;('bminx'+'bmaxx'/2&amp;lt;'player_x'*('board_w'-1))&amp;quot; &amp;quot;('bminy'+'bmaxy'/2&amp;lt;'player_y'*('board_h'-1))&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns those 16 lines into a single line, without the need for any intermediate steps.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This concludes the section on sprites as objects.  It got a little sidetracked at the end, but this is all necessary maintenance work if you want to use sprites as objects in a full-fledged game.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.4|Example 2.4 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S3}}&lt;br /&gt;
===The Sprite-Layer Model: Working With Layers===&lt;br /&gt;
Understanding sprites as layers is not really that complex a concept to grasp.  The basic idea dates back to MZX feature requests for having multiple overlays or underlays in the game, so that you could use different layers to handle different tasks.  The feature was rejected as is, but sprites can fill this role just fine.  Up till now we've thought of sprites as relatively small objects linked to specific actors in the game.  Now, we'll be using sprites as very large objects that can cover the whole screen or even the whole board.  Instead of placing a small sprite at a location on the board to change what the player sees, we will paint image data onto a large sprite to accomplish the same thing.&lt;br /&gt;
&lt;br /&gt;
There are a few useful status commands for working with layer-like sprites&lt;br /&gt;
 set &amp;quot;spr#_vlayer&amp;quot; to 1    ''Sets the sprite to get its image data from the vlayer instead of the board.''&lt;br /&gt;
 set &amp;quot;spr#_overlaid&amp;quot; to 1  ''Makes the sprite appear over the overlay. Ideal if using the overlay in a traditional way.''&lt;br /&gt;
 set &amp;quot;spr#_static&amp;quot; to 1    ''Makes the sprite display relative to the viewport, rather than the board, like a static overlay.''&lt;br /&gt;
Using the vlayer is especially important for layer sprites.  At this point it becomes completely impractical to set aside as much empty space on every board in the game as is necessary to accomodate all of the graphical data used by them.  Painting the sprite on top of the overlay can also be useful if you are using the overlay to draw static things on top of the normal game action, like trees or houses, but you want something special to appear above everything, like a status bar or a message box.  And very often, it is worth combining this with the static command, so that you don't have to figure out where to redraw the sprite every time the screen moves.&lt;br /&gt;
&lt;br /&gt;
There are also a few important things to consider when working with large sprites, and when combining them with the gameplay engine we're building.  The first is that character 32, the space, is not drawn in a sprite, just like it isn't drawn on the overlay.  This is pretty essential if you're going to have a sprite that covers the whole screen, space-wise, and still want to see what's beneath it.  Another is that sprites have an absolute maximum width and height of 255.  If you try to make a sprite larger than that, the practical dimensions will just wrap back around to 0, modulo 256.  Because we're using layer sprites as a window into the vlayer, we never actually NEED a sprite to be larger than 80x25 characters, and there are plenty of ways to work with them to stay inside this constraint.  But since it's often easier, for a layer that covers the entire board, to just place the layer on the board, we'll assume for the purposes of this tutorial that you won't be using a board or sprites larger than 255 in either dimension.&lt;br /&gt;
&lt;br /&gt;
Finally, one important catch that comes up when we try to use a layer sprite in conjunction with a system that uses spr_yorder to draw game objects correctly, is how to get the layer to appear on top of all the other sprites in the game, or to change its order relative to other layers.  After all, a sprite drawn over the whole screen is going to have a y-coordinate lower than any sprite object in the game, right?  Fortunately for us, spr_yorder doesn't calculate its draw order based on spr#_y values, but on spr#_cy values.  Since we almost never want sprites that are suppose to appear above all game objects to collide with those game objects, this means that we can co-opt this counter as a view order marker.  Setting it to extreme negative values will make it appear below every other sprite in the game.  Setting it to extreme positive ones will make it appear above everything.  It may require some tweaking to get working exactly right when combined with other layers, since the values are still taken as offsets from the sprite's position on the board, but it's a serviceable workaround.&lt;br /&gt;
&lt;br /&gt;
{{a|E3.1}}&lt;br /&gt;
====Exercise 3.1: Creating a status bar====&lt;br /&gt;
For our first foray into layer sprites, let's do something fairly simple to create, but that epitomizes the most basic purpose of layers: a status bar.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;Before anything else, we need to draw the base template for the status bar.  This can be done mostly however you like, but it should at least have locations to draw health, ammo, and collected keys, and the locations and sizes of the places for drawing to these areas should be recorded as constants in the global robot.  Here are the constants and sizes I'll be using:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;lyr_s_x&amp;quot; to 0   ''meaning layer-statusbar-refx''&lt;br /&gt;
: set &amp;quot;lyr_s_y&amp;quot; to 3   ''layer-statusbar-refy''&lt;br /&gt;
: set &amp;quot;lyr_s_w&amp;quot; to 50  ''layer-statusbar-width''&lt;br /&gt;
: set &amp;quot;lyr_s_h&amp;quot; to 2   ''layer-statusbar-height''&lt;br /&gt;
: set &amp;quot;lyr_sh_x&amp;quot; to 10 ''layer-statusbar-health-refx''&lt;br /&gt;
: set &amp;quot;lyr_sh_y&amp;quot; to 3  ''layer-statusbar-health-refy''&lt;br /&gt;
: set &amp;quot;lyr_sh_w&amp;quot; to 25 ''layer-statusbar-health-width''&lt;br /&gt;
: set &amp;quot;lyr_sh_h&amp;quot; to 1  ''layer-statusbar-health-height''&lt;br /&gt;
: set &amp;quot;lyr_sa_x&amp;quot; to 43 ''layer-statusbar-ammo-refx''&lt;br /&gt;
: set &amp;quot;lyr_sa_y&amp;quot; to 3  ''layer-statusbar-ammo-refy''&lt;br /&gt;
: set &amp;quot;lyr_sa_w&amp;quot; to 5  ''layer-statusbar-ammo-width''&lt;br /&gt;
: set &amp;quot;lyr_sa_h&amp;quot; to 1  ''layer-statusbar-ammo-height''&lt;br /&gt;
: set &amp;quot;lyr_sk_x&amp;quot; to 8  ''layer-statusbar-keys-refx''&lt;br /&gt;
: set &amp;quot;lyr_sk_y&amp;quot; to 4  ''layer-statusbar-keys-refy''&lt;br /&gt;
: set &amp;quot;lyr_sk_w&amp;quot; to 40 ''layer-statusbar-keys-width''&lt;br /&gt;
: set &amp;quot;lyr_sk_h&amp;quot; to 1  ''layer-statusbar-keys-height''&amp;lt;/tt&amp;gt;&lt;br /&gt;
The final result should look something like this, 50 characters wide, 2 high, with room for labels and a 2 character margin on each side:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;display:table&amp;quot;&amp;gt;| Health: =========================  Ammo: 00000 |&lt;br /&gt;
| Keys: ________________________________________ |&amp;lt;/pre&amp;gt;&lt;br /&gt;
Save it as a new MZM, statusbar.mzm, and then have the global robot load it along with sprites.mzm:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a robot to handle drawing our layer.  This starts out in the same basic way as all sprite robots have so far:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;('vw'-'lyr_s_w'/2)&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: . &amp;quot;These are the initial x/y coordinates for the sprite, though they'll change later.&amp;quot;&lt;br /&gt;
: . &amp;quot;The expression for the x coordinate is a midpoint formula that places the sprite in the center of the viewport&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: set &amp;quot;statusbar&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_static&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_s_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_s_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_s_h&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 500&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 0&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
All of the principles used here, including the new ones like spr&amp;amp;local&amp;amp;_static and using spr&amp;amp;local&amp;amp;_cy to fix the display order, should already be familiar to you if you've been following the tutorial.  We set the other collision counters to 0 in order to make sure they're off; remember, this sprite number could have belonged to something else on another board.  By the same token, don't forget to add a line to turn off the statusbar sprite on board transitions, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That got the sprite drawing, but now we need it to display something meaningful, instead of just looking pretty.  First, let's set up a main program loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: . &amp;quot;The easiest way to redraw the status bar is to reload the base image from the MZM.&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: goto &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then we need to flesh out each of those subroutines.  Health is the easiest to do: we need a bar of filled health as long as the space in the status bar, so draw a line of red 25 characters long next to the other sprites, and re-export sprites.mzm.  Make sure to add constants for this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_sh_x&amp;quot; to 8  ''meaning sprite-statusbar-health-refx, for the sprite image to copy onto the layer''&lt;br /&gt;
: set &amp;quot;spr_sh_y&amp;quot; to 0  ''sprite-statusbar-health-refy''&amp;lt;/tt&amp;gt;&lt;br /&gt;
To draw the health, we'll simply copy a portion of this bar based on the value of 'health' and 'maxhealth' (you'll have to set maxhealth to something yourself).  This leads to:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: copy block &amp;quot;#&amp;amp;spr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_sh_y&amp;amp;&amp;quot; for &amp;quot;('health'*'lyr_sh_w'/'maxhealth')&amp;quot; &amp;quot;lyr_sh_h&amp;quot; to &amp;quot;#&amp;amp;lyr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_sh_y&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now for the ammo.  The easiest way to read this out of a counter and onto the vlayer is to convert the counter into a string.  MZX will do this for you without having to write a conversion routine.  We would like to write that string directly to the vlayer, but unfortunately MZX doesn't support that operation in a convenient way right now (though it may in the future).  We could write it to some off-screen space on the overlay and then copy it, but depending on how you set up the board scrolling in the last section, you may not have any off-screen space.  So we'll just have to loop through the string.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: set &amp;quot;$ammo&amp;quot; to &amp;quot;&amp;amp;ammo&amp;amp;&amp;quot;&lt;br /&gt;
: . &amp;quot;Ampersands are required, so that we don't just draw 'ammo' on the screen.&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;vch('lyr_sa_x'+'loopcount'),('lyr_sa_y')&amp;quot; to &amp;quot;$ammo.&amp;amp;loopcount&amp;amp;&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('$ammo.length'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we don't do any checking for the length of the ammo string.  We could do this, but it would involve adding some complex expressions that are outside of this tutorial's scope, and is left as an exercise to the reader.  Instead, simply take care not to let the player's ammo exceed 99999.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, the keys.  Remember that the information for these is not stored in the built-in MZX key handling, but in counters we defined ourselves, 'key_#' for each color.  To draw the keys, we'll loop through these counters and test whether they're set or not.  This is a fairly complicated routine, and involves keeping track of the key color and the current draw location, and aborting the loop before we draw too many keys to fit on the status bar.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;keynext&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: if &amp;quot;local5&amp;quot; &amp;gt;= &amp;quot;lyr_sk_w&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
: set &amp;quot;vch('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to 12&lt;br /&gt;
: set &amp;quot;vco('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to &amp;quot;local4&amp;quot;&lt;br /&gt;
: inc &amp;quot;local5&amp;quot; by 1&lt;br /&gt;
: loop for &amp;quot;('key_&amp;amp;local4&amp;amp;'-1)&amp;quot;&lt;br /&gt;
: : &amp;quot;keynext&amp;quot;&lt;br /&gt;
: inc &amp;quot;local4&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local4&amp;quot; &amp;lt; 256 then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that 12 is the character of the key graphic; this could easily be changed.  Also understand that this is a fairly inefficient routine, and will take around 1000 commands to execute.  We could create some data structures to greatly improve on this time, but that would involve maintenance and a lot of extra effort.  Instead, this is the time to go ahead and set the 'commands' counter to something reasonably high, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Two last things before we're done: the status bar necessarily covers up parts of the playing area that we might like to see.  There are two things we can do to help with this.  One is to move the status bar to the opposite side of the screen if the player gets too close to it.  The other is to allow the player to toggle the display on and off.  Neither of these is that hard to do, so we'll take them both in order.  To move the sprite, create a #draw subroutine in the main loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;('spr&amp;amp;playersprite&amp;amp;_y'-'scrolledy')&amp;quot; &amp;gt;= &amp;quot;('vh'-'spr_p_h'/2)&amp;quot; then &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('vh'-'lyr_s_h')&amp;quot;&lt;br /&gt;
: : &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Basically, as long as the player remains in the lower half of the screen, the status bar will be on top.  If the player moves into the top of the screen, the status bar will move to the bottom.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;To turn the status bar on and off, we'll simply use a classic zap/restore toggle with the :keyenter label.  This is very basic stuff that should be familiar to most people already. We'll have the sprite start in the off state each time the board initializes.  So instead of placing the sprite and going to the draw loop, do this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 255&lt;br /&gt;
: goto &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: zap &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Since the status bar is now replacing the default enter menu, make sure to have the global robot turn that off by setting 'enter_menu' to 0.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That does it for our status bar.  You'll want to add in some test code and make use of the counter debugger to see that the various elements are reporting their numbers correctly, but you can take this robot and drop it on every screen on which you want to have a status bar.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.1|Example 3.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.2}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.2: Bullets as a layer (framework)====&lt;br /&gt;
Our next exercise is the most complicated individual piece of the engine yet: adding bullets and shooting to the game.  There's no easy way to break it into pieces, but it'll really take at least two exercises to fully explain.  So I'll do the best I can and break it into a framework phase, where we'll construct the basic skeleton for the code and explain what each part is going to do, and an implementation phase, where we'll implement each of the main subroutines and explain how they work.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, we need our basic sprite handler robot preamble.  You've written this thing several times already, but let's go over it again.  We need a one-time execution section that sets a counter based on the robot id, renames the robot based on it, and moves the robot to the robot bank (this part is not strictly necessary but we'll do it anyway):&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
We need a separator to prevent this code from happening more than once, and have the code after it happen every time the board loads:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
And we need some basic sprite initialization and placement:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playerbullets&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_pb_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_pb_h&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; &amp;quot;bminx&amp;quot; &amp;quot;bminy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We'll get to collision in a little bit, since it's going to be done a little bit differently than normal.  For now, we want to set up for a layer sprite that's going to fit snugly on top of the board's playing area.  And of course we make sure to create a reference counter for the sprite (playerbullets).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course we're going to need to set up the global robot to manage some of these counters, which are going to correspond to areas on the vlayer.  One thing we're going to need is an actual image for the player's bullets, separate from the layer the bullets get drawn on.  So add that to sprites.mzm and note its location, and then add some counters to global:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_pb_x&amp;quot; to 9&lt;br /&gt;
: set &amp;quot;spr_pb_y&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_pb_w&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr_pb_h&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;lyr_pb_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;lyr_pb_y&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;lyr_pb_w&amp;quot; to &amp;quot;('bmaxx'-'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;('bmaxy'-'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Another important thing we're going to need is a blank MZM the size of the layer, to use as a way to clear all of the bullets and redraw them.  You could go to the trouble of exporting this by hand, or you could do it the smart way and just have the global robot make it for you.  The vlayer consists of empty space by default, so we can just export an appropriately sized piece of it to make a blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;lyr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_pb_y&amp;amp;&amp;quot; for &amp;quot;lyr_pb_w&amp;quot; &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;@blank.mzm&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, we want to make sure the bullet sprite gets turned off between boards, so that its number can be properly reassigned if it changes.  Remember where the global robot section that performs this task is?&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playerbullets&amp;amp;_off&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now that we've got that out of the way, we need to figure out how bullets are going to work.  The idea is to have them all drawn on a layer that fits over the board, and to keep track of important stats for each bullet in an array.  For now these are basically position and velocity, where velocity will be effectively limited to moving in one of the four cardinal directions.  Our engine will work in a loop that will:&lt;br /&gt;
# Add any new bullets to the layer&lt;br /&gt;
# Move all of the bullets on the layer&lt;br /&gt;
# Check for bullet collisions with other sprites or walls&lt;br /&gt;
# Remove all bullets that have collided or moved off the screen&lt;br /&gt;
# Redraw the layer&lt;br /&gt;
As we've discussed before, the easiest way to tackle something like this is to break it down into component tasks.  So we'll make a loop that executes a bunch of subroutines in order:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#add&amp;quot;&lt;br /&gt;
: goto &amp;quot;#move&amp;quot;&lt;br /&gt;
: goto &amp;quot;#check&amp;quot;&lt;br /&gt;
: goto &amp;quot;#remove&amp;quot;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This loop will change somewhat when we actually implement these routines, but this is the basic idea.  Go ahead and add the label stubs for the subroutines, too.  For example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: . &amp;quot;TODO&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step: we're going to need to maintain a list of bullets on the layer, and we're going to need an interface to add to and remove from that list.  The easiest way to do this is to have a list of bullets to add and another list of bullets to remove, which are processed by each subroutine.  The player robot will add bullets to the add list when the player fires, and the bullet robot itself will add them to the remove list when they collide with something or move off the board.  The implementation is a little complicated and we'll discuss it in the next exercise, but for now, we should make sure the length of each list is set to 0 each time the board loads, so that we can start fresh.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This is all the set up we really need to do.  Running the code at this point won't do a single thing, but the framework is now in place for implementation.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.2|Example 3.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.3}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.3: Bullets as a layer (implementation)====&lt;br /&gt;
Now we come to the meat of the engine.  We can't really build this incrementally, but we can take each part individually since we've divided it up into distinct subroutines.  So that's just what we'll do.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt; First, the #add routine.  We're going to add a flag to a list (pbullets_add) each time the player fires a bullet, and then this routine will process that list every cycle, adding a set of bullet parameters based on the flag.  The flag we're going to use is the ID of the sprite that fired it (i.e. the player), and you might ask why we would even bother with a list at all and not just have a &amp;quot;bulletfired&amp;quot; flag that the player engine sets when it wants to shoot, or even a subroutine of its own to send.  The reason is because I prefer to generalize engines whenever possible; this engine in particular will be easy to use to handle multiple bullets from multiple enemies simultaneously with no problem at all.  Regardless, at this point we're not really concerned with how bullets get added to the add list, just with processing that list.  The list is of the form &amp;lt;tt&amp;gt;pbullets_add#&amp;lt;/tt&amp;gt; and has a length of &amp;lt;tt&amp;gt;pbullets_add&amp;lt;/tt&amp;gt;, and all of these values will be correct at the beginning of the routine.  So our subroutine is primarily a loop that processes this list:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_add'-1)&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we clear the add list once we're done, to prevent from processing the same stuff again next cycle.  New bullets will get added on top of the old.&amp;lt;br&amp;gt;&lt;br /&gt;
Now, each value in the list is a sprite ID (all the same ID in fact, but this will be a general case for later).  This means we have access to a host of information about a particular sprite, thanks to the object-oriented approach we've been following before with counter names, and the default sprite counters in general.  Notably, we have access to a set of coordinates and dimensions for the sprite (to help us decide where to put the bullet), and in the case of the player access to the last direction it moved (to help us decide which way the bullet should be firing).  We'll capture this reference out of the list into a temporary local counter, for easier access:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_add&amp;amp;loopcount&amp;amp;&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We also have a list of bullets containing various stats, which is referenced using the form &amp;lt;tt&amp;gt;pbullets#_stat&amp;lt;/tt&amp;gt;, and is &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; in length.  With zero indexing, this means we can add on to the end of the list by using &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; as an index.  Or more to the point:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_width'/2 + 'spr&amp;amp;local2&amp;amp;_x' - 'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_height'/2 + 'spr&amp;amp;local2&amp;amp;_y' - 'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expressions are a bit scary, but the basic idea is to put the bullet at the x/y coordinate of the player sprite, plus an offset to put it into the center of the sprite (half of the dimensions), and minus the offset for the location of the playing area relative to the actual board.  The reason for the last part is so that the bullets' x/y coordinates treat the 0,0 as the top-left of the playing area, since that's how the bullet sprite is placed.  The velocities are trickier: we want to translate a direction code (0 = north, 1 = south, 2 = west, 3 = east) into an x and y velocity component (we'll stick with -1, 0, and 1 for now, no need to get too fancy).  Remember that the counter for this is &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt;.  So the easiest way to do this is with a case structure, as follows:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#add('spr&amp;amp;local2&amp;amp;_lastmove')&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#add0&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullest&amp;amp;pbullets&amp;amp;_vy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Make sure to add four corresponding subroutines to the end of the program, out of the way of other code execution.  For your edification, I've left my two-line expression solution to this in the example code.&amp;lt;br&amp;gt;&lt;br /&gt;
Finally, we need to make sure the length of the bullet list is updated.&amp;lt;tt&amp;gt;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;quot; by 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
And we're done with this subroutine.  The game can now process a list of bullets and add them to our list.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Next, the move routine.  Moving is fairly simple in concept, except for one catch that we'll get to momentarily.  The gist is to process each bullet in the bullet list and add its velocity to its current location.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#move&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vx&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vy&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The catch is that bullets can move all the way off the playing field, in which case they need to be removed, or they'll end up being drawn on parts of the vlayer we'd like not to draw on.  We could handle this check in the #check routine along with collision, but it's still going to need handling, so we'll just do it here, next to the stuff it relates to.&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;(('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;lt;'lyr_pb_w')a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;lt;'lyr_pb_h'))&amp;quot; = 1 then &amp;quot;movenext&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;movenext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This block goes right before the end of the loop, after the bullet location counters have been updated.  The expression looks long and scary but this is actually an expression usage worth learning, since all it is is a bunch of conditional statements joined together with the AND operator.  Basically, if the bullet is still inside the defined playing area, the commands to remove it are skipped.  Removal is going to work much the same way adding does, with a list of bullets to remove.  Except in this case, the list contains indexes into the main bullet list.  In any case, that's all for the movement routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If it seems that all we've been doing so far is a bunch of abstract bookkeeping on numbers, the #check routine actually gets us back into the realm of sprites.  Here, we'll use the collision functionality provided by sprites to check each bullet and get a collision list for message sending with a minimum of fuss.  That means that the collision values need to be set for the layer first, for each bullet:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#check&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_pb_h&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This makes sure that we're dealing with a collision rectangle for each bullet on the layer, and can process them in turn.  Then, the actual collision is triggered:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_clist&amp;quot; to 1&lt;br /&gt;
: if &amp;quot;spr_collisions&amp;quot; &amp;lt;= 0 then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;checknext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here, I've decided to do things inline and short-circuit to the end of the loop, since I plan to use that label for something else in a moment.  Collision could also be done with a subroutine, of course, this is just how it happened to fall out when I originally wrote the engine.  Notice also that we're using the same removal method as before.&amp;lt;br&amp;gt;&lt;br /&gt;
We would be done with this here, except that we also need to do something about the sprite or sprites the bullet is colliding with.  This is just our basic collision handler loop, stuck in the middle:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;collide&amp;quot;&lt;br /&gt;
: if &amp;quot;spr_clist&amp;amp;local2&amp;amp;&amp;quot; = &amp;quot;playersprite&amp;quot; then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: send &amp;quot;spr('spr_clist&amp;amp;local2&amp;amp;')&amp;quot; to &amp;quot;playershot&amp;quot;&lt;br /&gt;
: inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local2&amp;quot; &amp;lt; &amp;quot;spr_collisions&amp;quot; then &amp;quot;collide&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Unfortunately we can't use a default loop structure since we're already in the middle of one, so we continue using local2 as a temp counter.  Notice in particular the breakout condition for when the bullet is colliding with the player.  This is done specifically to deal with the fact that each player bullet starts its life ''inside'' of the player, according to our #add routine.  We could do this differently, but this is an easy hack to get around that and prevent removing the bullet prematurely.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The #remove routine functions on a list of references to bullets to remove, as we've already seen.  This is to avoid the perils of deleting items from the bullet list in place, while we're iterating through it.  I have actually thought of an interesting way to do just that without negative side effects, but I'm not sure enough of it yet to use it in this tutorial, so I'm sticking with something I know will work.  In any case, removing a bullet from the bullet list will work much the same way as removing a key from the list of key sprites: we grab the bullet from the end of the list and put it into the location of the bullet to be removed.  In order to do this without risking serious malfunction though, we need to process the bullet list backwards.  That is, we need to remove bullets starting from the same end of the list that we're replacing them from, or we'll risk having a reference to a bullet that is no longer the same, or does not even exist, by the time we've gotten to the end.  Since replacing from the front is prohibitively complicated and costly to do, the easiest solution is to process the remove list backwards, since it's already sorted in ascending order.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#remove&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: dec &amp;quot;pbullets&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_remove('pbullets_remove'-'loopcount'-1)&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_remove'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember how we did the keys, we decrease the size of the list at the beginning so that we can have an easy reference to the end of the list, instead of the end of the list plus one.  The numbers don't actually go anywhere, so it doesn't matter if we decrease the length at the beginning or the end of the removal.  And as you can see, local2 is set to count backwards through the values in the remove list, which are indexes into the main bullet list.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_x&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_y&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vx&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vy&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This is the actual removal step, and as before simply involves some counters into others.  The only difference here is that there are more of them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Very near the end now, all we have left is the #draw routine.  Drawing is going to take care of all of the things necessary to repaint the layer, based on the numbers we've spent so much time setting up.  The first task is to wipe the layer clean with the blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, a loop for each of the bullets, to move the bullet image onto the layer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: loop start&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;spr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_pby&amp;quot; for &amp;quot;spr_pb_w&amp;quot; &amp;quot;spr_pb_h&amp;quot; to &amp;quot;#('lyr_pb_x'+'pbullets&amp;amp;loopcount&amp;amp;_x')&amp;quot; &amp;quot;#('lyr_pb_y'+'pbullets&amp;amp;loopcount&amp;amp;_y')&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, the end of the drawing, which for display purposes involves setting the &amp;lt;tt&amp;gt;spr#_cy&amp;lt;/tt&amp;gt; value so that bullets appear under everything:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You may wonder what this means for collision, if drawing happens afterwards, and whether collision will happen a cycle late.  But the default behavior for sprites is to collide with anything overlapping the collision rectangle, regardless of whether there is actually anything in it.  This can be changed with the &amp;lt;tt&amp;gt;spr#_ccheck&amp;lt;/tt&amp;gt; counter so that either character 32 (setting 1) or any empty character (setting 2) does NOT cause a collision, but for our purposes here that's not what we want.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step remains, and that's to revisit the main loop that actually calls all of the subroutines.  The astute reader will have noticed that the remove routine relies on having a sorted list, which the iterative approach in the move and check routines provides; but that there are two iterations to take into account, one for moving and one for collision checking, and so the list will not necessarily be completely sorted.  The simple way around this is to call #remove twice, once after #move and once after #check.&amp;lt;br&amp;gt;&lt;br /&gt;
The other snag is that the nature of the MZX loop structure always performs the loop once, even if there's nothing inside that we want to loop through.  This means that in the cases of empty lists, we don't want to call the subroutines at all.  Fortunately this is fairly easy to guard against:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_add&amp;quot; &amp;gt; 0 then &amp;quot;#add&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#move&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#check&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
There is, however, one thing that we do want to happen no matter what, and that's for the layer to be cleared and the collision set off the board when the last bullet disappears.  With that in mind, grab both of those commands out of the draw routine, and put them in the main loop instead:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it.  The engine still won't be doing anything, but it's no longer because there isn't any code behind it.  Instead, it's because there's nothing using the engine yet.  We'll cover that next in the section wrap up.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.3|Example 3.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.4}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.4: Interacting with the rest of the game====&lt;br /&gt;
After all of that setup, actually integrating the engine into the game is so simple it barely merits an exercise of its own.  In fact I'm considering moving all of this back into the framework exercise, since it would fit there and only take up a couple steps.  But for now, let's just finish this out.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;The first thing we need is a way to let the player shoot something.  Going with the standard MZX gameplay mechanic, this means the player robot needs to handle spacebar when an arrow key is pressed..  Simply add this line to each of the movement subroutines (#up, #down, etc.):&amp;lt;tt&amp;gt;&lt;br /&gt;
: if spacepressed then &amp;quot;shoot&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that the add routine is going to use the &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt; counter to determine which way the bullet should fire, so make sure this check happens after that gets set.  Then, set up the :shoot branch:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;amp;pbullets_add&amp;amp;&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_add&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This short-circuits the rest of the movement routine; the player can't move when spacebar is pressed now, only shoot.  Note that we don't have to send the bullet robot any sort of label, we just add an item to the list that we know will get processed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That gets the bullet engine rolling on the input side, and you can actually use it now and see it in action.  Output is even simpler: much like the player engine sends other sprites to :touch labels when it collides with them, the bullet engine sends them a :playershot label.  To see this in action, open up your key or door robot and add something like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playershot&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('local4'%16)&amp;quot;&lt;br /&gt;
: * &amp;quot;~&amp;amp;+local5&amp;amp;Ouch, you shot me!&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The extra step is an easy way to use the door's or key's color for the message, interpolating &amp;amp;+counter&amp;amp; returns a hexadecimal value.  Remember that local4 is the color of the key or door.  Unfortunately this can't be used with expressions, hence the need for an extra temp counter to extract the foreground color from the background.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Finally, to round it all off, let's actually tie the shooting to the value of the ammo counter.  That way, we can watch the ammo count down on the status bar when we shoot, and prevent from shooting when we're out of ammo.  Don't underestimate the usefulness of MZX's more specialized commands; here, the &amp;lt;tt&amp;gt;take&amp;lt;/tt&amp;gt; command provides exactly the functionality we need:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: take 1 AMMOS else &amp;quot;#return&amp;quot;&lt;br /&gt;
: ...&amp;lt;/tt&amp;gt;&lt;br /&gt;
Don't forget to have the global robot give the player some ammo up front, or this will stop you from shooting anything.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's all for now.  We're starting to have the beginnings of a really solid engine, all it really needs now are some enemies.  So we'll focus on that (and some other things) in the next section.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.4|Example 3.4 Code]]&lt;br /&gt;
&lt;br /&gt;
==External Links==&lt;br /&gt;
[http://www.digitalmzx.net/faq/sprite.html Saike's Sprite Tutorial] - Slightly out of date with regards to other MZX features.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;br /&gt;
{{stub}}&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7676</id>
		<title>Board</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Board&amp;diff=7676"/>
		<updated>2011-01-28T01:17:53Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;A '''Board''' is basically a playing field for which the game can take place in.  ==Limitations== *Boards can range in size from 1x1 to a massive 32767x32767 **Extremely large bo...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''Board''' is basically a playing field for which the game can take place in.&lt;br /&gt;
&lt;br /&gt;
==Limitations==&lt;br /&gt;
*Boards can range in size from 1x1 to a massive 32767x32767&lt;br /&gt;
**Extremely large boards will consume a massive block of memory. A board with the maximum dimensions would consume over 3 GB of memory.&lt;br /&gt;
**The BoardScan is a somewhat expensive routine that scans every square of the board every cycle for built-ins. The larger the board, the bigger the performance impact it can have on your game on slower computers. A good rule of thumb is to try to make boards not much larger than 1000x1000 in area.&lt;br /&gt;
*All boards must have one and only one instance of the player object.&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite_Code_Examples&amp;diff=7675</id>
		<title>Sprite Code Examples</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite_Code_Examples&amp;diff=7675"/>
		<updated>2011-01-27T04:11:16Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
This article contains all of the code described in the [[Sprite_(Tutorial)#Sprite Tutorial|Sprite Tutorial]].&lt;br /&gt;
==Example 1.1==&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;spr0_refx&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr0_refy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr0_width&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr0_height&amp;quot; to 3&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 put c?? Sprite p00 at &amp;quot;x&amp;quot; &amp;quot;y&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;down&amp;quot;&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;up&amp;quot;&lt;br /&gt;
 dec &amp;quot;y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;down&amp;quot;&lt;br /&gt;
 inc &amp;quot;y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;left&amp;quot;&lt;br /&gt;
 dec &amp;quot;x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;right&amp;quot;&lt;br /&gt;
 inc &amp;quot;x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
[[Sprite#E1.1|Back]]&lt;br /&gt;
==Example 1.2==&lt;br /&gt;
 lockplayer&lt;br /&gt;
 '''set &amp;quot;local&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to 5'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to 5'''&lt;br /&gt;
 set &amp;quot;spr'''&amp;amp;local&amp;amp;'''_refx&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr'''&amp;amp;local&amp;amp;'''_refy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr'''&amp;amp;local&amp;amp;'''_width&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr'''&amp;amp;local&amp;amp;'''_height&amp;quot; to 3&lt;br /&gt;
 '''goto &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;'''#'''up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;'''#'''left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;'''#'''right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;'''#'''down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;'''#'''up&amp;quot;&lt;br /&gt;
 '''if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 dec '''&amp;quot;local3&amp;quot;''' by 1&lt;br /&gt;
 '''goto &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 goto '''&amp;quot;#return&amp;quot;'''&lt;br /&gt;
 : &amp;quot;'''#'''down&amp;quot;&lt;br /&gt;
 '''if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 inc '''&amp;quot;local3&amp;quot;''' by 1&lt;br /&gt;
 '''goto &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 goto '''&amp;quot;#return&amp;quot;'''&lt;br /&gt;
 : &amp;quot;'''#'''left&amp;quot;&lt;br /&gt;
 '''if &amp;quot;local2&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 dec '''&amp;quot;local2&amp;quot;''' by 1&lt;br /&gt;
 '''goto &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 goto '''&amp;quot;#return&amp;quot;'''&lt;br /&gt;
 : &amp;quot;'''#'''right&amp;quot;&lt;br /&gt;
 '''if &amp;quot;local2&amp;quot; &amp;gt;= &amp;quot;(80-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 inc '''&amp;quot;local2&amp;quot;''' by 1&lt;br /&gt;
 '''goto &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 goto '''&amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 '''put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
[[Sprite#E1.2|Back]]&lt;br /&gt;
==Example 1.3==&lt;br /&gt;
 '''. &amp;quot;Global robot&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr_yorder&amp;quot; to 1'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to 5&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to 5&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to 3&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 2'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 3'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 1'''&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 dec &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;gt;= &amp;quot;(80-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
[[Sprite#E1.3|Back]]&lt;br /&gt;
==Example 2.1==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to 83&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to 86&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 . &amp;quot;Your values may differ, so please change them to suit.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to '''&amp;quot;robot_id&amp;quot;'''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to '''&amp;quot;thisx&amp;quot;'''&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to '''&amp;quot;thisy&amp;quot;'''&lt;br /&gt;
 '''gotoxy &amp;quot;local&amp;quot; 0'''&lt;br /&gt;
 '''. &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to '''&amp;quot;spr_p_x&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to '''&amp;quot;spr_p_y&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to '''&amp;quot;spr_p_w&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to '''&amp;quot;spr_p_h&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to '''&amp;quot;spr_p_cx&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to '''&amp;quot;spr_p_cy&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to '''&amp;quot;spr_p_cw&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to '''&amp;quot;spr_p_ch&amp;quot;'''&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then '''&amp;quot;collision&amp;quot;'''&lt;br /&gt;
 dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then '''&amp;quot;collision&amp;quot;'''&lt;br /&gt;
 inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then '''&amp;quot;collision&amp;quot;'''&lt;br /&gt;
 dec &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;gt;= &amp;quot;(80-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then '''&amp;quot;collision&amp;quot;'''&lt;br /&gt;
 inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ''': &amp;quot;collision&amp;quot;'''&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;'''&lt;br /&gt;
 '''send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;'''&lt;br /&gt;
 '''loop for &amp;quot;('spr_collisions'-1)&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Key robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_k_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_k_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_k_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_k_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_k_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_k_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_k_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_k_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Door robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_d_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_d_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_d_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_d_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_d_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_d_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_d_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_d_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
 dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 : &amp;quot;end&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
[[Sprite#E2.1|Back]]&lt;br /&gt;
&lt;br /&gt;
==Example 2.2==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to 83&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to 86&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 '''set &amp;quot;num_keys&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;num_doors&amp;quot; to 0'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 '''set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;'''&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_p_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_p_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_p_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_p_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_p_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_p_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_p_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_p_ch&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 if &amp;quot;local2&amp;quot; &amp;gt;= &amp;quot;(80-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Key robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;num_keys&amp;quot; by 1'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_k_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_k_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_k_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_k_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_k_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_k_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_k_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_k_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 '''dec &amp;quot;num_keys&amp;quot; by 1'''&lt;br /&gt;
 '''set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Door robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_doors&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;num_doors&amp;quot; by 1'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_d_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_d_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_d_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_d_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_d_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_d_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_d_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_d_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
 dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 '''dec &amp;quot;num_doors&amp;quot; by 1'''&lt;br /&gt;
 '''set &amp;quot;spr('doorsprite&amp;amp;num_doors&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;doorsprite&amp;amp;num_doors&amp;amp;&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 : &amp;quot;end&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
[[Sprite#E2.2|Back]]&lt;br /&gt;
==Example 2.3==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 '''set &amp;quot;bminx&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;bminy&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;bmaxx&amp;quot; to 80'''&lt;br /&gt;
 '''set &amp;quot;bmaxy&amp;quot; to 25'''&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to 83&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to 86&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;'''&lt;br /&gt;
 '''restore &amp;quot;justentered&amp;quot; 1'''&lt;br /&gt;
 '''| &amp;quot;justentered&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1'''&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1'''&lt;br /&gt;
 '''loop for &amp;quot;('num_keys'-1)&amp;quot;'''&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1'''&lt;br /&gt;
 '''loop for &amp;quot;('num_doors'-1)&amp;quot;'''&lt;br /&gt;
 set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;num_doors&amp;quot; to 0&lt;br /&gt;
 '''lockscroll'''&lt;br /&gt;
 '''set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;'''&lt;br /&gt;
 '''put player at 0 0'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ''': &amp;quot;edge0&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to &amp;quot;('bmaxy'-'spr_p_h')&amp;quot;'''&lt;br /&gt;
 '''put player at 0 0'''&lt;br /&gt;
 '''move player NORTH'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ''': &amp;quot;edge1&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to &amp;quot;bminy&amp;quot;'''&lt;br /&gt;
 '''put player at &amp;quot;('board_w'-1)&amp;quot; &amp;quot;('board_h'-1)&amp;quot;'''&lt;br /&gt;
 '''move player SOUTH'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ''': &amp;quot;edge2&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;('bmaxx'-'spr_p_w')&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to &amp;quot;player_y&amp;quot;'''&lt;br /&gt;
 '''put player at 0 0'''&lt;br /&gt;
 '''move player WEST'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ''': &amp;quot;edge3&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;bminx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local3&amp;quot; to &amp;quot;player_y&amp;quot;'''&lt;br /&gt;
 '''put player at &amp;quot;('board_w'-1)&amp;quot; &amp;quot;('board_h'-1)&amp;quot;'''&lt;br /&gt;
 '''move player EAST'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 &amp;lt;s&amp;gt;set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&amp;lt;/s&amp;gt;&lt;br /&gt;
 &amp;lt;s&amp;gt;set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&amp;lt;/s&amp;gt;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 '''restore &amp;quot;justentered&amp;quot; 1'''&lt;br /&gt;
 '''| &amp;quot;justentered&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_p_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_p_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_p_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_p_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_p_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_p_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_p_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_p_ch&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0'''&lt;br /&gt;
 if '''&amp;quot;player_y&amp;quot;''' &amp;lt;= '''&amp;quot;bminy&amp;quot;''' then '''&amp;quot;edgecollide&amp;quot;'''&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec '''&amp;quot;player_y&amp;quot;''' by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 1'''&lt;br /&gt;
 if '''&amp;quot;player_y&amp;quot;''' &amp;gt;= &amp;quot;(''''bmaxy''''-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then '''&amp;quot;edgecollide&amp;quot;'''&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc '''&amp;quot;player_y&amp;quot;''' by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 2'''&lt;br /&gt;
 if '''&amp;quot;player_x&amp;quot;''' &amp;lt;= '''&amp;quot;bminx&amp;quot;''' then '''&amp;quot;edgecollide&amp;quot;'''&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec '''&amp;quot;player_x&amp;quot;''' by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 3'''&lt;br /&gt;
 if '''&amp;quot;player_x&amp;quot;''' &amp;gt;= &amp;quot;(''''bmaxx''''-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then '''&amp;quot;edgecollide&amp;quot;'''&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc '''&amp;quot;player_x&amp;quot;''' by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at '''&amp;quot;player_x&amp;quot;''' '''&amp;quot;player_y&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ''': &amp;quot;edgecollide&amp;quot;'''&lt;br /&gt;
 '''send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Key robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 '''restore &amp;quot;justentered&amp;quot; 1'''&lt;br /&gt;
 '''| &amp;quot;justentered&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_k_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_k_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_k_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_k_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_k_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_k_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_k_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_k_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Door robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 '''restore &amp;quot;justentered&amp;quot; 1'''&lt;br /&gt;
 '''| &amp;quot;justentered&amp;quot;'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_doors&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_d_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_d_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_d_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_d_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_d_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_d_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_d_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_d_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
 dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;num_doors&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;doorsprite&amp;amp;num_doors&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 : &amp;quot;end&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
[[Sprite#E2.3|Back]]&lt;br /&gt;
&lt;br /&gt;
==Example 2.4==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 set &amp;quot;bminx&amp;quot; to '''1'''&lt;br /&gt;
 set &amp;quot;bminy&amp;quot; to '''1'''&lt;br /&gt;
 set &amp;quot;bmaxx&amp;quot; to '''81'''&lt;br /&gt;
 set &amp;quot;bmaxy&amp;quot; to '''26'''&lt;br /&gt;
 '''set &amp;quot;vw&amp;quot; to 80'''&lt;br /&gt;
 '''set &amp;quot;vh&amp;quot; to 25'''&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to '''0'''&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to '''3'''&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to '''6'''&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 '''put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0'''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&lt;br /&gt;
 '''set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;Uberleet expression hack method:&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;local4\&amp;quot; to \&amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;local5\&amp;quot; to \&amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')\&amp;quot;&amp;quot;'''&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_doors'-1)&amp;quot;&lt;br /&gt;
 set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;num_doors&amp;quot; to 0&lt;br /&gt;
 lockscroll&lt;br /&gt;
 '''scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;'''&lt;br /&gt;
 set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
 set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
 put player at 0 0&lt;br /&gt;
 ''': &amp;quot;playerloop&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;player_x&amp;quot; &amp;lt; &amp;quot;('bminx'+'bmaxx'/2)&amp;quot; then &amp;quot;#playerleft&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;player_x&amp;quot; &amp;gt; &amp;quot;('bminx'+'bmaxx'/2)&amp;quot; then &amp;quot;#playerright&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;player_y&amp;quot; &amp;lt; &amp;quot;('bminy'+'bmaxy'/2)&amp;quot; then &amp;quot;#playerup&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;player_y&amp;quot; &amp;gt; &amp;quot;('bminy'+'bmaxy'/2)&amp;quot; then &amp;quot;#playerdown&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;Uberleet expression hack method:&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;put player at \&amp;quot;('bminx'+'bmaxx'/2&amp;lt;'player_x'*('board_w'-1))\&amp;quot; \&amp;quot;('bminy'+'bmaxy'/2&amp;lt;'player_y'*('board_h'-1))\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''wait for 1'''&lt;br /&gt;
 '''goto &amp;quot;playerloop&amp;quot;'''&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;edge0&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;('bmaxy'-'spr_p_h')&amp;quot;&lt;br /&gt;
 '''set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;('bmaxy'-'vh')&amp;quot;'''&lt;br /&gt;
 &amp;lt;s&amp;gt;put player at 0 0&amp;lt;/s&amp;gt;&lt;br /&gt;
 move player NORTH&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;edge1&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;bminy&amp;quot;&lt;br /&gt;
 '''set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;bminy&amp;quot;'''&lt;br /&gt;
 &amp;lt;s&amp;gt;put player at &amp;quot;('board_w'-1)&amp;quot; &amp;quot;('board_h'-1)&amp;quot;&amp;lt;/s&amp;gt;&lt;br /&gt;
 move player SOUTH&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;edge2&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;('bmaxx'-'spr_p_w')&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;player_y&amp;quot;&lt;br /&gt;
 '''set &amp;quot;local4&amp;quot; to &amp;quot;('bmaxx'-'vw')&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;'''&lt;br /&gt;
 &amp;lt;s&amp;gt;put player at 0 0&amp;lt;/s&amp;gt;&lt;br /&gt;
 move player WEST&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;edge3&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;bminx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;player_y&amp;quot;&lt;br /&gt;
 '''set &amp;quot;local4&amp;quot; to &amp;quot;bminx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;'''&lt;br /&gt;
 &amp;lt;s&amp;gt;put player at &amp;quot;('board_w'-1)&amp;quot; &amp;quot;('board_h'-1)&amp;quot;&amp;lt;/s&amp;gt;&lt;br /&gt;
 move player EAST&lt;br /&gt;
 end&lt;br /&gt;
 ''': &amp;quot;#playerleft&amp;quot;'''&lt;br /&gt;
 '''put player at 0 &amp;quot;playery&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#playerright&amp;quot;'''&lt;br /&gt;
 '''put player at &amp;quot;('board_w'-1)&amp;quot; &amp;quot;playery&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#playerup&amp;quot;'''&lt;br /&gt;
 '''put player at &amp;quot;playerx&amp;quot; 0'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#playerdown&amp;quot;'''&lt;br /&gt;
 '''put player at &amp;quot;playerx&amp;quot; &amp;quot;('board_h'-1)&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_p_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_p_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_p_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_p_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_p_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_p_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_p_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_p_ch&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0&lt;br /&gt;
 if &amp;quot;player_y&amp;quot; &amp;lt;= &amp;quot;bminy&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;player_y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 1&lt;br /&gt;
 if &amp;quot;player_y&amp;quot; &amp;gt;= &amp;quot;('bmaxy'-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;player_y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 2&lt;br /&gt;
 if &amp;quot;player_x&amp;quot; &amp;lt;= &amp;quot;bminx&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;player_x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 3&lt;br /&gt;
 if &amp;quot;player_x&amp;quot; &amp;gt;= &amp;quot;('bmaxx'-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;player_x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;player_x&amp;quot; &amp;quot;player_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 '''if &amp;quot;scrolledx&amp;quot; &amp;lt; &amp;quot;bminx&amp;quot; then &amp;quot;#fixleft&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;scrolledx&amp;quot; &amp;gt; &amp;quot;('bmaxx'-'vw')&amp;quot; then &amp;quot;#fixright&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;scrolledy&amp;quot; &amp;lt; &amp;quot;bminy&amp;quot; then &amp;quot;#fixup&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;scrolledy&amp;quot; &amp;gt; &amp;quot;('bmaxy'-'vh')&amp;quot; then &amp;quot;#fixdown&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;Uberleet expression hack method:&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;local2\&amp;quot; to \&amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;local3\&amp;quot; to \&amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;scrollview position \&amp;quot;local2\&amp;quot; \&amp;quot;local3\&amp;quot;&amp;quot;'''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ''': &amp;quot;#fixleft&amp;quot;'''&lt;br /&gt;
 '''scrollview position &amp;quot;bminx&amp;quot; &amp;quot;scrolledy&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#fixright&amp;quot;'''&lt;br /&gt;
 '''scrollview position &amp;quot;('bmaxx'-'vw')&amp;quot; &amp;quot;scrolledy&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#fixup&amp;quot;'''&lt;br /&gt;
 '''scrollview position &amp;quot;scrolledx&amp;quot; &amp;quot;bminy&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#fixdown&amp;quot;'''&lt;br /&gt;
 '''scrollview position &amp;quot;scrolledx&amp;quot; &amp;quot;('bmaxy'-'vh')&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Key robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_k_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_k_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_k_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_k_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_k_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_k_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_k_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_k_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Door robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_doors&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1'''&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_d_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_d_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_d_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_d_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_d_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_d_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_d_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_d_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
 dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;num_doors&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;doorsprite&amp;amp;num_doors&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 : &amp;quot;end&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
[[Sprite#E2.4|Back]]&lt;br /&gt;
&lt;br /&gt;
==Example 3.1==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 '''set &amp;quot;commands&amp;quot; to 4096'''&lt;br /&gt;
 '''set &amp;quot;maxhealth&amp;quot; to 100'''&lt;br /&gt;
 '''set maxhealth to &amp;quot;maxhealth&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;enter_menu&amp;quot; to 0'''&lt;br /&gt;
 set &amp;quot;bminx&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bminy&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bmaxx&amp;quot; to 81&lt;br /&gt;
 set &amp;quot;bmaxy&amp;quot; to 26&lt;br /&gt;
 set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;vh&amp;quot; to 25&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to 6&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 '''set &amp;quot;lyr_s_x&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;lyr_s_y&amp;quot; to 3'''&lt;br /&gt;
 '''set &amp;quot;lyr_s_w&amp;quot; to 50'''&lt;br /&gt;
 '''set &amp;quot;lyr_s_h&amp;quot; to 2'''&lt;br /&gt;
 '''set &amp;quot;lyr_sh_x&amp;quot; to 10'''&lt;br /&gt;
 '''set &amp;quot;lyr_sh_y&amp;quot; to 3'''&lt;br /&gt;
 '''set &amp;quot;lyr_sh_w&amp;quot; to 25'''&lt;br /&gt;
 '''set &amp;quot;lyr_sh_h&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;lyr_sa_x&amp;quot; to 43'''&lt;br /&gt;
 '''set &amp;quot;lyr_sa_y&amp;quot; to 3'''&lt;br /&gt;
 '''set &amp;quot;lyr_sa_w&amp;quot; to 5'''&lt;br /&gt;
 '''set &amp;quot;lyr_sa_h&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;lyr_sk_x&amp;quot; to 8'''&lt;br /&gt;
 '''set &amp;quot;lyr_sk_y&amp;quot; to 4'''&lt;br /&gt;
 '''set &amp;quot;lyr_sk_w&amp;quot; to 40'''&lt;br /&gt;
 '''set &amp;quot;lyr_sk_h&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;spr_sh_x&amp;quot; to 8'''&lt;br /&gt;
 '''set &amp;quot;spr_sh_y&amp;quot; to 0'''&lt;br /&gt;
 put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0&lt;br /&gt;
 '''put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;'''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
 set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
 . &amp;quot;Uberleet expression hack method:&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local4\&amp;quot; to \&amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')\&amp;quot;&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local5\&amp;quot; to \&amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')\&amp;quot;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;statusbar&amp;amp;_off&amp;quot; to 1'''&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_doors'-1)&amp;quot;&lt;br /&gt;
 set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;num_doors&amp;quot; to 0&lt;br /&gt;
 lockscroll&lt;br /&gt;
 scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;&lt;br /&gt;
 set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
 set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
 put player at 0 0&lt;br /&gt;
 : &amp;quot;playerloop&amp;quot;&lt;br /&gt;
 . &amp;quot;... Lines after this point have not changed.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;The player, key, and door robots have not changed.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Status bar robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;('vw'-'lyr_s_w'/2)&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 set &amp;quot;statusbar&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_static&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_s_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_s_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_s_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 500&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 0&lt;br /&gt;
 restore &amp;quot;keyenter&amp;quot; 255&lt;br /&gt;
 goto &amp;quot;keyenter&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
 goto &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
 goto &amp;quot;#doammo&amp;quot;&lt;br /&gt;
 goto &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
 copy block &amp;quot;#&amp;amp;spr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_sh_y&amp;amp;&amp;quot; for &amp;quot;('health'*'lyr_sh_w'/'maxhealth')&amp;quot; &amp;quot;lyr_sh_h&amp;quot; to &amp;quot;#&amp;amp;lyr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_sh_y&amp;amp;&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#doammo&amp;quot;&lt;br /&gt;
 . &amp;quot;Uberleet expression hack for capping ammo at 99999.&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;ammo\&amp;quot; to \&amp;quot;('ammo'&amp;gt;99999*(99999-'ammo')+'ammo')\&amp;quot;&amp;quot;&lt;br /&gt;
 set &amp;quot;$ammo&amp;quot; to &amp;quot;&amp;amp;ammo&amp;amp;&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;vch('lyr_sa_x'+'loopcount'),('lyr_sa_y')&amp;quot; to &amp;quot;$ammo.&amp;amp;loopcount&amp;amp;&amp;quot;&lt;br /&gt;
 loop for &amp;quot;('$ammo.length'-1)&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;local5&amp;quot; to 0&lt;br /&gt;
 : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;keynext&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 if &amp;quot;local5&amp;quot; &amp;gt;= &amp;quot;lyr_sk_w&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
 set &amp;quot;vch('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to 12&lt;br /&gt;
 set &amp;quot;vco('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to &amp;quot;local4&amp;quot;&lt;br /&gt;
 inc &amp;quot;local5&amp;quot; by 1&lt;br /&gt;
 loop for &amp;quot;('key_&amp;amp;local4&amp;amp;'-1)&amp;quot;&lt;br /&gt;
 : &amp;quot;keynext&amp;quot;&lt;br /&gt;
 inc &amp;quot;local4&amp;quot; by 1&lt;br /&gt;
 if &amp;quot;local4&amp;quot; &amp;lt; 256 then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
 if &amp;quot;('spr&amp;amp;playersprite&amp;amp;_y'-'scrolledy')&amp;quot; &amp;gt;= &amp;quot;('vh'-'spr_p_h'/2)&amp;quot; then &amp;quot;drawnext&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;('vh'-'lyr_s_h')&amp;quot;&lt;br /&gt;
 : &amp;quot;drawnext&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
 zap &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
 restore &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
[[Sprite#E3.1|Back]]&lt;br /&gt;
==Example 3.2==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 set &amp;quot;commands&amp;quot; to 4096&lt;br /&gt;
 set &amp;quot;maxhealth&amp;quot; to 100&lt;br /&gt;
 set maxhealth to &amp;quot;maxhealth&amp;quot;&lt;br /&gt;
 set &amp;quot;enter_menu&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;bminx&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bminy&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bmaxx&amp;quot; to 81&lt;br /&gt;
 set &amp;quot;bmaxy&amp;quot; to 26&lt;br /&gt;
 set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;vh&amp;quot; to 25&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_p_x&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_p_cy&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_p_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_p_ch&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_d_x&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_w&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_d_cw&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_d_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_x&amp;quot; to 6&lt;br /&gt;
 set &amp;quot;spr_k_y&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_w&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_h&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;spr_k_cx&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cy&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr_k_cw&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;spr_k_ch&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;lyr_s_x&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;lyr_s_y&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;lyr_s_w&amp;quot; to 50&lt;br /&gt;
 set &amp;quot;lyr_s_h&amp;quot; to 2&lt;br /&gt;
 set &amp;quot;lyr_sh_x&amp;quot; to 10&lt;br /&gt;
 set &amp;quot;lyr_sh_y&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;lyr_sh_w&amp;quot; to 25&lt;br /&gt;
 set &amp;quot;lyr_sh_h&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;lyr_sa_x&amp;quot; to 43&lt;br /&gt;
 set &amp;quot;lyr_sa_y&amp;quot; to 3&lt;br /&gt;
 set &amp;quot;lyr_sa_w&amp;quot; to 5&lt;br /&gt;
 set &amp;quot;lyr_sa_h&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;lyr_sk_x&amp;quot; to 8&lt;br /&gt;
 set &amp;quot;lyr_sk_y&amp;quot; to 4&lt;br /&gt;
 set &amp;quot;lyr_sk_w&amp;quot; to 40&lt;br /&gt;
 set &amp;quot;lyr_sk_h&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr_sh_x&amp;quot; to 8&lt;br /&gt;
 set &amp;quot;spr_sh_y&amp;quot; to 0&lt;br /&gt;
 '''set &amp;quot;spr_pb_x&amp;quot; to 8'''&lt;br /&gt;
 '''set &amp;quot;spr_pb_y&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;spr_pb_w&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;spr_pb_h&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;lyr_pb_x&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;lyr_pb_y&amp;quot; to 5'''&lt;br /&gt;
 '''set &amp;quot;lyr_pb_w&amp;quot; to &amp;quot;('bmaxx'-'bminx')&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;('bmaxy'-'bminy')&amp;quot;'''&lt;br /&gt;
 put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0&lt;br /&gt;
 put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
 '''copy block at &amp;quot;#&amp;amp;lyr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_pb_y&amp;amp;&amp;quot; for &amp;quot;lyr_pb_w&amp;quot; &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;@blank.mzm&amp;quot; 1'''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
 set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
 . &amp;quot;Uberleet expression hack method:&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local4\&amp;quot; to \&amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')\&amp;quot;&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local5\&amp;quot; to \&amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')\&amp;quot;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;statusbar&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;playerbullets&amp;amp;_off&amp;quot; to 1'''&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
 loop for &amp;quot;('num_doors'-1)&amp;quot;&lt;br /&gt;
 set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;num_doors&amp;quot; to 0&lt;br /&gt;
 lockscroll&lt;br /&gt;
 scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;&lt;br /&gt;
 set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
 set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
 put player at 0 0&lt;br /&gt;
 : &amp;quot;playerloop&amp;quot;&lt;br /&gt;
 . &amp;quot;... Lines after this point have not changed.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;The player, status bar, key, and door robots have not changed.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player bullet robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;playerbullets&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 set &amp;quot;pbullets&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;pbullets_remove&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_pb_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_pb_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_pb_h&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; &amp;quot;bminx&amp;quot; &amp;quot;bminy&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 goto &amp;quot;#add&amp;quot;&lt;br /&gt;
 goto &amp;quot;#move&amp;quot;&lt;br /&gt;
 goto &amp;quot;#check&amp;quot;&lt;br /&gt;
 goto &amp;quot;#remove&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#add&amp;quot;&lt;br /&gt;
 . &amp;quot;TODO&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#move&amp;quot;&lt;br /&gt;
 . &amp;quot;TODO&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#check&amp;quot;&lt;br /&gt;
 . &amp;quot;TODO&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#remove&amp;quot;&lt;br /&gt;
 . &amp;quot;TODO&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 . &amp;quot;TODO&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
[[Sprite#E3.2|Back]]&lt;br /&gt;
&lt;br /&gt;
==Example 3.3==&lt;br /&gt;
 . &amp;quot;The global, player, status bar, key, and door robots have not changed.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player bullet robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;playerbullets&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 set &amp;quot;pbullets&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;pbullets_remove&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_pb_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_pb_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_pb_h&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; &amp;quot;bminx&amp;quot; &amp;quot;bminy&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 '''if &amp;quot;pbullets_add&amp;quot; &amp;gt; 0 then &amp;quot;#add&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#move&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#check&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;'''&lt;br /&gt;
 '''put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1'''&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#add&amp;quot;&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_add&amp;amp;loopcount&amp;amp;&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_width'/2+'spr&amp;amp;local2&amp;amp;_x'-'bminx')&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_height'/2+'spr&amp;amp;local2&amp;amp;_y'-'bminy')&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;Uberleet expression hack version&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx\&amp;quot; to \&amp;quot;('spr&amp;amp;local2&amp;amp;_lastmove'%2*2-1*('spr&amp;amp;local2&amp;amp;_lastmove'/2))\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''. &amp;quot;set \&amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy\&amp;quot; to \&amp;quot;('spr&amp;amp;local2&amp;amp;_lastmove'%2*2-1*('spr&amp;amp;local2&amp;amp;_lastmove'/2-1*-1))\&amp;quot;&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#add('spr&amp;amp;local2&amp;amp;_lastmove')&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;pbullets&amp;quot; by 1'''&lt;br /&gt;
 '''loop for &amp;quot;('pbullets_add'-1)&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets_add&amp;quot; to 0'''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#move&amp;quot;&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vx&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vy&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;(('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;lt;'lyr_pb_w')a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;lt;'lyr_pb_h'))&amp;quot; = 1 then &amp;quot;movenext&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;pbullets_remove&amp;quot; by 1'''&lt;br /&gt;
 ''': &amp;quot;movenext&amp;quot;'''&lt;br /&gt;
 '''loop for &amp;quot;('pbullets'-1)&amp;quot;'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 : &amp;quot;#check&amp;quot;&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_pb_w&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_pb_h&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;spr&amp;amp;local&amp;amp;_clist&amp;quot; to 1'''&lt;br /&gt;
 '''if &amp;quot;spr_collisions&amp;quot; &amp;lt;= 0 then &amp;quot;checknext&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to 0'''&lt;br /&gt;
 ''': &amp;quot;collide&amp;quot;'''&lt;br /&gt;
 '''if &amp;quot;spr_clist&amp;amp;local2&amp;amp;&amp;quot; = &amp;quot;playersprite&amp;quot; then &amp;quot;checknext&amp;quot;'''&lt;br /&gt;
 '''send &amp;quot;spr('spr_clist&amp;amp;local2&amp;amp;')&amp;quot; to &amp;quot;playershot&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;local2&amp;quot; by 1'''&lt;br /&gt;
 '''if &amp;quot;local2&amp;quot; &amp;lt; &amp;quot;spr_collisions&amp;quot; then &amp;quot;collide&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;pbullets_remove&amp;quot; by 1'''&lt;br /&gt;
 ''': &amp;quot;checknext&amp;quot;'''&lt;br /&gt;
 '''loop for &amp;quot;('pbullets'-1)&amp;quot;'''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#remove&amp;quot;&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''dec &amp;quot;pbullets&amp;quot; by 1'''&lt;br /&gt;
 '''set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_remove('pbullets_remove'-'loopcount'-1)&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;local2&amp;amp;_x&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;local2&amp;amp;_y&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vx&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vy&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot;'''&lt;br /&gt;
 '''loop for &amp;quot;('pbullets_remove'-1)&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets_remove&amp;quot; to 0'''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 '''loop start'''&lt;br /&gt;
 '''copy block at &amp;quot;#&amp;amp;spr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_pb_y&amp;amp;&amp;quot; for &amp;quot;spr_pb_w&amp;quot; &amp;quot;spr_pb_h&amp;quot; to &amp;quot;#('lyr_pb_x'+'pbullets&amp;amp;loopcount&amp;amp;_x')&amp;quot; &amp;quot;#('lyr_pb_y'+'pbullets&amp;amp;loopcount&amp;amp;_y')&amp;quot;'''&lt;br /&gt;
 '''loop for &amp;quot;('pbullets'-1)&amp;quot;'''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ''': &amp;quot;#add0&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot; to -1'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#add1&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 0'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot; to 1'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#add2&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to -1'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot; to 0'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ''': &amp;quot;#add3&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 1'''&lt;br /&gt;
 '''set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot; to 0'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
[[Sprite#E3.3|Back]]&lt;br /&gt;
==Example 3.4==&lt;br /&gt;
 . &amp;quot;Global robot&amp;quot;&lt;br /&gt;
 set &amp;quot;commands&amp;quot; to 4096&lt;br /&gt;
 set &amp;quot;maxhealth&amp;quot; to 100&lt;br /&gt;
 set maxhealth to &amp;quot;maxhealth&amp;quot;&lt;br /&gt;
 '''set &amp;quot;ammo&amp;quot; to 10000'''&lt;br /&gt;
 set &amp;quot;enter_menu&amp;quot; to 0&lt;br /&gt;
 set &amp;quot;bminx&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bminy&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;bmaxx&amp;quot; to 81&lt;br /&gt;
 set &amp;quot;bmaxy&amp;quot; to 26&lt;br /&gt;
 set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
 set &amp;quot;vh&amp;quot; to 25&lt;br /&gt;
 set &amp;quot;spr_yorder&amp;quot; to 1&lt;br /&gt;
 . &amp;quot;... And all the rest.&amp;quot;&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Player robot&amp;quot;&lt;br /&gt;
 lockplayer&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_p_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_p_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_p_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_p_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_p_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_p_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_p_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_p_ch&amp;quot;&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
 if leftpressed then &amp;quot;#left&amp;quot;&lt;br /&gt;
 if rightpressed then &amp;quot;#right&amp;quot;&lt;br /&gt;
 if downpressed then &amp;quot;#down&amp;quot;&lt;br /&gt;
 wait for 1&lt;br /&gt;
 goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
 : &amp;quot;#up&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0&lt;br /&gt;
 '''if spacepressed then &amp;quot;shoot&amp;quot;'''&lt;br /&gt;
 if &amp;quot;player_y&amp;quot; &amp;lt;= &amp;quot;bminy&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;player_y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#down&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 1&lt;br /&gt;
 '''if spacepressed then &amp;quot;shoot&amp;quot;'''&lt;br /&gt;
 if &amp;quot;player_y&amp;quot; &amp;gt;= &amp;quot;('bmaxy'-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 1 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;player_y&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#left&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 2&lt;br /&gt;
 '''if spacepressed then &amp;quot;shoot&amp;quot;'''&lt;br /&gt;
 if &amp;quot;player_x&amp;quot; &amp;lt;= &amp;quot;bminx&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at -1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 dec &amp;quot;player_x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#right&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 3&lt;br /&gt;
 '''if spacepressed then &amp;quot;shoot&amp;quot;'''&lt;br /&gt;
 if &amp;quot;player_x&amp;quot; &amp;gt;= &amp;quot;('bmaxx'-'spr&amp;amp;local&amp;amp;_width')&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 if c?? Sprite_colliding &amp;quot;local&amp;quot; at 1 0 then &amp;quot;collision&amp;quot;&lt;br /&gt;
 inc &amp;quot;player_x&amp;quot; by 1&lt;br /&gt;
 goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#draw&amp;quot;&lt;br /&gt;
 put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;player_x&amp;quot; &amp;quot;player_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&lt;br /&gt;
 if &amp;quot;scrolledx&amp;quot; &amp;lt; &amp;quot;bminx&amp;quot; then &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
 if &amp;quot;scrolledx&amp;quot; &amp;gt; &amp;quot;('bmaxx'-'vw')&amp;quot; then &amp;quot;#fixright&amp;quot;&lt;br /&gt;
 if &amp;quot;scrolledy&amp;quot; &amp;lt; &amp;quot;bminy&amp;quot; then &amp;quot;#fixup&amp;quot;&lt;br /&gt;
 if &amp;quot;scrolledy&amp;quot; &amp;gt; &amp;quot;('bmaxy'-'vh')&amp;quot; then &amp;quot;#fixdown&amp;quot;&lt;br /&gt;
 . &amp;quot;Uberleet expression hack method:&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local2\&amp;quot; to \&amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')\&amp;quot;&amp;quot;&lt;br /&gt;
 . &amp;quot;set \&amp;quot;local3\&amp;quot; to \&amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')\&amp;quot;&amp;quot;&lt;br /&gt;
 . &amp;quot;scrollview position \&amp;quot;local2\&amp;quot; \&amp;quot;local3\&amp;quot;&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
 send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
 scrollview position &amp;quot;bminx&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#fixright&amp;quot;&lt;br /&gt;
 scrollview position &amp;quot;('bmaxx'-'vw')&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#fixup&amp;quot;&lt;br /&gt;
 scrollview position &amp;quot;scrolledx&amp;quot; &amp;quot;bminy&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 : &amp;quot;#fixdown&amp;quot;&lt;br /&gt;
 scrollview position &amp;quot;scrolledx&amp;quot; &amp;quot;('bmaxy'-'vh')&amp;quot;&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;&lt;br /&gt;
 ''': &amp;quot;shoot&amp;quot;'''&lt;br /&gt;
 '''take 1 AMMOS else &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;pbullets_add&amp;amp;pbullets_add&amp;amp;&amp;quot; to &amp;quot;local&amp;quot;'''&lt;br /&gt;
 '''inc &amp;quot;pbullets_add&amp;quot; by 1'''&lt;br /&gt;
 '''goto &amp;quot;#return&amp;quot;'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Key robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_k_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_k_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_k_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_k_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_k_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_k_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_k_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_k_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 ''': &amp;quot;playershot&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;('local4'%16)&amp;quot;'''&lt;br /&gt;
 '''* &amp;quot;~&amp;amp;+local5&amp;amp;Ouch, you shot me!&amp;quot;'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
 ---------------------------------------------------------------&lt;br /&gt;
 . &amp;quot;Door robot&amp;quot;&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
 set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
 restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
 | &amp;quot;justentered&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_doors&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
 inc &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;spr_d_x&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;spr_d_y&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;spr_d_w&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;spr_d_h&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;spr_d_cx&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;spr_d_cy&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_d_cw&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_d_ch&amp;quot;&lt;br /&gt;
 put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 : &amp;quot;touch&amp;quot;&lt;br /&gt;
 if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
 dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
 dec &amp;quot;num_doors&amp;quot; by 1&lt;br /&gt;
 set &amp;quot;spr('doorsprite&amp;amp;num_doors&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
 set &amp;quot;doorsprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;doorsprite&amp;amp;num_doors&amp;amp;&amp;quot;&lt;br /&gt;
 set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
 die&lt;br /&gt;
 : &amp;quot;end&amp;quot;&lt;br /&gt;
 end&lt;br /&gt;
 ''': &amp;quot;playershot&amp;quot;'''&lt;br /&gt;
 '''set &amp;quot;local5&amp;quot; to &amp;quot;('local4'%16)&amp;quot;'''&lt;br /&gt;
 '''* &amp;quot;~&amp;amp;+local5&amp;amp;Ouch, you shot me!&amp;quot;'''&lt;br /&gt;
 '''end'''&lt;br /&gt;
[[Sprite#E3.4|Back]]&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7671</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7671"/>
		<updated>2011-01-26T20:40:59Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For a comprehensive tutorial on sprites, see [[Sprite (Tutorial)]].&amp;lt;!--don't know how to do this properly--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[PUT color Sprite param # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite_Colliding pNN # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite p?? # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
===Instantiation===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_X]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_Y]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_HEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_WIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Collision===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CWIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CHEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CLIST]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_CLISTn]] (read-only)''' &lt;br /&gt;
&lt;br /&gt;
'''[[SPR_COLLISIONS]] (read-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CCHECK]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_NUM]]'''&lt;br /&gt;
&lt;br /&gt;
===Graphical===&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_YORDER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OFF]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAID]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAY]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_STATIC]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_VLAYER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SWAP]] (write-only)'''&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7670</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7670"/>
		<updated>2011-01-26T20:24:59Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For a comprehensive tutorial on sprites, see [[Sprite (Tutorial)]].&amp;lt;!--don't know how to do this properly--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[PUT color Sprite param # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite_Colliding pNN # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite p?? # # &amp;quot;label&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CLIST]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_CLISTn]] (read-only)''' &lt;br /&gt;
&lt;br /&gt;
'''[[SPR_COLLISIONS]] (read-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_NUM]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPR_YORDER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CHECK]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CWIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CHEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_CY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OFF]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAID]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_OVERLAY]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_REFY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_STATIC]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SWAP]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_VLAYER]] (write-only)'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_HEIGHT]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_WIDTH]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_X]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_Y]]'''&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7669</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7669"/>
		<updated>2011-01-26T19:42:32Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For a comprehensive tutorial on sprites, see [[Sprite (Tutorial)]].&amp;lt;!--don't know how to do this properly--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
&lt;br /&gt;
'''[[IF color Sprite_Colliding pNN # # &amp;quot;label&amp;quot;]]'''&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7668</id>
		<title>Sprite</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite&amp;diff=7668"/>
		<updated>2011-01-26T19:37:26Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Sprite to Sprite (Tutorial): Writing a much shorter page for Sprites instead.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Sprite (Tutorial)]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7667</id>
		<title>Sprite (Tutorial)</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Sprite_(Tutorial)&amp;diff=7667"/>
		<updated>2011-01-26T19:37:26Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: moved Sprite to Sprite (Tutorial): Writing a much shorter page for Sprites instead.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Sprites''' were introduced to [[MegaZeux]] in version 2.65, primarily as a method of making it easier to implement large object representations in the game (for example, [[Engine|engines]] for handling a multiple character player or enemies).  They include many features such as collision detection, easy drawing, and configurable draw order.  Despite being designed to make coding easier, many [[:Category:MZXers|MZXers]] avoid their use in favor of more traditional methods such as [[overlay]] buffering and hand-rolled collision routines.  This is largely out of a perception that Sprites are difficult to use.&lt;br /&gt;
__NOTOC__ &lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid black; font-size: 1; display: table; padding: 1em&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;center&amp;gt;'''Contents'''&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[#Sprite Tutorial|Sprite Tutorial]]&lt;br /&gt;
:[[#S1|1 The Basics: Drawing Sprites]]&lt;br /&gt;
::[[#E1.1|Exercise 1.1: Making a sprite based player]]&lt;br /&gt;
::[[#E1.2|Exercise 1.2: Improving and generalizing the code]]&lt;br /&gt;
:[[#S1a|1a The Not So Basics: Sprite Collision]]&lt;br /&gt;
::[[#E1.3|Exercise 1.3: Adding basic collision detection]]&lt;br /&gt;
:[[#S2|2 The Sprite-Object Model: Active Collision]]&lt;br /&gt;
::[[#E2.1|Exercise 2.1: Keys and doors with sprites]]&lt;br /&gt;
::[[#E2.2|Exercise 2.2: Keeping track of sprites on the board]]&lt;br /&gt;
::[[#E2.3|Exercise 2.3: Moving the player sprite between boards]]&lt;br /&gt;
::[[#E2.4|Exercise 2.4: Finishing touches, fixing the scrolling]]&lt;br /&gt;
:[[#S3|3 The Sprite-Layer Model: Working With Layers]]&lt;br /&gt;
::[[#E3.1|Exercise 3.1: Creating a status bar]]&lt;br /&gt;
::[[#E3.2|Exercise 3.2: Bullets as a layer (framework)]]&lt;br /&gt;
::[[#E3.3|Exercise 3.3: Bullets as a layer (implementation)]]&lt;br /&gt;
::[[#E3.4|Exercise 3.4: Interacting with the rest of the game]]&lt;br /&gt;
&lt;br /&gt;
[[#External Links|External Links]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
==Sprite Tutorial==&lt;br /&gt;
Despite the mystery and trepidation that generally surrounds them, sprites are not that hard to work with and are designed to be easy to use, with the right program model.  Two common and effective models, which can be used together or alone depending on the requirements of the engine, are the '''sprite-layer model''' and the '''sprite-object model'''.  The structure of your code will depend on the application and the model being used, but there are some basics to cover first.&lt;br /&gt;
{{a|S1}}&lt;br /&gt;
===The Basics: Drawing Sprites===&lt;br /&gt;
All sprites, regardless of their function, require some basic initialization and setup before they can be used.  First, you need to set aside space on the board (or the [[Vlayer]]) for the sprite source image.  You don't even have to put anything there yet, some advanced techniques construct the image data dynamically.  But you need a block of space that is going to be used for sprite data.  Next, all sprites need initialization code somewhere that designates this area.&lt;br /&gt;
 set &amp;quot;spr#_refx&amp;quot; to XCOORD      ''These counters specify the x coordinate, y coordinate,''&lt;br /&gt;
 set &amp;quot;spr#_refy&amp;quot; to YCOORD      ''width, and height of the bounding rectangle for the source image''&lt;br /&gt;
 set &amp;quot;spr#_width&amp;quot; to WIDTH      ''Replace # with the number of the sprite, from 0 to 255.''&lt;br /&gt;
 set &amp;quot;spr#_height&amp;quot; to HEIGHT    ''Counter interpolation is acceptable and in fact common for this.''&lt;br /&gt;
Finally, all sprites need to be placed somewhere in order to be viewed.  While &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot; counters do exist, and they can be written to place and move the sprite, we recommend you treat them as read-only and use the &amp;quot;put&amp;quot; command for readability and clarity of purpose:&lt;br /&gt;
 put c?? Sprite # at X Y        ''# is the number of the sprite to be placed, as a parameter.  Can be a counter.''&lt;br /&gt;
{{a|E1.1}}&lt;br /&gt;
====Exercise 1.1: Making a sprite based player====&lt;br /&gt;
A common application for sprites is to have all actors in the game, including the player, be represented by sprites.  This lends itself well to a sprite-object model, but we'll come to that later.  Our first exercise will be to make a player sprite that can be moved around with the arrow keys.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, start editing a new world, and draw a customblock smiley face on the board.  It doesn't really matter what it looks like, or where it is, but for the sake of example put it at (80,0) off the right edge of the screen, and make it 3x3 characters large.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Create a new robot called &amp;quot;sprite&amp;quot; to handle the sprite drawing and moving code.  I like to put my control robots in a horizontal line starting at (1,0), but again, it really doesn't matter.  The very first line of the robot should be &amp;quot;lockplayer&amp;quot;, just to keep the player from moving around.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Let's use sprite 0 for our player.  So, the next 4 commands should be:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr0_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr0_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr0_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr0_height&amp;quot; to 3&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a control loop that draws the sprite and handles input.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite p00 at &amp;quot;x&amp;quot; &amp;quot;y&amp;quot;&lt;br /&gt;
: if uppressed then &amp;quot;up&amp;quot;&lt;br /&gt;
: if leftpressed then &amp;quot;left&amp;quot;&lt;br /&gt;
: if rightpressed then &amp;quot;right&amp;quot;&lt;br /&gt;
: if downpressed then &amp;quot;down&amp;quot;&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that x and y will default to 0 since they haven't been used yet.  It's generally a good idea to keep this information in a pair of local counters and initialize them along with the rest of the sprite data.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, you just need code to modify the values of &amp;quot;x&amp;quot; and &amp;quot;y&amp;quot; for each label &amp;quot;up&amp;quot;, &amp;quot;left&amp;quot;, &amp;quot;right&amp;quot;, and &amp;quot;down&amp;quot;.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: dec &amp;quot;y&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And the rest should be obvious: inc &amp;quot;y&amp;quot; by 1 for &amp;quot;down&amp;quot;, dec &amp;quot;x&amp;quot; by 1 for &amp;quot;left&amp;quot;, and inc &amp;quot;x&amp;quot; by 1 for &amp;quot;right&amp;quot;.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.1|Example 1.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E1.2}}&lt;br /&gt;
====Exercise 1.2: Improving and generalizing the code====&lt;br /&gt;
That's it, you can now test your world and move the sprite around.  You'll notice that the sprite gets &amp;quot;stuck&amp;quot; if you move it off the top or left of the board, and disappears off the bottom right.  That's because we didn't do any bounds checking.  In fact, there are a lot of improvements we can make to this code before we move on.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First let's make the sprite initialization dynamic.  This may seem like more work now, but it'll make things much easier when you want to play with a lot of objects later, and decide that you need to reallocate sprite numbers.  We'll declare local counters for the sprite draw location while we're at it.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to 3&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;We also need some bounds checking.  I prefer to define variables for zone boundaries, but we'll use constants with [[expressions]] for now.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: : &amp;quot;down&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;gt;= &amp;quot;(25-'spr&amp;amp;local&amp;amp;_height')&amp;quot; then &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: inc &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that &amp;quot;local3&amp;quot; is &amp;quot;y&amp;quot;.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You also probably noticed that the previous movement routine favored certain directions over others; you can fix this by turning the label calls into [[subroutines]] (with diagonal movement as a free bonus!)&amp;lt;tt&amp;gt;&lt;br /&gt;
: if uppressed then &amp;quot;#up&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One pitfall that comes with using subroutines for movement like this is that it's possible to get the sprite stuck on corners as you move it.  This is because the sprite position is not updated after the sprite counters are changed, but only after every move direction has been checked.  One way to fix this is to just use the spr#_x and spr#_y counters instead of local counters, since those are directly tied to sprite position.  But for reasons we'll discuss later, I recommend against this, or at least keeping copies of them in local counters.  The other way is to make sure the sprite is updated (i.e. drawn) after each move.  This is accomplished most easily through subroutines as well:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for every location where the sprite needs updating, that is at the end of all movement subroutines and within the main loop, call the subroutine &amp;quot;#draw&amp;quot; with a goto.  In fact, it's not really even necessary to call this in every iteration of the main loop if it's called on movement.  It only needs to be called once after all the sprite counters have been initialized.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Since this is our player sprite, it would be nice if we could get the screen scrolling to act like it.  Fortunately there's a really easy way to do this without having to work out a bunch of bothersome math.  Just put the following functional counter in your #draw subroutine, after you draw the sprite:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_setview&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Really simple, and another good reason to have a separate subroutine for the drawing code, since that makes it easy to update and augment.  You can now expand the board area and bounds checking beyond the confines of the viewport.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This leaves us with this final code:&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.2|Example 1.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S1a}}&lt;br /&gt;
===The Not So Basics: Sprite Collision===&lt;br /&gt;
So we can now draw a sprite and move it around the screen.  This is great, but except for some very limited cases is not particularly useful for gameplay.  Simple bounds checking is easy enough to implement, but what if we want to have our player sprite move around inside a defined terrain, with walls and solid objects and impassible barriers?  Worse, what if we want to interact with the environment, or with other sprites?  Designing this from scratch would involve doing a lot of checking for [[customblocks]], a way to figure out which sprite is at a specific location, and depending on the size of the sprite being moved, would require checking multiple locations each time in order to ensure consistency.  It would be difficult to make the system general enough to be transplantable from game to game, and if you did manage it it would be hard to read and understand the code.&lt;br /&gt;
&lt;br /&gt;
Fortunately, MZX provides a way to do all that work with one statement:&lt;br /&gt;
 if c?? Sprite_colliding p## at X Y then LABEL   ''p## is the number of the sprite you want to move, X and Y are relative coordinates.''&lt;br /&gt;
One of the reasons people find this simple command so difficult to use is that they don't understand what it actually does.  The first important requirement is that the sprite being moved define a collision rectangle.  This should be done along with the other sprite initialization counters like so:&lt;br /&gt;
 set &amp;quot;spr#_cx&amp;quot; to X             ''These X and Y coordinates are relative values.''&lt;br /&gt;
 set &amp;quot;spr#_cy&amp;quot; to Y             ''That means you set them relative to (0,0) as the top left corner of the sprite.''&lt;br /&gt;
 set &amp;quot;spr#_cwidth&amp;quot; to WIDTH     ''So if you want the collision rectangle to be the same size and area as the sprite itself,''&lt;br /&gt;
 set &amp;quot;spr#_cheight&amp;quot; to HEIGHT   ''cx and cy should both be 0, and cwidth and cheight should be the same as width and height.''&lt;br /&gt;
Most people understand this much.  What often gets confused is that the Sprite_colliding object in the if statement is NOT this collision rectangle.  Nor does it directly represent the collision rectangle of another sprite, though it is necessary for other sprites to have collision rectangles in order for collision to work.  But there isn't an actual sprite_colliding object anywhere on the board, this is simply the syntax used to call collision detection for a sprite in advance of movement.  The command says &amp;quot;if I hypothetically move this sprite (specified by the parameter) X by Y from its current location, will it collide with anything.&amp;quot;  And then it branches depending on whether the answer is true or false.&lt;br /&gt;
&lt;br /&gt;
The two key points about X and Y are that they are ''relative'' to the sprite's current location, and they specify the ''movement'' of the sprite, not the position of something else.  The color term is co-opted to perform a non-intuitive task of specifying relative versus absolute movement.  c?? means that X and Y are relative values, and is what you will normally want to use.  c00 (or any other absolute color) make X and Y absolute coordinates, but again the statement checks to see what would happen if you put the sprite at that location, not for the presence of some other object at that location.  This is vital to understand, since without it you will probably try to do much more work than you need to do, and will probably achieve unexpected and incorrect results for your efforts.&lt;br /&gt;
&lt;br /&gt;
{{a|E1.3}}&lt;br /&gt;
====Exercise 1.3: Adding basic collision detection====&lt;br /&gt;
Let's see if we can't improve our player sprite code and turn it into something you might actually want to use in a game.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, take that board you were working on and draw some walls on it.  Sprite collision detection only works with customblocks and other sprites, so in any game where you want to use sprite collision, all of your collidable scenery should be customblock.  But if you're really interested in advanced MZX programming and artwork, you should already be doing this anyway.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;In order to create the illusion of depth and a 3/4 camera angle, we'll define the collision rectangle as being only the bottom row of the sprite.  The sprite dimensions are 3x3, so that means:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 2&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Update each of your movement subroutines to include a collision check along with the bounds check:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: if &amp;quot;local3&amp;quot; &amp;lt;= 0 then &amp;quot;#return&amp;quot;&lt;br /&gt;
: '''if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;#return&amp;quot;'''&lt;br /&gt;
: dec &amp;quot;local3&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, going along with that 3/4 camera thing, you will generally want game sprites farther down the screen to appear &amp;quot;in front&amp;quot; of sprites above them.  Sprites have a globally applicable drawing mode to handle this very thing:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_yorder&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Note that this counter is global to all sprites, and is not a per-sprite counter.  You can stick it anywhere you like, but it makes the most sense to put it in the global robot.  We will discuss how to use layer-like sprites with yorder later.  For now, all you need to know is that this makes sprites draw in order of position from the top of the screen to the bottom, instead of in order of their sprite numbers.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it!  That's really all you have to do!&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 1.3|Example 1.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S2}}&lt;br /&gt;
===The Sprite-Object Model: Active Collision===&lt;br /&gt;
It's wonderful and all that we can make sprites not do something (i.e. move) if they collide.  But what if we want to make them do something else instead?  What if we want that thing to be different depending on the object of the collision?  When you perform a collision check with &amp;quot;if sprite_colliding&amp;quot;, it has the side effect of populating an array-like construct that details what, if anything, was collided with.  This array is called &amp;quot;spr_clist&amp;quot;, its length is stored in the counter &amp;quot;spr_collisions&amp;quot;, and it is accessed as pseudo-arrays usually are in MZX, through counter interpolation.  Here is a typical and flexible collision handler:&lt;br /&gt;
 : &amp;quot;collision&amp;quot;&lt;br /&gt;
 loop start&lt;br /&gt;
 goto &amp;quot;#collide('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot;        ''This will only goto labels that actually exist, making it easily pluggable.''&lt;br /&gt;
 send &amp;quot;spr('spr_clist&amp;amp;loopcount&amp;amp;')&amp;quot; to &amp;quot;touch&amp;quot;  ''This will send to a robot named with the same number as the colliding sprite.''&lt;br /&gt;
 loop for &amp;quot;('spr_collisions'-1)&amp;quot;                ''Don't forget about the loop termination quirk, where the terminator is inclusive.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Short circuits whatever else would have been done had collision not happened.''&lt;br /&gt;
 : &amp;quot;#collide-1&amp;quot;                                 ''-1 is the background, meaning the sprite collided with a customblock.''&lt;br /&gt;
 * &amp;quot;~fOuch, I bumped into a wall!&amp;quot;              ''Normally you wouldn't bother with this label though, since a wall is a wall.''&lt;br /&gt;
 goto &amp;quot;#return&amp;quot;                                 ''Continues collision handling.  Remember, subroutines go on a call stack.''&lt;br /&gt;
The send command is the beginning of understanding sprites with an object model, where each sprite is bound to code in a robot specific to that sprite, so that everything relevant to that sprite (including counters you may create) can be accessed with a single number.  Here, we use that number to send the sprite (and I find it useful to make no distinction between the sprite and the robot controlling it) a touch label.&lt;br /&gt;
&lt;br /&gt;
You should devise and maintain a convention for what robots that control sprites should be called.  &amp;quot;sprite#&amp;quot; or &amp;quot;spr#&amp;quot; are normal, or you could just reference them by number.  In order to make things as code driven as possible, so that you only have to change a single line to reassign a sprite number in a robot, you should do this dynamically in your robot setup with a rename command.  And there's some other stuff you can do to make it easy to move sprites around just by moving the robots that control them.&lt;br /&gt;
 set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;   ''This makes things very dynamic, since you can copy the same robot around the board with no changes''&lt;br /&gt;
 set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;     ''and make multiple copies of the sprite.  Setting local2 and local3 based on the robot's position''&lt;br /&gt;
 set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;     ''means that you don't have to configure the initial sprite placement, either.  Then you can move the''&lt;br /&gt;
 gotoxy &amp;quot;local&amp;quot; 0            ''robot into a robot bank at the top of the board, and the unique value of local ensures you won't''&lt;br /&gt;
 . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;             ''overwrite anything.  But this is not always appropriate, sometimes you'll want to choose a specific ID''&lt;br /&gt;
&lt;br /&gt;
{{a|E2.1}}&lt;br /&gt;
====Exercise 2.1: Keys and doors with sprites====&lt;br /&gt;
Now that we have an idea of how to make our sprite player touch things, let's create some things for him to touch.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First, the player needs a collision handler.  You can use the one we just discussed with no modification (though you may want to take out the #collide-1 label since that's just to demonstrate how to do something special based on what you collided with).  You'll also need to change the target label for the collision check to &amp;quot;collision&amp;quot;:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if c?? Sprite_colliding &amp;quot;local&amp;quot; at 0 -1 then &amp;quot;collision&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
And so on.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;You need to create some key objects and some door objects, at least one of each, but creating more than one will be really, really easy.  Each of these will be sprites, and each of them will have a robot in control.  First, draw some graphics over with the player source you had before.  Remember what their parameters are.  If you want to do something REALLY cool, create a list of constants and put it in the global robot to keep track of these numbers for you.  This way, if you ever change them, or do something like making your sprites vlayer based, you'll have a much easier time of things since you'll only have to change the global robot.  In any case, use what you've learned about sprites so far to create a robot called &amp;quot;key&amp;quot; with a dynamic initialization routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;thisx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;thisy&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;this_color&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to XCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to YCOORD&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to WIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to HEIGHT&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to CX&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to CY&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to CWIDTH&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to CHEIGHT&lt;br /&gt;
: put &amp;quot;local4&amp;quot; Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Of course you'll need to provide your own values for those counters, and as I've said, I really recommend assigning them to constant counters whose values you set all in one place.  It makes things much easier later, when you want to change the way things are done.  Also notice that in addition to reading the coordinates of the key based on where you put the robot, it also reads the color of the key and draws the sprite accordingly.  This means we can use exactly the same robot code for different colored keys, without changing a thing except the color of the robot itself.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now you need a &amp;quot;:touch&amp;quot; label.  In the case of a key, if you touch it you just collect the key and it disappears.  So we need a counter to keep track of the key, and we need to make the sprite disappear.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: inc &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&lt;br /&gt;
What we've done here is increment a counter that is unique to the color of the key.  This means we can collect more than one of the same color key, and open just as many doors.  The spr#_off counter is a special functional counter which turns off sprite drawing and sprite collision when it is set to something.  It does NOT set the sprite's counters to zero, though.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy that key robot and make a door robot out of it.  I'm serious, the changes you'll be making are so slight that they don't warrant starting from scratch.  Just change the values of the sprite initialization to suit, and change the behavior in the touch routine:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;touch&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: dec &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: die&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
We perform a simple check to make sure that the player collected a key that is the same color as this door.  Other than that, it's a mirror image of the key's touch routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now, copy those two robots all over the board.  You may actually want to do this with copyrobot commands, so that you only have to change the code in one place, when you need to change it.  Or, if you want to be clever, save the robot code into a [[file access|file]] and load from that.  Whatever you do, put a bunch of copies of the key and door code onto your board, using as many different colors as you like.  Now play around with it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.1|Example 2.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.2|}}&lt;br /&gt;
====Exercise 2.2: Keeping track of sprites on the board====&lt;br /&gt;
So far, the only time we've needed to have sprites talk to other sprites or refer to them by ID is when they collided, and then the numbers are provided for us.  But suppose we want to know which sprite is the player and where it is, so that we can allow another robot controlling another sprite (like an enemy) to target it?  Or what if we want to have the same sprite run around the board stealing keys (we'll actually do this in an upcoming example)?  It'll need to know where they are too.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;For the player, this is simple enough, we can just have the following line in our initialization:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playersprite&amp;quot; to &amp;quot;local&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Can't get much easier than that.  But for keys and doors, we need to be a little bit more clever, since there can be arbitrarily many of those.  Just using their color (local4) as an identifier isn't enough, since that might not be unique on the board, and besides that we'd like a solution to enumerate a list of things.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;First, in the global robot, initialize a couple of counters to keep track of the number of keys and doors on the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;num_keys&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;num_doors&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Then in the key init code (and similarly for the door code), add each key to the end of a list and advance the counter:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot; to &amp;quot;num_keys&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;num_keys&amp;quot; by 1 &amp;lt;/tt&amp;gt;&lt;br /&gt;
We also store the sprite's position in the list and attach it to the sprite, double linking them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Why bother spending overhead on this, and making this counter public?  So that we can easily prune the list when the player collects a key or opens a door.  Here's a neat trick to quickly remove an item from an array without leaving a hole:&amp;lt;tt&amp;gt;&lt;br /&gt;
: dec &amp;quot;num_keys&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;num_keys&amp;amp;')_lpos&amp;quot; to &amp;quot;spr&amp;amp;local&amp;amp;_lpos&amp;quot;&lt;br /&gt;
: set &amp;quot;keysprite('spr&amp;amp;local&amp;amp;_lpos')&amp;quot; to &amp;quot;keysprite&amp;amp;num_keys&amp;amp;&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; 1&lt;br /&gt;
: die&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
Let's pause here and explain what we've just done in more detail.  First, we create a list of sprite/robot ids (they're the same in our system, remember).   We populate this list by first setting the length of the list to zero, and adding each item to the end of the list as its robot gets executed.  We also know that these items are subject to being removed from the list of active sprites in certain game situations.  Now we can set things up such that the list will be automatically regenerated if we leave the board and come back (more on that in the next example).  But when we start using lists to keep track of lots of objects that get added to and deleted from the list a lot (e.g. bullets), we'll really appreciate having a way to perform those add and delete operations in constant time, while limiting the time to iterate over the list down to the number of currently active items.&amp;lt;br&amp;gt;&lt;br /&gt;
The key observation that makes the above trick work is that the list doesn't need to be sorted.  So all we need to do to deal with the hole left by a deleted list item is find another item to put in the hole.  And there's always an item at the end of the list, even if it's the very item we're deleting.  We tell the sprite at the end of the list that it's list position (spr#_lpos) is now the position of the item we're deleting (this is why that counter needed to be public).  And then we tell the list that the id at that position is now the id at the end of the list.  Finally we decrease the length of the list (it's safe to do this first as shown in the code because the data doesn't actually go anywhere), effectively removing the last item on the list.&lt;br /&gt;
&amp;lt;ol start=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;li&amp;gt;This exercise has largely been in preparation for things to come.  But in order to demonstrate its usefulness quickly, let's create a simple debug robot to print the status of all of our sprites on the board.&amp;lt;tt&amp;gt;&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyt&amp;quot;&lt;br /&gt;
: [ &amp;quot;The player is sprite &amp;amp;playersprite&amp;amp;, located at (('spr&amp;amp;playersprite&amp;amp;_x'), ('spr&amp;amp;playersprite&amp;amp;_y')).&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_keys&amp;quot; &amp;lt;= 0 then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: [ &amp;quot;Key sprite #&amp;amp;local&amp;amp; is located at (('spr('keysprite&amp;amp;local&amp;amp;')_x'), ('spr('keysprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_keys&amp;quot; then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: if &amp;quot;num_doors&amp;quot; &amp;lt;= 0 then &amp;quot;end&amp;quot;&lt;br /&gt;
: [ &amp;quot;Door sprite #&amp;amp;local&amp;amp; is located at (('spr('doorsprite&amp;amp;local&amp;amp;')_x'), ('spr('doorsprite&amp;amp;local&amp;amp;')_y')).&amp;quot;&lt;br /&gt;
: inc &amp;quot;local&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local&amp;quot; &amp;lt; &amp;quot;num_doors&amp;quot; then &amp;quot;doorloop&amp;quot;&lt;br /&gt;
: : &amp;quot;end&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
Just copy this into a new robot (put it somewhere other than the top row of the board) and press 'T' to access it.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
[[Sprite Code Examples#Example 2.2|Example 2.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.3|}}&lt;br /&gt;
====Exercise 2.3: Moving the player sprite between boards====&lt;br /&gt;
Almost any real game is going to involve more than one board (single board content management via [[MZM|MZMs]] aside).  However, successfully managing sprites across multiple boards requires some overhead and foresight.  Before we go any further, we need to address one of the major gotchas of sprites, which is that you have 256 of them to use in the entire GAME, not per board.  This means that, especially for a dynamic sprite system, you need a way to ensure that sprites are kept consistent and in the same places across boards.  &lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;What this generally means is that we want to have the sprite initialization happen every time you load the board, implying the use of :justentered.  But there are also parts of our sprite initialization code that we want to happen only one time, like setting the initial sprite position by using the initial robot position and then moving the robot.  Fortunately there's a simple trick for pulling this off:&amp;lt;tt&amp;gt;&lt;br /&gt;
: . &amp;quot;One time execution code goes here.&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: . &amp;quot;Static initialization code goes here (sprite ref and collision box among others).&amp;quot;&lt;br /&gt;
: . &amp;quot;Fallthrough to main program loop.&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember your robotic, a pipe is a pre-zapped label.  This should be applied to the global robot as well, for sprite list setup.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course there are things, especially for sprites that are going to move around, that must be preserved on a board change but which are subject to change.  This is the reason I suggested the use of &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; to keep track of sprite position, instead of &amp;quot;spr#_x&amp;quot; and &amp;quot;spr#_y&amp;quot;.  But the player needs a system that doesn't simply preserve its position on each board, but which accurately sets its position based on where it was on the previous board.  This means that the player sprite needs to use global counters instead of local counters.  So do a search and replace on &amp;quot;local2&amp;quot; and &amp;quot;local3&amp;quot; in the player robot (CTRL+R is your friend) for counters like &amp;quot;player_x&amp;quot; and &amp;quot;player_y&amp;quot;.  Then add this code to the one time execution segment of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;playerx&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;playery&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The reason for the locals as temps will become clear in a moment.  Now add this code to the board init section:&amp;lt;tt&amp;gt;&lt;br /&gt;
: lockscroll&lt;br /&gt;
: set &amp;quot;player_x&amp;quot; to &amp;quot;local2&amp;quot;&lt;br /&gt;
: set &amp;quot;player_y&amp;quot; to &amp;quot;local3&amp;quot;&lt;br /&gt;
: put player 0 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
Now you can us the player object itself to mark the start position of the player sprite, and be able to test from that position on any board.  We lock scrolling because of what we do with the player in the next step, to prevent the viewport from jumping around.  It no longer really matters where you put the player robot, as long as you don't put it in the top row (for safety reasons, since all the sprite robots move to that line and it might get overwritten before it moves).  Also note the use of &amp;quot;player_x&amp;quot; instead of &amp;quot;playerx&amp;quot;, since &amp;quot;playerx&amp;quot; and &amp;quot;playery&amp;quot; are built-in and read-only.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to know when the sprite moves off the board.  Fortunately bounds checking allows us to do just that.  For each movement routine, add a sprite counter that tells which direction the sprite last moved, and then route the bounds check to a label that sends the global robot a message, like so:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#up&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_lastmove&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;lt;= &amp;quot;bminy&amp;quot; then &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;edgecollide&amp;quot;&lt;br /&gt;
: send &amp;quot;global&amp;quot; to &amp;quot;edge&amp;amp;spr('local')_lastmove&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we're going to use a nice little shortcut so that we can keep track of board adjacencies with the standard MZX system instead of writing another data structure to do it.  All it requires is that the four corners of each board you use it on be empty.  That's because we're going to use the player object itself to move between boards, instead of using teleport player.  Write each edge# method similar to this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: . &amp;quot;North&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;player_x&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('bmaxy'-'spr_p_h')&amp;quot;&lt;br /&gt;
: . &amp;quot;That is, the bottom of the sprite playing field minus the height of the player sprite.&amp;quot;&lt;br /&gt;
: put player 0 0&lt;br /&gt;
: . &amp;quot;Use board_w-1 and board_h-1 to move south and east.&amp;quot;&lt;br /&gt;
: move player NORTH&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The idea here is to set temp counters to the expected location of the player sprite on the next board, then move the actual player to that board.  We don't use the actual counters so that if the move fails (there is no board in that direction), nothing happens to the sprite.  But if the move succeeds, the justentered label will be triggered and the values will be committed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Obviously for this to work right, those &amp;quot;bminy&amp;quot; and &amp;quot;bmaxy&amp;quot; counters need to actually exist.  They also need to be the same across all boards; if the boards need to have different dimensions you will need a more complex system.  But for this simple case, just add those to the one-time code of the global.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
You can use whatever values you like, of course, at this point it's more up to the requirements of your game than anything else.  You can and should replace all hard-coded values in the player bounds checking with these counters, as seen above.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final thing remains to be done, and that's to make sure all the sprites being used at the time of the board transition are turned OFF. We may have done a lot of work to make sure sprites can initialize properly each time the board loads, but if we don't destroy them before moving to another board then any sprites that don't get reinitialized will hang around.  Now it would be possible to just loop through all 256 sprites and turn them all off to be safe, but that may not always be optimal, and besides that this is a perfect application for those lists we made earlier.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playersprite&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('keysprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_keys'-1)&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr('doorsprite&amp;amp;loopcount&amp;amp;')_off&amp;quot; to 1&lt;br /&gt;
: loop for &amp;quot;('num_doors'-1)&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Stick this at the front of the global board init, and it'll be the first thing executed when a board loads.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That's really all that needs to be done at this point.  Test it out by creating a few interlinked boards and spread your doors and keys across them.  You'll need to copy the sprite source data between the boards too.  (Writing an [[MZM#MZM Tutorial|MZM loader]] for this into the global robot is left as an exercise to the reader.  I actually recommend using the vlayer to store them though, and we'll do this in the next step, so brush up on the [[vlayer#VLayer Tutorial|vlayer tutorial]] for more info.)&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.3|Example 2.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E2.4}}&lt;br /&gt;
====Exercise 2.4: Finishing touches, fixing the scrolling====&lt;br /&gt;
Before we wrap up this section for good, there's a bit of cleanup work we need to do.  Most pressing, and something you will have noticed by now unless your boards are all the same size as the bounding area for your sprite playing field, is that the simple directions I gave you for scrolling the viewport don't work right, or not the way you'd really want them to. If your sprite images are still on the board, you probably want them to not be visible; you'd like the &amp;quot;board&amp;quot; that the player sprite moves on to stop before you get to things that are off the screen.  There are really only two ways to handle this: either put nothing on the board that is not intended to be seen (i.e. use the vlayer and some other tricks), or use complicated math to clamp the viewport to the edges of the playing area, to prevent the player from seeing things that are not intended to be seen.&lt;br /&gt;
&lt;br /&gt;
I wrestled with how to present this material for close to a year, since there are just so many problems with it.  One problem is that it's mostly just necessary busywork, tying off loose ends so that the engine functions more smoothly; it doesn't really fit in with the flow of the tutorial, but it really needs to be done now before we proceed to the next major section.  Another problem is that doing things in an easily pluggable way that only involves adding a few lines in key places requires some very complex [[expressions|expression hacking]] that just isn't appropriate to teach in a tutorial about sprites; while doing it in a way that is easy to understand requires more additions and modifications than I'd really like.  So ultimately I've decided to give you as many options as possible.  If you want to skip as much of this nonsense as possible and get right on to the sprite-layer model, just follow step 1 to get your sprites on the vlayer, and step 1a to deal with the details of only doing that.  If you want to go the whole nine yards, the rest of the steps will show you, in order of necessity, how to tweak the engine to handle scrolling inside of a bounded area.  You can stop following them whenever you're satisfied with the results.  And if you're interested in my preferred method for doing this, the last step will show you the expressions for compressing 50 lines of code into 5.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, one thing that absolutely must happen before we move on to sprite layers is that we start using the vlayer for sprites.  If nothing else, we don't want to have to set aside broad swaths of space on each board for sprites that are as large as the playing area itself.  So, export your sprite image data to something like &amp;quot;sprites.mzm&amp;quot;, and add the following line to the one-time code of the global robot:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@sprites.mzm&amp;quot; Image_file p02 at 0 0&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You'll also need to adjust all the coordinate constants for the sprites appropriately, by subtracting 80 from the refx coordinates.  So for example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_p_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_d_x&amp;quot; to 3&lt;br /&gt;
: set &amp;quot;spr_k_x&amp;quot; to 6&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, all sprite robots need a line in their board init to reference them from the vlayer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;ol type=&amp;quot;a&amp;quot;&amp;gt;&amp;lt;li&amp;gt;If this is the only step you want to take, there are a few more small things to do.  First, make sure the board size, and the dimensions specified by bminx, bmaxx, bminy, and bmaxy, are the same.  The easiest way to do this is to set them in the global robot directly based on the board settings:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;bminx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bminy&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;bmaxx&amp;quot; to &amp;quot;board_w&amp;quot;&lt;br /&gt;
: set &amp;quot;bmaxy&amp;quot; to &amp;quot;board_h&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You will then need to draw overlay artwork on the areas of the board where the robots will reside (i.e. the top row) and in the top-left and bottom-right corners where the player can be.  Finally, to accomodate this, all sprites that might move into these areas (notably the player) need to have this line added to their setup:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_overlaid&amp;quot; to 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
This will ensure that the sprites appear over the overlay you've drawn, with the drawback that you won't be able to draw overlay to appear above them.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need to correct the scrolling.  The easiest way to conceptualize this is to create a subroutine for each boundary that resets the viewport to line up with that edge, and then to call those subroutines each time the current scrolling code causes the viewport to cross any boundary.  The subroutines will all go at the end the player robot, and will be called conditionally inside of the &amp;quot;#draw&amp;quot; subroutine, right after the &amp;lt;tt&amp;gt;spr#_setview&amp;lt;/tt&amp;gt; line.  So for example, the left edge works like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;lt; &amp;quot;bminx&amp;quot; then &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixleft&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;bminx&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The right edge requires a little bit more, since we need to take the width of the viewport into account:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;scrolledx&amp;quot; &amp;gt; &amp;quot;('bmaxx'-'vw')&amp;quot; then &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#fixright&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;('bmaxx'-'vw')&amp;quot; &amp;quot;scrolledy&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The other two edges are basically the same, with different counters in the appropriate places.  Of course, the counter vw, and its brother vh (for viewport width and viewport height) need to exist.  MZX doesn't have built-in counters to read these values, so we need to set them ourselves, in the global robot one-time code:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;vw&amp;quot; to 80&lt;br /&gt;
: set &amp;quot;vh&amp;quot; to 25&amp;lt;/tt&amp;gt;&lt;br /&gt;
This allows them to be easily changed later, in case we decide we want the viewport to be smaller than the full screen.  As a final step, so that the player and robots don't have to be covered up with overlay, we want to make sure the playing area for the sprites has at least a character of margin around it, for the player and robots to live in and move around.  This means that bminx and bminy should both be changed to 1, at least, and bmaxx and bmaxy should both be at least one less than the width and height of the board.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;There will be a minor problem with a visible scroll snap when you move from board to board.  This is because the board draws before any of the robots on it run, so the scroll correction code in the player robot will only take effect after the board has been drawn once.  To fix this, we'll put some corrective code into the only robot that runs before the screen is drawn: the global robot.  The basic idea here is that, similar to how we move the player to the opposite side of the playing field every time we change boards, we'll do the same with the viewport.  We'll use &amp;quot;local4&amp;quot; and &amp;quot;local5&amp;quot; as carry-over counters for this purpose.  First, in the board init, right after the lockscroll command:&amp;lt;tt&amp;gt;&lt;br /&gt;
: scrollview position &amp;quot;local4&amp;quot; &amp;quot;local5&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, for each of the :edge# routines, we set these counters, similarly to the way the clamping routines worked in the last step.  So for moving north, we want the screen to end up on the bottom edge:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;edge0&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('bmaxy'-'vh')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Similar additions apply to the other routines.  Finally, we want local4 and local5 to have values on the first board.  We could perform the same complicated scroll correction routine the player robot uses to make sure the viewport is inside the playing area, but that's really a waste of code for something that's only ever going to be used once at the very beginning of the game.  So we'll just set them in the one-time code based on the initial scroll location:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to &amp;quot;scrolledx&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;scrolledy&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The put player command is an interesting one, since it consumes a cycle only if it actually causes the player to move.  But this does mean that there will be an extra cycle of delay whenever we move south or east, since then the player DOES have to move to the opposite end of the board.  This isn't that important, but as long as we're cleaning up loose ends, we might as well handle this.  Similar to the scroll correction we did before, we will set up subroutines to move the real player object to the correct edge of the board, based on the location of the player sprite, and then call them conditionally in a loop.  This way, the player will always be at the correct location in advance.  So, after the global board setup, instead of just ending the program, create a loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playerloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;playerloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then create the subroutines and if calls.  To check if the player is on the left side of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_x&amp;quot; &amp;lt; &amp;quot;('bminx'+'bmaxx'/2)&amp;quot; then &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerleft&amp;quot;&lt;br /&gt;
: put player at 0 &amp;quot;playery&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Or for the bottom of the board:&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;player_y&amp;quot; &amp;gt; &amp;quot;('bminy'+'bmaxy'/2)&amp;quot; then &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#playerdown&amp;quot;&lt;br /&gt;
: put player at &amp;quot;playerx&amp;quot; &amp;quot;('board_h'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expression used in the comparison is a simple midpoint calculation for the board playing area.  All you have to do now is remove the put player commands from the edge handlers, since the player will already be in the right place to move when they're called.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The subroutine system is pretty easy to understand and works just fine, but I personally don't like to use it when I don't have to, just to save on commands.  Instead, when I have a situation that involves setting one value to a choice of two or three values depending on some condition, I like to cram all the logic into an expression that will execute in one command.  This is purely a preference on my part, it doesn't make the code that much more efficient and it certainly doesn't make it more readable.  But it does make it shorter.  So in the case of scroll correction, this is what I do:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;(('scrolledx'&amp;lt;'bminx'*('bminx'-'scrolledx'))+('scrolledx'+'vw'&amp;gt;'bmaxx'*('bmaxx'-'vw'-'scrolledx'))+'scrolledx')&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;(('scrolledy'&amp;lt;'bminy'*('bminy'-'scrolledy'))+('scrolledy'+'vh'&amp;gt;'bmaxy'*('bmaxy'-'vh'-'scrolledy'))+'scrolledy')&amp;quot;&lt;br /&gt;
: scrollview position &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns what was 16 lines into three; it would be one, but the expressions are so complicated that they won't fit side by side in one line.  The first two lines there can also be applied at the beginning of the global robot to local4 and local5, instead of simply &amp;quot;scrolledx&amp;quot; and &amp;quot;scrolledy&amp;quot;, to more accurately set the initial location of the viewport.&amp;lt;br&amp;gt;&lt;br /&gt;
Then, for moving the player around, I use this construct:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put player at &amp;quot;('bminx'+'bmaxx'/2&amp;lt;'player_x'*('board_w'-1))&amp;quot; &amp;quot;('bminy'+'bmaxy'/2&amp;lt;'player_y'*('board_h'-1))&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This turns those 16 lines into a single line, without the need for any intermediate steps.&lt;br /&gt;
&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This concludes the section on sprites as objects.  It got a little sidetracked at the end, but this is all necessary maintenance work if you want to use sprites as objects in a full-fledged game.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 2.4|Example 2.4 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|S3}}&lt;br /&gt;
===The Sprite-Layer Model: Working With Layers===&lt;br /&gt;
Understanding sprites as layers is not really that complex a concept to grasp.  The basic idea dates back to MZX feature requests for having multiple overlays or underlays in the game, so that you could use different layers to handle different tasks.  The feature was rejected as is, but sprites can fill this role just fine.  Up till now we've thought of sprites as relatively small objects linked to specific actors in the game.  Now, we'll be using sprites as very large objects that can cover the whole screen or even the whole board.  Instead of placing a small sprite at a location on the board to change what the player sees, we will paint image data onto a large sprite to accomplish the same thing.&lt;br /&gt;
&lt;br /&gt;
There are a few useful status commands for working with layer-like sprites&lt;br /&gt;
 set &amp;quot;spr#_vlayer&amp;quot; to 1    ''Sets the sprite to get its image data from the vlayer instead of the board.''&lt;br /&gt;
 set &amp;quot;spr#_overlaid&amp;quot; to 1  ''Makes the sprite appear over the overlay. Ideal if using the overlay in a traditional way.''&lt;br /&gt;
 set &amp;quot;spr#_static&amp;quot; to 1    ''Makes the sprite display relative to the viewport, rather than the board, like a static overlay.''&lt;br /&gt;
Using the vlayer is especially important for layer sprites.  At this point it becomes completely impractical to set aside as much empty space on every board in the game as is necessary to accomodate all of the graphical data used by them.  Painting the sprite on top of the overlay can also be useful if you are using the overlay to draw static things on top of the normal game action, like trees or houses, but you want something special to appear above everything, like a status bar or a message box.  And very often, it is worth combining this with the static command, so that you don't have to figure out where to redraw the sprite every time the screen moves.&lt;br /&gt;
&lt;br /&gt;
There are also a few important things to consider when working with large sprites, and when combining them with the gameplay engine we're building.  The first is that character 32, the space, is not drawn in a sprite, just like it isn't drawn on the overlay.  This is pretty essential if you're going to have a sprite that covers the whole screen, space-wise, and still want to see what's beneath it.  Another is that sprites have an absolute maximum width and height of 255.  If you try to make a sprite larger than that, the practical dimensions will just wrap back around to 0, modulo 256.  Because we're using layer sprites as a window into the vlayer, we never actually NEED a sprite to be larger than 80x25 characters, and there are plenty of ways to work with them to stay inside this constraint.  But since it's often easier, for a layer that covers the entire board, to just place the layer on the board, we'll assume for the purposes of this tutorial that you won't be using a board or sprites larger than 255 in either dimension.&lt;br /&gt;
&lt;br /&gt;
Finally, one important catch that comes up when we try to use a layer sprite in conjunction with a system that uses spr_yorder to draw game objects correctly, is how to get the layer to appear on top of all the other sprites in the game, or to change its order relative to other layers.  After all, a sprite drawn over the whole screen is going to have a y-coordinate lower than any sprite object in the game, right?  Fortunately for us, spr_yorder doesn't calculate its draw order based on spr#_y values, but on spr#_cy values.  Since we almost never want sprites that are suppose to appear above all game objects to collide with those game objects, this means that we can co-opt this counter as a view order marker.  Setting it to extreme negative values will make it appear below every other sprite in the game.  Setting it to extreme positive ones will make it appear above everything.  It may require some tweaking to get working exactly right when combined with other layers, since the values are still taken as offsets from the sprite's position on the board, but it's a serviceable workaround.&lt;br /&gt;
&lt;br /&gt;
{{a|E3.1}}&lt;br /&gt;
====Exercise 3.1: Creating a status bar====&lt;br /&gt;
For our first foray into layer sprites, let's do something fairly simple to create, but that epitomizes the most basic purpose of layers: a status bar.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;Before anything else, we need to draw the base template for the status bar.  This can be done mostly however you like, but it should at least have locations to draw health, ammo, and collected keys, and the locations and sizes of the places for drawing to these areas should be recorded as constants in the global robot.  Here are the constants and sizes I'll be using:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;lyr_s_x&amp;quot; to 0   ''meaning layer-statusbar-refx''&lt;br /&gt;
: set &amp;quot;lyr_s_y&amp;quot; to 3   ''layer-statusbar-refy''&lt;br /&gt;
: set &amp;quot;lyr_s_w&amp;quot; to 50  ''layer-statusbar-width''&lt;br /&gt;
: set &amp;quot;lyr_s_h&amp;quot; to 2   ''layer-statusbar-height''&lt;br /&gt;
: set &amp;quot;lyr_sh_x&amp;quot; to 10 ''layer-statusbar-health-refx''&lt;br /&gt;
: set &amp;quot;lyr_sh_y&amp;quot; to 3  ''layer-statusbar-health-refy''&lt;br /&gt;
: set &amp;quot;lyr_sh_w&amp;quot; to 25 ''layer-statusbar-health-width''&lt;br /&gt;
: set &amp;quot;lyr_sh_h&amp;quot; to 1  ''layer-statusbar-health-height''&lt;br /&gt;
: set &amp;quot;lyr_sa_x&amp;quot; to 43 ''layer-statusbar-ammo-refx''&lt;br /&gt;
: set &amp;quot;lyr_sa_y&amp;quot; to 3  ''layer-statusbar-ammo-refy''&lt;br /&gt;
: set &amp;quot;lyr_sa_w&amp;quot; to 5  ''layer-statusbar-ammo-width''&lt;br /&gt;
: set &amp;quot;lyr_sa_h&amp;quot; to 1  ''layer-statusbar-ammo-height''&lt;br /&gt;
: set &amp;quot;lyr_sk_x&amp;quot; to 8  ''layer-statusbar-keys-refx''&lt;br /&gt;
: set &amp;quot;lyr_sk_y&amp;quot; to 4  ''layer-statusbar-keys-refy''&lt;br /&gt;
: set &amp;quot;lyr_sk_w&amp;quot; to 40 ''layer-statusbar-keys-width''&lt;br /&gt;
: set &amp;quot;lyr_sk_h&amp;quot; to 1  ''layer-statusbar-keys-height''&amp;lt;/tt&amp;gt;&lt;br /&gt;
The final result should look something like this, 50 characters wide, 2 high, with room for labels and a 2 character margin on each side:&lt;br /&gt;
&amp;lt;pre style=&amp;quot;display:table&amp;quot;&amp;gt;| Health: =========================  Ammo: 00000 |&lt;br /&gt;
| Keys: ________________________________________ |&amp;lt;/pre&amp;gt;&lt;br /&gt;
Save it as a new MZM, statusbar.mzm, and then have the global robot load it along with sprites.mzm:&amp;lt;tt&amp;gt;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now we need a robot to handle drawing our layer.  This starts out in the same basic way as all sprite robots have so far:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;('vw'-'lyr_s_w'/2)&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: . &amp;quot;These are the initial x/y coordinates for the sprite, though they'll change later.&amp;quot;&lt;br /&gt;
: . &amp;quot;The expression for the x coordinate is a midpoint formula that places the sprite in the center of the viewport&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&lt;br /&gt;
: set &amp;quot;statusbar&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_static&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_s_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_s_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_s_h&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to 500&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to 0&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
All of the principles used here, including the new ones like spr&amp;amp;local&amp;amp;_static and using spr&amp;amp;local&amp;amp;_cy to fix the display order, should already be familiar to you if you've been following the tutorial.  We set the other collision counters to 0 in order to make sure they're off; remember, this sprite number could have belonged to something else on another board.  By the same token, don't forget to add a line to turn off the statusbar sprite on board transitions, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That got the sprite drawing, but now we need it to display something meaningful, instead of just looking pretty.  First, let's set up a main program loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: put &amp;quot;@statusbar.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_s_x&amp;quot; &amp;quot;lyr_s_y&amp;quot;&lt;br /&gt;
: . &amp;quot;The easiest way to redraw the status bar is to reload the base image from the MZM.&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: goto &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: goto &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then we need to flesh out each of those subroutines.  Health is the easiest to do: we need a bar of filled health as long as the space in the status bar, so draw a line of red 25 characters long next to the other sprites, and re-export sprites.mzm.  Make sure to add constants for this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_sh_x&amp;quot; to 8  ''meaning sprite-statusbar-health-refx, for the sprite image to copy onto the layer''&lt;br /&gt;
: set &amp;quot;spr_sh_y&amp;quot; to 0  ''sprite-statusbar-health-refy''&amp;lt;/tt&amp;gt;&lt;br /&gt;
To draw the health, we'll simply copy a portion of this bar based on the value of 'health' and 'maxhealth' (you'll have to set maxhealth to something yourself).  This leads to:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dohealth&amp;quot;&lt;br /&gt;
: copy block &amp;quot;#&amp;amp;spr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_sh_y&amp;amp;&amp;quot; for &amp;quot;('health'*'lyr_sh_w'/'maxhealth')&amp;quot; &amp;quot;lyr_sh_h&amp;quot; to &amp;quot;#&amp;amp;lyr_sh_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_sh_y&amp;amp;&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now for the ammo.  The easiest way to read this out of a counter and onto the vlayer is to convert the counter into a string.  MZX will do this for you without having to write a conversion routine.  We would like to write that string directly to the vlayer, but unfortunately MZX doesn't support that operation in a convenient way right now (though it may in the future).  We could write it to some off-screen space on the overlay and then copy it, but depending on how you set up the board scrolling in the last section, you may not have any off-screen space.  So we'll just have to loop through the string.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#doammo&amp;quot;&lt;br /&gt;
: set &amp;quot;$ammo&amp;quot; to &amp;quot;&amp;amp;ammo&amp;amp;&amp;quot;&lt;br /&gt;
: . &amp;quot;Ampersands are required, so that we don't just draw 'ammo' on the screen.&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;vch('lyr_sa_x'+'loopcount'),('lyr_sa_y')&amp;quot; to &amp;quot;$ammo.&amp;amp;loopcount&amp;amp;&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('$ammo.length'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we don't do any checking for the length of the ammo string.  We could do this, but it would involve adding some complex expressions that are outside of this tutorial's scope, and is left as an exercise to the reader.  Instead, simply take care not to let the player's ammo exceed 99999.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Finally, the keys.  Remember that the information for these is not stored in the built-in MZX key handling, but in counters we defined ourselves, 'key_#' for each color.  To draw the keys, we'll loop through these counters and test whether they're set or not.  This is a fairly complicated routine, and involves keeping track of the key color and the current draw location, and aborting the loop before we draw too many keys to fit on the status bar.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#dokeys&amp;quot;&lt;br /&gt;
: set &amp;quot;local4&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: if &amp;quot;key_&amp;amp;local4&amp;amp;&amp;quot; &amp;lt;= 0 then &amp;quot;keynext&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: if &amp;quot;local5&amp;quot; &amp;gt;= &amp;quot;lyr_sk_w&amp;quot; then &amp;quot;#return&amp;quot;&lt;br /&gt;
: set &amp;quot;vch('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to 12&lt;br /&gt;
: set &amp;quot;vco('lyr_sk_x'+'local5'),('lyr_sk_y')&amp;quot; to &amp;quot;local4&amp;quot;&lt;br /&gt;
: inc &amp;quot;local5&amp;quot; by 1&lt;br /&gt;
: loop for &amp;quot;('key_&amp;amp;local4&amp;amp;'-1)&amp;quot;&lt;br /&gt;
: : &amp;quot;keynext&amp;quot;&lt;br /&gt;
: inc &amp;quot;local4&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local4&amp;quot; &amp;lt; 256 then &amp;quot;keyloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that 12 is the character of the key graphic; this could easily be changed.  Also understand that this is a fairly inefficient routine, and will take around 1000 commands to execute.  We could create some data structures to greatly improve on this time, but that would involve maintenance and a lot of extra effort.  Instead, this is the time to go ahead and set the 'commands' counter to something reasonably high, in the global robot.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Two last things before we're done: the status bar necessarily covers up parts of the playing area that we might like to see.  There are two things we can do to help with this.  One is to move the status bar to the opposite side of the screen if the player gets too close to it.  The other is to allow the player to toggle the display on and off.  Neither of these is that hard to do, so we'll take them both in order.  To move the sprite, create a #draw subroutine in the main loop:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to 0&lt;br /&gt;
: if &amp;quot;('spr&amp;amp;playersprite&amp;amp;_y'-'scrolledy')&amp;quot; &amp;gt;= &amp;quot;('vh'-'spr_p_h'/2)&amp;quot; then &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: set &amp;quot;local3&amp;quot; to &amp;quot;('vh'-'lyr_s_h')&amp;quot;&lt;br /&gt;
: : &amp;quot;drawnext&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; at &amp;quot;local2&amp;quot; &amp;quot;local3&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Basically, as long as the player remains in the lower half of the screen, the status bar will be on top.  If the player moves into the top of the screen, the status bar will move to the bottom.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;To turn the status bar on and off, we'll simply use a classic zap/restore toggle with the :keyenter label.  This is very basic stuff that should be familiar to most people already. We'll have the sprite start in the off state each time the board initializes.  So instead of placing the sprite and going to the draw loop, do this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 255&lt;br /&gt;
: goto &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: zap &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_off&amp;quot; to 1&lt;br /&gt;
: end&lt;br /&gt;
: : &amp;quot;keyenter&amp;quot;&lt;br /&gt;
: restore &amp;quot;keyenter&amp;quot; 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Since the status bar is now replacing the default enter menu, make sure to have the global robot turn that off by setting 'enter_menu' to 0.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
That does it for our status bar.  You'll want to add in some test code and make use of the counter debugger to see that the various elements are reporting their numbers correctly, but you can take this robot and drop it on every screen on which you want to have a status bar.&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.1|Example 3.1 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.2}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.2: Bullets as a layer (framework)====&lt;br /&gt;
Our next exercise is the most complicated individual piece of the engine yet: adding bullets and shooting to the game.  There's no easy way to break it into pieces, but it'll really take at least two exercises to fully explain.  So I'll do the best I can and break it into a framework phase, where we'll construct the basic skeleton for the code and explain what each part is going to do, and an implementation phase, where we'll implement each of the main subroutines and explain how they work.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;First things first, we need our basic sprite handler robot preamble.  You've written this thing several times already, but let's go over it again.  We need a one-time execution section that sets a counter based on the robot id, renames the robot based on it, and moves the robot to the robot bank (this part is not strictly necessary but we'll do it anyway):&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local&amp;quot; to &amp;quot;robot_id&amp;quot;&lt;br /&gt;
: . &amp;quot;@spr&amp;amp;local&amp;amp;&amp;quot;&lt;br /&gt;
: gotoxy &amp;quot;local&amp;quot; 0&amp;lt;/tt&amp;gt;&lt;br /&gt;
We need a separator to prevent this code from happening more than once, and have the code after it happen every time the board loads:&amp;lt;tt&amp;gt;&lt;br /&gt;
: restore &amp;quot;justentered&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
: | &amp;quot;justentered&amp;quot;&lt;br /&gt;
And we need some basic sprite initialization and placement:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;playerbullets&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_vlayer&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refx&amp;quot; to &amp;quot;lyr_pb_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_refy&amp;quot; to &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_width&amp;quot; to &amp;quot;lyr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_height&amp;quot; to &amp;quot;lyr_pb_h&amp;quot;&lt;br /&gt;
: put c?? Sprite &amp;quot;local&amp;quot; &amp;quot;bminx&amp;quot; &amp;quot;bminy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We'll get to collision in a little bit, since it's going to be done a little bit differently than normal.  For now, we want to set up for a layer sprite that's going to fit snugly on top of the board's playing area.  And of course we make sure to create a reference counter for the sprite (playerbullets).&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Of course we're going to need to set up the global robot to manage some of these counters, which are going to correspond to areas on the vlayer.  One thing we're going to need is an actual image for the player's bullets, separate from the layer the bullets get drawn on.  So add that to sprites.mzm and note its location, and then add some counters to global:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr_pb_x&amp;quot; to 9&lt;br /&gt;
: set &amp;quot;spr_pb_y&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;spr_pb_w&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;spr_pb_h&amp;quot; to 1&lt;br /&gt;
: set &amp;quot;lyr_pb_x&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;lyr_pb_y&amp;quot; to 5&lt;br /&gt;
: set &amp;quot;lyr_pb_w&amp;quot; to &amp;quot;('bmaxx'-'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;('bmaxy'-'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Another important thing we're going to need is a blank MZM the size of the layer, to use as a way to clear all of the bullets and redraw them.  You could go to the trouble of exporting this by hand, or you could do it the smart way and just have the global robot make it for you.  The vlayer consists of empty space by default, so we can just export an appropriately sized piece of it to make a blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;lyr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;lyr_pb_y&amp;amp;&amp;quot; for &amp;quot;lyr_pb_w&amp;quot; &amp;quot;lyr_pb_h&amp;quot; to &amp;quot;@blank.mzm&amp;quot; 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, we want to make sure the bullet sprite gets turned off between boards, so that its number can be properly reassigned if it changes.  Remember where the global robot section that performs this task is?&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;playerbullets&amp;amp;_off&amp;quot; to 1&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Now that we've got that out of the way, we need to figure out how bullets are going to work.  The idea is to have them all drawn on a layer that fits over the board, and to keep track of important stats for each bullet in an array.  For now these are basically position and velocity, where velocity will be effectively limited to moving in one of the four cardinal directions.  Our engine will work in a loop that will:&lt;br /&gt;
# Add any new bullets to the layer&lt;br /&gt;
# Move all of the bullets on the layer&lt;br /&gt;
# Check for bullet collisions with other sprites or walls&lt;br /&gt;
# Remove all bullets that have collided or moved off the screen&lt;br /&gt;
# Redraw the layer&lt;br /&gt;
As we've discussed before, the easiest way to tackle something like this is to break it down into component tasks.  So we'll make a loop that executes a bunch of subroutines in order:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: goto &amp;quot;#add&amp;quot;&lt;br /&gt;
: goto &amp;quot;#move&amp;quot;&lt;br /&gt;
: goto &amp;quot;#check&amp;quot;&lt;br /&gt;
: goto &amp;quot;#remove&amp;quot;&lt;br /&gt;
: goto &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This loop will change somewhat when we actually implement these routines, but this is the basic idea.  Go ahead and add the label stubs for the subroutines, too.  For example:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: . &amp;quot;TODO&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step: we're going to need to maintain a list of bullets on the layer, and we're going to need an interface to add to and remove from that list.  The easiest way to do this is to have a list of bullets to add and another list of bullets to remove, which are processed by each subroutine.  The player robot will add bullets to the add list when the player fires, and the bullet robot itself will add them to the remove list when they collide with something or move off the board.  The implementation is a little complicated and we'll discuss it in the next exercise, but for now, we should make sure the length of each list is set to 0 each time the board loads, so that we can start fresh.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;quot; to 0&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
This is all the set up we really need to do.  Running the code at this point won't do a single thing, but the framework is now in place for implementation.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.2|Example 3.2 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.3}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.3: Bullets as a layer (implementation)====&lt;br /&gt;
Now we come to the meat of the engine.  We can't really build this incrementally, but we can take each part individually since we've divided it up into distinct subroutines.  So that's just what we'll do.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt; First, the #add routine.  We're going to add a flag to a list (pbullets_add) each time the player fires a bullet, and then this routine will process that list every cycle, adding a set of bullet parameters based on the flag.  The flag we're going to use is the ID of the sprite that fired it (i.e. the player), and you might ask why we would even bother with a list at all and not just have a &amp;quot;bulletfired&amp;quot; flag that the player engine sets when it wants to shoot, or even a subroutine of its own to send.  The reason is because I prefer to generalize engines whenever possible; this engine in particular will be easy to use to handle multiple bullets from multiple enemies simultaneously with no problem at all.  Regardless, at this point we're not really concerned with how bullets get added to the add list, just with processing that list.  The list is of the form &amp;lt;tt&amp;gt;pbullets_add#&amp;lt;/tt&amp;gt; and has a length of &amp;lt;tt&amp;gt;pbullets_add&amp;lt;/tt&amp;gt;, and all of these values will be correct at the beginning of the routine.  So our subroutine is primarily a loop that processes this list:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#add&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_add'-1)&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;quot; to 0&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Notice that we clear the add list once we're done, to prevent from processing the same stuff again next cycle.  New bullets will get added on top of the old.&amp;lt;br&amp;gt;&lt;br /&gt;
Now, each value in the list is a sprite ID (all the same ID in fact, but this will be a general case for later).  This means we have access to a host of information about a particular sprite, thanks to the object-oriented approach we've been following before with counter names, and the default sprite counters in general.  Notably, we have access to a set of coordinates and dimensions for the sprite (to help us decide where to put the bullet), and in the case of the player access to the last direction it moved (to help us decide which way the bullet should be firing).  We'll capture this reference out of the list into a temporary local counter, for easier access:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_add&amp;amp;loopcount&amp;amp;&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
We also have a list of bullets containing various stats, which is referenced using the form &amp;lt;tt&amp;gt;pbullets#_stat&amp;lt;/tt&amp;gt;, and is &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; in length.  With zero indexing, this means we can add on to the end of the list by using &amp;lt;tt&amp;gt;pbullets&amp;lt;/tt&amp;gt; as an index.  Or more to the point:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_width'/2 + 'spr&amp;amp;local2&amp;amp;_x' - 'bminx')&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot; to &amp;quot;('spr&amp;amp;local2&amp;amp;_height'/2 + 'spr&amp;amp;local2&amp;amp;_y' - 'bminy')&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The expressions are a bit scary, but the basic idea is to put the bullet at the x/y coordinate of the player sprite, plus an offset to put it into the center of the sprite (half of the dimensions), and minus the offset for the location of the playing area relative to the actual board.  The reason for the last part is so that the bullets' x/y coordinates treat the 0,0 as the top-left of the playing area, since that's how the bullet sprite is placed.  The velocities are trickier: we want to translate a direction code (0 = north, 1 = south, 2 = west, 3 = east) into an x and y velocity component (we'll stick with -1, 0, and 1 for now, no need to get too fancy).  Remember that the counter for this is &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt;.  So the easiest way to do this is with a case structure, as follows:&amp;lt;tt&amp;gt;&lt;br /&gt;
: goto &amp;quot;#add('spr&amp;amp;local2&amp;amp;_lastmove')&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: : &amp;quot;#add0&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot; to 0&lt;br /&gt;
: set &amp;quot;pbullest&amp;amp;pbullets&amp;amp;_vy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Make sure to add four corresponding subroutines to the end of the program, out of the way of other code execution.  For your edification, I've left my two-line expression solution to this in the example code.&amp;lt;br&amp;gt;&lt;br /&gt;
Finally, we need to make sure the length of the bullet list is updated.&amp;lt;tt&amp;gt;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;quot; by 1&amp;lt;/tt&amp;gt;&lt;br /&gt;
And we're done with this subroutine.  The game can now process a list of bullets and add them to our list.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Next, the move routine.  Moving is fairly simple in concept, except for one catch that we'll get to momentarily.  The gist is to process each bullet in the bullet list and add its velocity to its current location.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#move&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vx&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot; by &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_vy&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
The catch is that bullets can move all the way off the playing field, in which case they need to be removed, or they'll end up being drawn on parts of the vlayer we'd like not to draw on.  We could handle this check in the #check routine along with collision, but it's still going to need handling, so we'll just do it here, next to the stuff it relates to.&amp;lt;tt&amp;gt;&lt;br /&gt;
: if &amp;quot;(('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;gt;=0)a('pbullets&amp;amp;loopcount&amp;amp;_x'&amp;lt;'lyr_pb_w')a('pbullets&amp;amp;loopcount&amp;amp;_y'&amp;lt;'lyr_pb_h'))&amp;quot; = 1 then &amp;quot;movenext&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;movenext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This block goes right before the end of the loop, after the bullet location counters have been updated.  The expression looks long and scary but this is actually an expression usage worth learning, since all it is is a bunch of conditional statements joined together with the AND operator.  Basically, if the bullet is still inside the defined playing area, the commands to remove it are skipped.  Removal is going to work much the same way adding does, with a list of bullets to remove.  Except in this case, the list contains indexes into the main bullet list.  In any case, that's all for the movement routine.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;If it seems that all we've been doing so far is a bunch of abstract bookkeeping on numbers, the #check routine actually gets us back into the realm of sprites.  Here, we'll use the collision functionality provided by sprites to check each bullet and get a collision list for message sending with a minimum of fuss.  That means that the collision values need to be set for the layer first, for each bullet:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#check&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cx&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to &amp;quot;pbullets&amp;amp;loopcount&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cwidth&amp;quot; to &amp;quot;spr_pb_w&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cheight&amp;quot; to &amp;quot;spr_pb_h&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This makes sure that we're dealing with a collision rectangle for each bullet on the layer, and can process them in turn.  Then, the actual collision is triggered:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_clist&amp;quot; to 1&lt;br /&gt;
: if &amp;quot;spr_collisions&amp;quot; &amp;lt;= 0 then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: set &amp;quot;pbullets_remove&amp;amp;pbullets_remove&amp;amp;&amp;quot; to &amp;quot;loopcount&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_remove&amp;quot; by 1&lt;br /&gt;
: : &amp;quot;checknext&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Here, I've decided to do things inline and short-circuit to the end of the loop, since I plan to use that label for something else in a moment.  Collision could also be done with a subroutine, of course, this is just how it happened to fall out when I originally wrote the engine.  Notice also that we're using the same removal method as before.&amp;lt;br&amp;gt;&lt;br /&gt;
We would be done with this here, except that we also need to do something about the sprite or sprites the bullet is colliding with.  This is just our basic collision handler loop, stuck in the middle:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to 0&lt;br /&gt;
: : &amp;quot;collide&amp;quot;&lt;br /&gt;
: if &amp;quot;spr_clist&amp;amp;local2&amp;amp;&amp;quot; = &amp;quot;playersprite&amp;quot; then &amp;quot;checknext&amp;quot;&lt;br /&gt;
: send &amp;quot;spr('spr_clist&amp;amp;local2&amp;amp;')&amp;quot; to &amp;quot;playershot&amp;quot;&lt;br /&gt;
: inc &amp;quot;local2&amp;quot; by 1&lt;br /&gt;
: if &amp;quot;local2&amp;quot; &amp;lt; &amp;quot;spr_collisions&amp;quot; then &amp;quot;collide&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Unfortunately we can't use a default loop structure since we're already in the middle of one, so we continue using local2 as a temp counter.  Notice in particular the breakout condition for when the bullet is colliding with the player.  This is done specifically to deal with the fact that each player bullet starts its life ''inside'' of the player, according to our #add routine.  We could do this differently, but this is an easy hack to get around that and prevent removing the bullet prematurely.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;The #remove routine functions on a list of references to bullets to remove, as we've already seen.  This is to avoid the perils of deleting items from the bullet list in place, while we're iterating through it.  I have actually thought of an interesting way to do just that without negative side effects, but I'm not sure enough of it yet to use it in this tutorial, so I'm sticking with something I know will work.  In any case, removing a bullet from the bullet list will work much the same way as removing a key from the list of key sprites: we grab the bullet from the end of the list and put it into the location of the bullet to be removed.  In order to do this without risking serious malfunction though, we need to process the bullet list backwards.  That is, we need to remove bullets starting from the same end of the list that we're replacing them from, or we'll risk having a reference to a bullet that is no longer the same, or does not even exist, by the time we've gotten to the end.  Since replacing from the front is prohibitively complicated and costly to do, the easiest solution is to process the remove list backwards, since it's already sorted in ascending order.&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#remove&amp;quot;&lt;br /&gt;
: loop start&lt;br /&gt;
: dec &amp;quot;pbullets&amp;quot; by 1&lt;br /&gt;
: set &amp;quot;local2&amp;quot; to &amp;quot;pbullets_remove('pbullets_remove'-'loopcount'-1)&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: loop for &amp;quot;('pbullets_remove'-1)&amp;quot;&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
If you remember how we did the keys, we decrease the size of the list at the beginning so that we can have an easy reference to the end of the list, instead of the end of the list plus one.  The numbers don't actually go anywhere, so it doesn't matter if we decrease the length at the beginning or the end of the removal.  And as you can see, local2 is set to count backwards through the values in the remove list, which are indexes into the main bullet list.&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_x&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_x&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_y&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_y&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vx&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vx&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets&amp;amp;local2&amp;amp;_vy&amp;quot; to &amp;quot;pbullets&amp;amp;pbullets&amp;amp;_vy&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This is the actual removal step, and as before simply involves some counters into others.  The only difference here is that there are more of them.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;Very near the end now, all we have left is the #draw routine.  Drawing is going to take care of all of the things necessary to repaint the layer, based on the numbers we've spent so much time setting up.  The first task is to wipe the layer clean with the blank MZM:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;#draw&amp;quot;&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Then, a loop for each of the bullets, to move the bullet image onto the layer:&amp;lt;tt&amp;gt;&lt;br /&gt;
: loop start&lt;br /&gt;
: copy block at &amp;quot;#&amp;amp;spr_pb_x&amp;amp;&amp;quot; &amp;quot;#&amp;amp;spr_pby&amp;quot; for &amp;quot;spr_pb_w&amp;quot; &amp;quot;spr_pb_h&amp;quot; to &amp;quot;#('lyr_pb_x'+'pbullets&amp;amp;loopcount&amp;amp;_x')&amp;quot; &amp;quot;#('lyr_pb_y'+'pbullets&amp;amp;loopcount&amp;amp;_y')&amp;quot;&lt;br /&gt;
: loop for &amp;quot;('pbullets'-1)&amp;lt;/tt&amp;gt;&lt;br /&gt;
Finally, the end of the drawing, which for display purposes involves setting the &amp;lt;tt&amp;gt;spr#_cy&amp;lt;/tt&amp;gt; value so that bullets appear under everything:&amp;lt;tt&amp;gt;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
You may wonder what this means for collision, if drawing happens afterwards, and whether collision will happen a cycle late.  But the default behavior for sprites is to collide with anything overlapping the collision rectangle, regardless of whether there is actually anything in it.  This can be changed with the &amp;lt;tt&amp;gt;spr#_ccheck&amp;lt;/tt&amp;gt; counter so that either character 32 (setting 1) or any empty character (setting 2) does NOT cause a collision, but for our purposes here that's not what we want.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;One final step remains, and that's to revisit the main loop that actually calls all of the subroutines.  The astute reader will have noticed that the remove routine relies on having a sorted list, which the iterative approach in the move and check routines provides; but that there are two iterations to take into account, one for moving and one for collision checking, and so the list will not necessarily be completely sorted.  The simple way around this is to call #remove twice, once after #move and once after #check.&amp;lt;br&amp;gt;&lt;br /&gt;
The other snag is that the nature of the MZX loop structure always performs the loop once, even if there's nothing inside that we want to loop through.  This means that in the cases of empty lists, we don't want to call the subroutines at all.  Fortunately this is fairly easy to guard against:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_add&amp;quot; &amp;gt; 0 then &amp;quot;#add&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#move&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#check&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets_remove&amp;quot; &amp;gt; 0 then &amp;quot;#remove&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: wait 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
There is, however, one thing that we do want to happen no matter what, and that's for the layer to be cleared and the collision set off the board when the last bullet disappears.  With that in mind, grab both of those commands out of the draw routine, and put them in the main loop instead:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;drawloop&amp;quot;&lt;br /&gt;
: ...&lt;br /&gt;
: put &amp;quot;@blank.mzm&amp;quot; Image_file p02 at &amp;quot;lyr_pb_x&amp;quot; &amp;quot;lyr_pb_y&amp;quot;&lt;br /&gt;
: if &amp;quot;pbullets&amp;quot; &amp;gt; 0 then &amp;quot;#draw&amp;quot;&lt;br /&gt;
: set &amp;quot;spr&amp;amp;local&amp;amp;_cy&amp;quot; to -1&lt;br /&gt;
: wait for 1&lt;br /&gt;
: goto &amp;quot;drawloop&amp;quot;&amp;lt;/tt&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's it.  The engine still won't be doing anything, but it's no longer because there isn't any code behind it.  Instead, it's because there's nothing using the engine yet.  We'll cover that next in the section wrap up.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.3|Example 3.3 Code]]&lt;br /&gt;
&lt;br /&gt;
{{a|E3.4}}&lt;br /&gt;
&lt;br /&gt;
====Exercise 3.4: Interacting with the rest of the game====&lt;br /&gt;
After all of that setup, actually integrating the engine into the game is so simple it barely merits an exercise of its own.  In fact I'm considering moving all of this back into the framework exercise, since it would fit there and only take up a couple steps.  But for now, let's just finish this out.&lt;br /&gt;
&amp;lt;ol&amp;gt;&amp;lt;li&amp;gt;The first thing we need is a way to let the player shoot something.  Going with the standard MZX gameplay mechanic, this means the player robot needs to handle spacebar when an arrow key is pressed..  Simply add this line to each of the movement subroutines (#up, #down, etc.):&amp;lt;tt&amp;gt;&lt;br /&gt;
: if spacepressed then &amp;quot;shoot&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
Remember that the add routine is going to use the &amp;lt;tt&amp;gt;spr#_lastmove&amp;lt;/tt&amp;gt; counter to determine which way the bullet should fire, so make sure this check happens after that gets set.  Then, set up the :shoot branch:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: set &amp;quot;pbullets_add&amp;amp;pbullets_add&amp;amp;&amp;quot; to &amp;quot;local&amp;quot;&lt;br /&gt;
: inc &amp;quot;pbullets_add&amp;quot; by 1&lt;br /&gt;
: goto &amp;quot;#return&amp;quot;&amp;lt;/tt&amp;gt;&lt;br /&gt;
This short-circuits the rest of the movement routine; the player can't move when spacebar is pressed now, only shoot.  Note that we don't have to send the bullet robot any sort of label, we just add an item to the list that we know will get processed.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;That gets the bullet engine rolling on the input side, and you can actually use it now and see it in action.  Output is even simpler: much like the player engine sends other sprites to :touch labels when it collides with them, the bullet engine sends them a :playershot label.  To see this in action, open up your key or door robot and add something like this:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;playershot&amp;quot;&lt;br /&gt;
: set &amp;quot;local5&amp;quot; to &amp;quot;('local4'%16)&amp;quot;&lt;br /&gt;
: * &amp;quot;~&amp;amp;+local5&amp;amp;Ouch, you shot me!&amp;quot;&lt;br /&gt;
: end&amp;lt;/tt&amp;gt;&lt;br /&gt;
The extra step is an easy way to use the door's or key's color for the message, interpolating &amp;amp;+counter&amp;amp; returns a hexadecimal value.  Remember that local4 is the color of the key or door.  Unfortunately this can't be used with expressions, hence the need for an extra temp counter to extract the foreground color from the background.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt; Finally, to round it all off, let's actually tie the shooting to the value of the ammo counter.  That way, we can watch the ammo count down on the status bar when we shoot, and prevent from shooting when we're out of ammo.  Don't underestimate the usefulness of MZX's more specialized commands; here, the &amp;lt;tt&amp;gt;take&amp;lt;/tt&amp;gt; command provides exactly the functionality we need:&amp;lt;tt&amp;gt;&lt;br /&gt;
: : &amp;quot;shoot&amp;quot;&lt;br /&gt;
: take 1 AMMOS else &amp;quot;#return&amp;quot;&lt;br /&gt;
: ...&amp;lt;/tt&amp;gt;&lt;br /&gt;
Don't forget to have the global robot give the player some ammo up front, or this will stop you from shooting anything.&amp;lt;/li&amp;gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;
And that's all for now.  We're starting to have the beginnings of a really solid engine, all it really needs now are some enemies.  So we'll focus on that (and some other things) in the next section.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Sprite Code Examples#Example 3.4|Example 3.4 Code]]&lt;br /&gt;
&lt;br /&gt;
==External Links==&lt;br /&gt;
[http://www.digitalmzx.net/faq/sprite.html Saike's Sprite Tutorial] - Slightly out of date with regards to other MZX features.&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;br /&gt;
{{stub}}&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Viewport&amp;diff=7666</id>
		<title>Viewport</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Viewport&amp;diff=7666"/>
		<updated>2011-01-26T17:18:58Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Viewport''' is essentially a window that the player looks through in order to see the elements on a board. With it, you can limit the viewable area of a board, adjust the location in which the viewport is drawn on the screen (as long as the viewport is smaller than 80x25), modify how the viewport scrolls along the board, and even choose which location of the board should be viewable.&lt;br /&gt;
&lt;br /&gt;
A nice thing about the viewport is that it will automatically track the player's movements, and make sure that the player is always visible on screen by default. This functionality can also be applied to sprites by setting the SPRn_VIEW counter to 1.&lt;br /&gt;
&lt;br /&gt;
Aside from setting the edge color, all of the viewport's internal values are stored locally, per board. You can set the viewport's size and position relative to the screen through the ALT-P command in the world editor. The default edge color can be set by using the ALT-G command in the world editor, then selecting the &amp;quot;More&amp;quot; button. &lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[VIEWPORT # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[VIEWPORT SIZE # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLVIEW dir #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLVIEW POSITION]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[RESETVIEW]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLEDX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLEDY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]]'''&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Viewport&amp;diff=7665</id>
		<title>Viewport</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Viewport&amp;diff=7665"/>
		<updated>2011-01-26T17:18:47Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;The '''Viewport''' is essentially a window that the player looks through in order to see the elements on a board. With it, you can limit the viewable area of a board, adjust the ...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Viewport''' is essentially a window that the player looks through in order to see the elements on a board. With it, you can limit the viewable area of a board, adjust the location in which the viewport is drawn on the screen (as long as the viewport is smaller than 80x25), modify how the viewport scrolls along the board, and even choose which location of the board should be viewable.&lt;br /&gt;
&lt;br /&gt;
A nice thing about the viewport is that it will automatically track the player's movements, and make sure that the player is always visible on screen by default. This functionality can also be applied to sprites by setting the SPRn_VIEW counter to 1.&lt;br /&gt;
&lt;br /&gt;
Aside from setting the edge color, all of the viewport's internal values are stored locally, per board. You can set the viewport's size and position relative to the screen through the ALT-P command in the world editor. The default edge color can be set by using the ALT-G command in the world editor, then selecting the &amp;quot;More&amp;quot; button. &lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
'''[[VIEWPORT # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[VIEWPORT SIZE # #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLVIEW dir #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLVIEW POSITION]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[RESETVIEW]]''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLEDX]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SCROLLEDY]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[SPRn_SETVIEW]]'''&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7664</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7664"/>
		<updated>2011-01-26T07:16:15Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: /* Message Row HUDs vs Overlay and Sprite HUDs */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Row''' is an incredibly simple yet powerful tool for displaying strings and values on the screen.  Activating the message line only requires a single line of code, which must be repeated every cycle to keep the displayed data current. As of Megazeux 2.83, the message line can consist of 512 characters.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Row!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. Lastly, built-in objects can also use the message line to display their own messages, which could potentially overwrite important information that we want to communicate to the player. Fortunately, we can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#CLEAR MESG|CLEAR MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|MESSAGE ROW #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|SET MESG COLUMN #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|CENTER MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#DISABLE MESG EDGE|DISABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#ENABLE MESG EDGE|ENABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
The global counter BIMESG can be used to disable/enable built-in messages, such as the ones displayed when the player is hit by built-in bullets or switches bomb types.&lt;br /&gt;
&lt;br /&gt;
==Special Formatting==&lt;br /&gt;
&lt;br /&gt;
You can also adjust the appearance of the text through the special prefixes ~ and @ followed by a hexadecimal digit for the color.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;~FThis text is white on black. ~eThis text is yellow on black. @1This text is yellow on dark blue.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The message row will also interpret the new line character, \n, and display any text that follows on the next row.  The newline character can be used as many times as needed, as long as it doesn't extend past the bottom row of the screen. &lt;br /&gt;
&lt;br /&gt;
You can also display values stored inside of counters, and even expressions, through [[counter interpolation]].&lt;br /&gt;
&lt;br /&gt;
 set &amp;quot;$string&amp;quot; to &amp;quot;Five minus four equals &amp;quot;&lt;br /&gt;
 set &amp;quot;num&amp;quot; to 4&lt;br /&gt;
 * &amp;quot;~f&amp;amp;$string&amp;amp;(5-'num')&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==Message Row HUDs vs Overlay and Sprite HUDs==&lt;br /&gt;
&lt;br /&gt;
+ The message row is static to the [[viewport]], as opposed to the Write/Copy Overlay commands&lt;br /&gt;
&lt;br /&gt;
+ Unlike the message row, the overlay requires some clean-up if the board is allowed to scroll, or displays data that can be of varying length (like counter values).&lt;br /&gt;
&lt;br /&gt;
- The robotic editor isn't designed to display ~ and @ color prefixes; As a result, scripting the message row to display graphical data can be cumbersome and error prone.&lt;br /&gt;
&lt;br /&gt;
- Unlike the overlay and sprite layers, the background color of a message row will never change to what color is below it.&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7663</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7663"/>
		<updated>2011-01-26T07:16:01Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Row''' is an incredibly simple yet powerful tool for displaying strings and values on the screen.  Activating the message line only requires a single line of code, which must be repeated every cycle to keep the displayed data current. As of Megazeux 2.83, the message line can consist of 512 characters.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Row!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. Lastly, built-in objects can also use the message line to display their own messages, which could potentially overwrite important information that we want to communicate to the player. Fortunately, we can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#CLEAR MESG|CLEAR MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|MESSAGE ROW #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|SET MESG COLUMN #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|CENTER MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#DISABLE MESG EDGE|DISABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#ENABLE MESG EDGE|ENABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
The global counter BIMESG can be used to disable/enable built-in messages, such as the ones displayed when the player is hit by built-in bullets or switches bomb types.&lt;br /&gt;
&lt;br /&gt;
==Special Formatting==&lt;br /&gt;
&lt;br /&gt;
You can also adjust the appearance of the text through the special prefixes ~ and @ followed by a hexadecimal digit for the color.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;~FThis text is white on black. ~eThis text is yellow on black. @1This text is yellow on dark blue.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The message row will also interpret the new line character, \n, and display any text that follows on the next row.  The newline character can be used as many times as needed, as long as it doesn't extend past the bottom row of the screen. &lt;br /&gt;
&lt;br /&gt;
You can also display values stored inside of counters, and even expressions, through [[counter interpolation]].&lt;br /&gt;
&lt;br /&gt;
 set &amp;quot;$string&amp;quot; to &amp;quot;Five minus four equals &amp;quot;&lt;br /&gt;
 set &amp;quot;num&amp;quot; to 4&lt;br /&gt;
 * &amp;quot;~f&amp;amp;$string&amp;amp;(5-'num')&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==Message Row HUDs vs Overlay and Sprite HUDs==&lt;br /&gt;
&lt;br /&gt;
+ The message row is static to the [[viewport]], as opposed to the Write/Copy Overlay commands&lt;br /&gt;
+ Unlike the message row, the overlay requires some clean-up if the board is allowed to scroll, or displays data that can be of varying length (like counter values).&lt;br /&gt;
&lt;br /&gt;
- The robotic editor isn't designed to display ~ and @ color prefixes; As a result, scripting the message row to display graphical data can be cumbersome and error prone.&lt;br /&gt;
&lt;br /&gt;
- Unlike the overlay and sprite layers, the background color of a message row will never change to what color is below it.&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7662</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7662"/>
		<updated>2011-01-26T05:43:38Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Row''' is an incredibly simple yet powerful tool for displaying strings and values on the screen.  Activating the message line only requires a single line of code, which must be repeated every cycle to keep the displayed data current. As of Megazeux 2.83, the message line can consist of 512 characters.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Row!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. Lastly, built-in objects can also use the message line to display their own messages, which could potentially overwrite important information that we want to communicate to the player. Fortunately, we can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#CLEAR MESG|CLEAR MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|MESSAGE ROW #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|SET MESG COLUMN #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|CENTER MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#DISABLE MESG EDGE|DISABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#ENABLE MESG EDGE|ENABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
The global counter BIMESG can be used to disable/enable built-in messages, such as the ones displayed when the player is hit by built-in bullets or switches bomb types.&lt;br /&gt;
&lt;br /&gt;
==Special Formatting==&lt;br /&gt;
&lt;br /&gt;
You can also adjust the appearance of the text through the special prefixes ~ and @ followed by a hexadecimal digit for the color.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;~FThis text is white on black. ~eThis text is yellow on black. @1This text is yellow on dark blue.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The message row will also interpret the new line character, \n, and display any text that follows on the next row.  The newline character can be used as many times as needed, as long as it doesn't extend past the bottom row of the screen. &lt;br /&gt;
&lt;br /&gt;
You can also display values stored inside of counters, and even expressions, through [[counter interpolation]].&lt;br /&gt;
&lt;br /&gt;
 set &amp;quot;$string&amp;quot; to &amp;quot;Five minus four equals &amp;quot;&lt;br /&gt;
 set &amp;quot;num&amp;quot; to 4&lt;br /&gt;
 * &amp;quot;~f&amp;amp;$string&amp;amp;(5-'num')&amp;quot;&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7661</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7661"/>
		<updated>2011-01-26T05:43:24Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Row''' is an incredibly simple yet powerful tool for displaying strings and values on the screen.  Activating the message line only requires a single line of code, which must be repeated every cycle to keep the displayed data current. As of Megazeux 2.83, the message line can consist of 512 characters.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Row!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. Lastly, built-in objects can also use the message line to display their own messages, which could potentially overwrite important information that we want to communicate to the player. Fortunately, we can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#CLEAR MESG|CLEAR MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|MESSAGE ROW #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|SET MESG COLUMN #]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[MESSAGE ROW (command)|CENTER MESG]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#DISABLE MESG EDGE|DISABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
'''[[* &amp;quot;string&amp;quot;#ENABLE MESG EDGE|ENABLE MESG EDGE]]'''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
The global counter BIMESG can be used to disable/enable built-in messages, such as the ones displayed when the player is hit by built-in bullets or switches bomb types.&lt;br /&gt;
&lt;br /&gt;
==Special Formatting==&lt;br /&gt;
&lt;br /&gt;
You can also adjust the appearance of the text through the special prefixes ~ and @ followed by a hexadecimal digit for the color.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;~FThis text is white on black. ~eThis text is yellow on black. @1This text is yellow on dark blue.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The message row will also interpret the new line character, \n, and display any text that follows on the next row.  The newline character can be used as many times as needed, as long as it doesn't extend past the bottom row of the screen. &lt;br /&gt;
&lt;br /&gt;
You can also display values stored inside of counters, and even expressions, through [[counter interpolation]].&lt;br /&gt;
&lt;br /&gt;
 set &amp;quot;$string&amp;quot; to &amp;quot;Five minus four equals &amp;quot;&lt;br /&gt;
 set &amp;quot;num&amp;quot; to 4&lt;br /&gt;
 * &amp;quot;~f&amp;amp;$string&amp;amp;(5-'num')&amp;quot;&lt;br /&gt;
[[Category:Megazeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Commands&amp;diff=7660</id>
		<title>Commands</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Commands&amp;diff=7660"/>
		<updated>2011-01-26T02:50:01Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A '''command''' is a single, executed line of [[Robotic]] in a given [[robot]]. In general, every line - including labels, comments, and even blank lines - is interpreted and treated as a command when they are encountered, save for some minor exceptions.&lt;br /&gt;
&lt;br /&gt;
This is important because each robot in a [[Megazeux]] world is allowed to execute a certain number of commands per [[cycle]], before control automatically passes to the next robot on the board.  Historically, this number has been 40 since MZX version 2.00 (25 before that), but since [[MegaZeux#Exophase Versions|version 2.60]] Megazeux has provided the aptly named &amp;quot;commands&amp;quot; [[counter]] to set this number to something else.  In games with complex [[engines]] requiring a lot of computation, it is common to see this counter set to something high, in order allow the engine function in a reasonable amount of time.  Popular settings include 1000, 32767, (1000000), and the [[expression]] (-1&amp;gt;&amp;gt;1) that sets the value as high as possible.&lt;br /&gt;
&lt;br /&gt;
However it is worth cautioning that while &amp;quot;commands&amp;quot; sets a software limit on what MZX is allowed to do, you will still come up against a hardware limit on what MZX is ''able'' to do.  At a certain point (2^16 = 65536 average total commands per cycle on the average MZXer's Pentium II), attempting to actually execute as many commands as you're allowed to will start causing noticeably slow performance.  This can become much more pronounced for processor intensive commands like &amp;lt;tt&amp;gt;copy block&amp;lt;/tt&amp;gt;, which take more time to execute, to the point where MZX hangs and becomes completely unusable.  Therefore, while it is usually recommended to set &amp;quot;commands&amp;quot; much higher than you actually need, it is also strongly recommended that you make sure each robot only executes as many commands as it needs to per cycle, particularly when loops are involved.  When an engine incorporates a main program loop that is supposed to execute each cycle make sure the loop explicitly terminates with a cycle-ending command like &amp;lt;tt&amp;gt;[[cycle 1]]&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Other than non cycle ending commands, there are cycle-ending and multi-cycle commands. Cycle ending commands, once executed, stop the processing of Robotic within the given robot. Usually any command that moves either the player or robot is cycle ending. Multi-cycle commands are unique in that they are executed over the course of 0 or more cycles before moving on to the next command. However, one downside to using multi-cycle commands is that if the robot is sent to a [[subroutine]] call by another robot, the command will be immediately interrupted to deal with the subroutine call, and on return the multi-cycle command will start over. &lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7630</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7630"/>
		<updated>2011-01-24T20:38:37Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Line''' is an incredibly simple yet powerful tool for outputting strings and values on the screen. Displaying the message line only requires a single line of code. As of Megazeux 2.83, the message line can consist of 512 characters.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Line!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. Lastly, built-in objects can also use the message line to display their own messages, which could potentially overwrite important information that we want to communicate to the player. Fortunately, we can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
==Commands==&lt;br /&gt;
&lt;br /&gt;
 set message row # ''Sets the row in which the message line appears in''&lt;br /&gt;
 set mesg column # ''Sets the column in which the message line appears in, and disables auto-centering''&lt;br /&gt;
 center mesg ''Enables auto-centering of the message row.''&lt;br /&gt;
&lt;br /&gt;
==Counters==&lt;br /&gt;
&lt;br /&gt;
The global counter BIMESG can be used to disable/enable built-in messages&lt;br /&gt;
&lt;br /&gt;
==Special Formatting==&lt;br /&gt;
&lt;br /&gt;
You can also adjust the appearance of the text through the special prefixes ~ and @ followed by a hexadecimal digit for the color.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;~FThis text is white on black. ~eThis text is yellow on black. @1This text is yellow on dark blue.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The message line will also interpret the new line character, \n, and display the text on the next line, as long as it doesn't extend past the bottom row of the screen. &lt;br /&gt;
&lt;br /&gt;
You can also output values stored inside of counters, and even expressions, through [[counter interpolation]].&lt;br /&gt;
&lt;br /&gt;
 set &amp;quot;$string&amp;quot; to &amp;quot;Five minus four equals &amp;quot;&lt;br /&gt;
 set &amp;quot;num&amp;quot; to 4&lt;br /&gt;
 * &amp;quot;~f&amp;amp;$string&amp;amp;(5-'num')&amp;quot;&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7629</id>
		<title>Message Row</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Message_Row&amp;diff=7629"/>
		<updated>2011-01-24T19:39:48Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Created page with &amp;quot;The '''Message Line''' is an incredibly simple yet powerful tool for outputting strings and values on the screen. Displaying the message line only requires a single line of code....&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''Message Line''' is an incredibly simple yet powerful tool for outputting strings and values on the screen. Displaying the message line only requires a single line of code.&lt;br /&gt;
&lt;br /&gt;
 * &amp;quot;This line of text will be displayed on the Message Line!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
By default, the message line command causes the text to appear centered on the bottom row, while the forground color of the text is animated by cycling through various colors of the palette. Also, the message line will only be displayed for a short period, unless a new message is created. We can adjust these defaults with a few commands and some special formatting.&lt;br /&gt;
&lt;br /&gt;
 set message row # ''Sets the row in which the message line appears in''&lt;br /&gt;
 set mesg column # ''Sets the column in which the message line appears in, and disables auto-centering''&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Christmas_2005_Dualstream_Day_of_Zeux&amp;diff=5150</id>
		<title>Christmas 2005 Dualstream Day of Zeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Christmas_2005_Dualstream_Day_of_Zeux&amp;diff=5150"/>
		<updated>2008-01-15T00:51:45Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Christmas 2005 DSDoZ was held in late december of 2005. The most noticable thing about it is that it was the first one that was without the anonymity rule, which was met with mixed reactions. The topics were Valor and Organized Crime&lt;br /&gt;
&lt;br /&gt;
==Game Rankings==&lt;br /&gt;
*1&amp;lt;sup&amp;gt;st&amp;lt;/sup&amp;gt; Place - Entry ????- V-Complex - The 27th ([[Quasar]]) (Score:1120/1600)&lt;br /&gt;
*2&amp;lt;sup&amp;gt;nd&amp;lt;/sup&amp;gt; Place - Entry ????-Pacone's Grand Day Out - Revgromo and the Dancing Brambles ([[Revvy]], [[asgromo]], [[Bramble]]) (Score:1110/1600)&lt;br /&gt;
*3&amp;lt;sup&amp;gt;rd&amp;lt;/sup&amp;gt; Place - Entry ????- Fallen Angels - Better Than 6th This Time (KirbySSB, Edge) (996/1600)&lt;br /&gt;
*4&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- Its A Vigilante! ??? - Crustaceous (Malik_Gynax, Celedor)  (866/1600)&lt;br /&gt;
*5&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ???? - cyber-mafia - Team MZXian funDEMENTelists (Xeirxes, KKairos) (834/1600)&lt;br /&gt;
*6&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- untitled? - Team Dessert (Torte) (597/1600)&lt;br /&gt;
*7&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- untitled? - TEAM LEDAH ([[Goshi|Goshi3156]]) (531/1600)&lt;br /&gt;
*8&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- Hero's Quest - TEAM SUF 4!! ([[Old-Sckool]]) (475/1600)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 48136 - i miss micah ([[CJA]])&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 57005 - Team Cherry Cotton (funkbrat)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 58509 - Team Omega-3 Fatty Acids (Pyro1588, Commodorejohn, The Pope)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 59158 - TEAM POOP ROAD &amp;gt;:( ([[micah]], [[CJA]], nahah)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 73803 - Two Men Whose Feet Are in Coffins (Fungahhh, burstroc)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 96276 - Artificial Spank (TraumaFox)&lt;br /&gt;
caponi and trex - who the hell knows.&lt;br /&gt;
==External Links==&lt;br /&gt;
*[http://www.digitalmzx.net/forums/index.php?showtopic=9948 Official results thread]&lt;br /&gt;
&lt;br /&gt;
{{stub}}&lt;br /&gt;
[[Category:Competitions]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Christmas_2005_Dualstream_Day_of_Zeux&amp;diff=5149</id>
		<title>Christmas 2005 Dualstream Day of Zeux</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Christmas_2005_Dualstream_Day_of_Zeux&amp;diff=5149"/>
		<updated>2008-01-15T00:41:14Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: Scores added, Needs Team Numbers, Some Formating&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Christmas 2005 DSDoZ was held in late december of 2005. The most noticable thing about it is that it was the first one that was without the anonymity rule, which was met with mixed reactions. The topics were Valor and Organized Crime&lt;br /&gt;
&lt;br /&gt;
==Game Rankings==&lt;br /&gt;
*1&amp;lt;sup&amp;gt;st&amp;lt;/sup&amp;gt; Place - Entry ????- V-Complex - The 27th ([[Quasar]]) (Score:1120/1600)&lt;br /&gt;
*2&amp;lt;sup&amp;gt;nd&amp;lt;/sup&amp;gt; Place - Entry ????-Pacone's Grand Day Out - Revgromo and the Dancing Brambles ([[Revvy]], [[asgromo]], [[Bramble]]) (Score:1110/1600)&lt;br /&gt;
*3&amp;lt;sup&amp;gt;rd&amp;lt;/sup&amp;gt; Place - Entry ????- Fallen Angels - Better Than 6th This Time (KirbySSB, Edge) (996/1600)&lt;br /&gt;
*4&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- Its A Vigilante! ??? - Crustaceous (Malik_Gynax, Celedor)  (866/1600)&lt;br /&gt;
*5&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ???? - cyber-mafia - Team MZXian funDEMENTelists (Xeirxes, KKairos) (834/1600)&lt;br /&gt;
*6&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- untitled? - Team Dessert (Torte) (597/1600)&lt;br /&gt;
*7&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- untitled? - TEAM LEDAH ([[Goshi|Goshi3156]]) (531/1600)&lt;br /&gt;
*8&amp;lt;sup&amp;gt;th&amp;lt;/sup&amp;gt; Place - Entry ????- Hero's Quest - TEAM SUF 4!! ([[Old-Sckool]]) (475/1600)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 48136 - i miss micah ([[CJA]])&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 57005 - Team Cherry Cotton (funkbrat)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 58509 - Team Omega-3 Fatty Acids (Pyro1588, Commodorejohn, The Pope)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 59158 - TEAM POOP ROAD &amp;gt;:( ([[micah]], [[CJA]], nahah)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 73803 - Two Men Whose Feet Are in Coffins (Fungahhh, burstroc)&lt;br /&gt;
*DQ&amp;lt;sup&amp;gt;ed&amp;lt;/sup&amp;gt; Entry 96276 - Artificial Spank (TraumaFox)&lt;br /&gt;
caponi and trex - who the hell knows.&lt;br /&gt;
==External Links==&lt;br /&gt;
*[http://www.digitalmzx.net/forums/index.php?showtopic=9695 Official results thread]&lt;br /&gt;
&lt;br /&gt;
{{stub}}&lt;br /&gt;
[[Category:Competitions]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Overlay&amp;diff=4285</id>
		<title>Overlay</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Overlay&amp;diff=4285"/>
		<updated>2008-01-08T21:17:10Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''overlay''' is a graphical layer in [[MegaZeux]] that is normally used for graphics that are drawn over the main playing area.  These graphics can't be directly interacted with by the player, and only contain color and character data.  Common uses for the overlay include creating scenery that the player can walk &amp;quot;behind&amp;quot;, such as trees or houses.  It is also often used to create special effects that can be copied onto the visible board as necessary and then removed.  More complex games may use the overlay as a buffer area for graphics, though the introduction of dynamically loadable [[MZM|MZMs]] and the [[vlayer]] have somewhat supplanted this in more sophisticated code.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
Char 32 is not part of the overlay&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:MegaZeux]]&lt;br /&gt;
{{stub}}&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Marty_the_Mage&amp;diff=4272</id>
		<title>Marty the Mage</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Marty_the_Mage&amp;diff=4272"/>
		<updated>2008-01-08T00:24:24Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Marty the Mage, Old-Sckool's third entry in the DoZ competition, is a free roaming shooter sidescroller done in SMZX mode 3. You play as a mage returning to his homeland who has to destroy a powerful demon (which was never implemented).&lt;br /&gt;
&lt;br /&gt;
==Gameplay==&lt;br /&gt;
The object of the game is to simply move Marty from the left side of the board to the right within the alloted time, although the player can choose to kill the moon-shaped demons along the path. The player is fully controlled by the mouse. By centering the mouse on the player's general position, Marty stops. By positioning the cursor in the apropriate direction, Marty moves, depending on how far away the cursor is from Marty. Clicking the mouse causes marty to shoot fireballs from his hands.&lt;br /&gt;
&lt;br /&gt;
==Development==&lt;br /&gt;
Initially, the gameplay concept was going to be based off of the movie Kiki's Delivery Service, where the player was going to fly back and forth between 5 locals running errands and having a story develop alongside these errands. This was never remotely achieved though due to Old-Sckool's inexperience with a variety of MZX's features.&lt;br /&gt;
&lt;br /&gt;
==Notes==&lt;br /&gt;
The game's title doesn't actually appear at all in the game. However, the team name Bionic Commando (based off of the NES Videogame) appeared as the title in the official score ranking as well as a few scoresheets.&lt;br /&gt;
[[Category:Games]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
	<entry>
		<id>https://www.digitalmzx.com/wiki/index.php?title=Christmas_2006_Dualstream_Day_of_Zeux_Judging_Sheets:ShloobeR&amp;diff=4271</id>
		<title>Christmas 2006 Dualstream Day of Zeux Judging Sheets:ShloobeR</title>
		<link rel="alternate" type="text/html" href="https://www.digitalmzx.com/wiki/index.php?title=Christmas_2006_Dualstream_Day_of_Zeux_Judging_Sheets:ShloobeR&amp;diff=4271"/>
		<updated>2008-01-08T00:02:26Z</updated>

		<summary type="html">&lt;p&gt;Old-Sckool: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;2006 DUALSTREAM DOZ, Q4&lt;br /&gt;
&lt;br /&gt;
TOPICS ARE :&lt;br /&gt;
&lt;br /&gt;
MEMORY (GENERAL)&amp;lt;br&amp;gt;&lt;br /&gt;
FLIGHT (SPECIFIC)&lt;br /&gt;
&lt;br /&gt;
THE HONOURABLE JUDGE SHLOOBER PRESIDING.&lt;br /&gt;
&lt;br /&gt;
LET US COMMENCE.&lt;br /&gt;
&lt;br /&gt;
------------------------------------------&lt;br /&gt;
&lt;br /&gt;
'''''Team 525 - [[Aviation Aspiration]].'''''&lt;br /&gt;
&lt;br /&gt;
- first impressions -&lt;br /&gt;
&lt;br /&gt;
'Nice music!' That's what I immediately thought as I loaded up the title screen (at least until that trumpety thing came in), The title screen looks nice enough, the graphics seems, average at best but I'm not too worried about that, generally quite pleased with how it looks, the colours are very 'flight'y&lt;br /&gt;
&lt;br /&gt;
-So then what? -&lt;br /&gt;
&lt;br /&gt;
The introduction (again with some nice chilling music) is quite well written, I can't really complain about the plot here although it does seem a bit simple, the wind sample used in the song sounds truely flighty! Ok the other tune has just come in, and the slideshow has just sta-OH MY GOD what are those things. Those are the freakiest looking people I have ever seen, &lt;br /&gt;
one looks like a cross between charlie brown and a giraffe, the other a construction worker and a hippy, if one of them weren't bald it would be hard to tell who was the girl and who was the boy :(.&lt;br /&gt;
&lt;br /&gt;
- The game -&lt;br /&gt;
&lt;br /&gt;
Ok, so you're presented with a menu, with different choices, now, while it may look at first instance as if some effort was put in to make the game harder or easier, it's in fact, just a simple speed change, a point or two for effort, but not really. I consider myself a sort of 'Normal/hard' person, no one calls me a BORING or alcoholic. Alcoholics, I have heard though, do enjoy a bit of difficulty, let's go.&lt;br /&gt;
&lt;br /&gt;
Eek, what the hell has happened here, it looks like someone threw up on the game after eating alphabet soup, it seems some sort of BUG has attacked the game, this can be fixed by loading through the editor and (thankfully) the whole game can be played this way, but lose a few points here for obvious reasons!&lt;br /&gt;
&lt;br /&gt;
The game has clouds, not just some clouds, the game is all clouds. The entire game centres aroudn clouds, you fly around clouds and shoot grey clouds to turn them into gold clouds. Fair enough I guess, it is about flight, you may see clouds when you fly!. So yeh, you're going through the air, being shot at by orbs, so you shoot them with your gun and uh... yeh, you shoot clouds. To be honest you don't really do much. There's not a huge enjoyment factor attached to this game, it can be quite challenging, but you regain health for seemingly random reasons (at one point i thought if you went through a cloud you got health but now i'm just NOT SURE! :O). All the levels are the same structure, just progressively harder, the difficulty curve is quite solid, starting off truely tedious and become quite frantic, but it's not particularly fun, 1x1 shooter never really are aiming is so annoying, the burst gun is somewhat helpful but doesn't help that much.&lt;br /&gt;
&lt;br /&gt;
Ok so now I've got to what looks like the last level, where you and the girl have to confront your dreams or fears or something dumb like that and prove your worth, the way to do this is the most annoying thing imaginable, i'd rather staple my fingers to the table then do that again. What you have to do, is alternately whack Up-left and down-right over, and over, and OVER, AND OVER again. my fingers were smoking afterwards, that was the worst idea in the world! why did you do that to me?. It's actually harder then it sounds to maintain a good rhythm, the first time I did it I only got one of them in, and I was presented with a one liner ending, So I tried getting the other endings, all one liners. A little emotional (oh no she cant fly D:&amp;gt;) but apart from that a bit of a letdown, for all that bone crushing and muscle aching I had to give up for it!&lt;br /&gt;
&lt;br /&gt;
Also, make sure you're READY and know exactly what you have to do in this last stage before you attempt it or you are guaranteed you lose, in fact, if you're not hitting those buttons before you begin you will have lost when you started, there is no warning as to what happens, it's a bit unfair : (&lt;br /&gt;
&lt;br /&gt;
- On review -&lt;br /&gt;
&lt;br /&gt;
I can't decide which part of the game is more enjoyable, the finger pain or the really boring part. I'll take a leap of faith and say the former, it was really pretty boring and somewhat illogical, who's even seen a gold cloud i ask you &amp;gt;:(, but there was some length/depth to it and it had more to do with the whole flight thing.&amp;lt;br&amp;gt;&lt;br /&gt;
The one constant throughout this game is the music, it's definitely very good, I doubt it's original as the styles are much too varied but hey I might be wrong, it's a good selection anyway and represents the theme quite well.&amp;lt;br&amp;gt;&lt;br /&gt;
Have I mentioned the graphics are pretty drab? No? Oh well they are, they're not HORRIBLE by any means but they're just quite boring to look at, the clouds are by FAR too curly for my taste and those people are just nightmare inducing, your character, honestly, I don't know what he's meant to look like in real life but he would be like, I dunno, kept in a zoo or something. Hopefully.&lt;br /&gt;
&lt;br /&gt;
Ok I've figured it out now, you get health by shooting the grey clouds, so they're not essential to shoot I guess. What is 'Andante corporation'!&lt;br /&gt;
&lt;br /&gt;
- Pros -&lt;br /&gt;
&lt;br /&gt;
Music - Can't emphasis this one enough, but it's not enough.&amp;lt;br&amp;gt;&lt;br /&gt;
Design - Apart from that one crippling bug the game is pretty much flawless, I don't like the way the game doesn't tell you how to 'win' the dream sequences though, I'm still not sure whether shooting the grey clouds is a must or not.&amp;lt;br&amp;gt;&lt;br /&gt;
Plot - Half decent plot, can't really complain, a bit fanciful and  doesn't leave much to the imagination, but solid nonetheless.&lt;br /&gt;
&lt;br /&gt;
- Cons -&lt;br /&gt;
&lt;br /&gt;
Gameplay - I know it sounds harsh but I'm sorry, it's like, as fun to play as tag, tag against a TREE.&amp;lt;br&amp;gt;&lt;br /&gt;
Length - Slightly below average length for a doz game.&amp;lt;br&amp;gt;&lt;br /&gt;
Graphics - Drab, tedious, dull. Won't go as far as to say BAD but they were not good by any means&amp;lt;br&amp;gt;&lt;br /&gt;
Sound - No sounds&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SPECIFIC TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     18/20''&lt;br /&gt;
&lt;br /&gt;
Not bad, on the new ruleset obviously theme isn't weighted very highly for a specific game, but it adheres to it well, not just the plot but the atmosphere in general, soft music in places, with windy sounds. Bright blues and whites in the game, plus the fact that you know, you're ALWAYS flying.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  36/120''&lt;br /&gt;
&lt;br /&gt;
Could have been so much more, 1x1 shooters are just not very fun in MZX in general, aiming is too much of a bitch. But this game is certainly not one of the best ones out there anyway, really is nothing to hit more then one char wide. The final stage was just infuriating, I did not like it at all &amp;gt;:(.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  26/90''&lt;br /&gt;
&lt;br /&gt;
Nuh uh, not very good at all, the graphical cutscenes just ruined the atmosphere that the text slides had going. The graphics in game were pretty horrible, some edited chars but nothing amazing, the screens were quite boring to look at and had no real features on them, the best graphics of the &lt;br /&gt;
game were arguably the pause screen, see it had... it had that mountain there and ... you know.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  25/80''&lt;br /&gt;
&lt;br /&gt;
It has a sidescrolling shooter, which is generally quite functional, if a little monotonous, the last stage also worked, and hurt. While what was there was pretty workable, it was nothing remotely new or exciting, the robotic feels uninspired.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  32/50''&lt;br /&gt;
&lt;br /&gt;
One of the stronger points of the game, the plot was above average. It developed somewhat as the game went on and had multiple endings which was nice enough. It was unfortunately, quite simple and did not really make me think much about it, coupled with the music however the plot felt quite  deep. Flying in your dreams was an interesting take on the theme.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  29/40''&lt;br /&gt;
&lt;br /&gt;
Probably as high as I can make the score for not having an original soundtrack or sound, the music was excellent for the game. We firmly believe that no audio is better then bad audio, but good sound is better still! Atmospheric&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -  166 / 400'''&lt;br /&gt;
&lt;br /&gt;
Mediocre&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
I feel that that score is VERY generous for that game, in my mind I had it pegged as no more then 150/400 but when it all adds up, well, there you go.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
'''''Team 5389 - [[The Thing What Came From Beneath|The thing what came from beneath.]]'''''&lt;br /&gt;
&lt;br /&gt;
- Rhyme!!! -&lt;br /&gt;
&lt;br /&gt;
Exciting stuff rhyme, you don't see it much in DoZ games but then again you wouldnt really expect to would you?&lt;br /&gt;
&lt;br /&gt;
When you first load this game you see a bunch of numbers and built in SFX, I was a little skeptical of the sound effects especially at first, wondering whether this was going to be a artsy retro game or just a plain lack of decent sound/music game. The title screen, as far as they go, was nice enough, it was all MONOCHROMEY which gives it a nice memoryish feel (I will take a leap of faith and assume this game goes on that theme). So ok, fair enough, let's hit P.&lt;br /&gt;
&lt;br /&gt;
You're confronted with an intro, an interesting one due to the aforementioned rhyme, a sort of oldskooly graphics style abounds in this game too, with smileys and simple rooms and walls. The intro wasn't anything amazing itself, some demon's eating kids, buhh buhh, you must stop him. To be fair I probably don't give the plot enough credit but there you go that's just me. Anyway, so apparently you've challenged the demon, and what he says is, you must find out his name. There are 4 rooms in this game with different ... how should we say... 'challenges'. The way the main room works is a bit odd, when you finish one room another room becomes available or some become blocked off, sometimes the final question comes too soon, sometimes you get trapped behind a wall after a room, I'm not quite sure what the intended order of rooms is, as far as I know there isn't one, bugger.&lt;br /&gt;
&lt;br /&gt;
- On my first try -&lt;br /&gt;
&lt;br /&gt;
- The Liar -&lt;br /&gt;
&lt;br /&gt;
So on my first try, I started off with 'the liar', seemed fair enough to me to try this one first, so in I go. Interesting, two rooms, the polar of each other. It took me a couple seconds to get what the scrolls meant but I figured it out soon enough, the scrolls contained letters of the Demon's name. I was a little unsure about 'the house of lies' and 'the house of truth' I assumed at first that the left was the former because it was below the sentance, but then I figured that the colour of the text was what mattered, I hope I'm right : (. With that you get a couple of letters.&amp;lt;br&amp;gt;&lt;br /&gt;
Call me thick witted but I'm not sure how that puzzle on the right works, unless it's not supposed to work, there's a scroll in there which seems impossible to get to, there's a sort of hooky thing next to the house but it seems to do nothing. So I'm guessing you just exit via the left side. Fair enough. I found three 'true' letters... I think.&lt;br /&gt;
&lt;br /&gt;
- The Murderer -&lt;br /&gt;
&lt;br /&gt;
This penelope seems to be quite the character, killing people and getting cheated on, eh, I wish I knew her!, but to the point, this room looks pretty simple, there are 4 icons on the floor and one pushable object. There are 4 words in either corner, one of the icons produces a door and 3 letters if you roll the thing on it, the only logic behind this puzzle I can see is that the icon in question is closest to the word 'revenge' which is most relevant to the scroll in question. Weird. Anyway, moving on.&lt;br /&gt;
&lt;br /&gt;
- The Thief&lt;br /&gt;
&lt;br /&gt;
Looks like I'm trapped in the thief's room and have to enter. A slider puzzle, delicious. There's a rabbit in the top left so I assumed I have to reach him, why is there a rabbit here, what is with the rabbits, WHY DOES THIS GAME MAKE NO SENSE D:. I'm afraid this is probably THE WORST slider  puzzle I have ever seen, there are like 50 ways to do it succesfully, I don't know why the author even bothered it seems a waste of time. 3 more letters. Oh and I'm stuck outside the room, game over!&lt;br /&gt;
&lt;br /&gt;
- The Whore -&lt;br /&gt;
&lt;br /&gt;
This is probably both, the most interesting, and the most retarded of the 4 rooms. You're inside a kidney shaped (IT BETTER BE A KIDNEY) room, there is a puzzley thing at the top of the screen, it's quite easy to work out what happens, basically you have to get the bombs to explode the scrolly things at the top, it's not too hard to figure out, you receive 3 more letters.&lt;br /&gt;
&lt;br /&gt;
You wouldn't believe the groan I uttered when I saw 'the cock' and 'the egg'. Arty yes, original yes, dumb yes.&lt;br /&gt;
&lt;br /&gt;
- Ok so now what -&lt;br /&gt;
&lt;br /&gt;
Ok so you've completed all 4 rooms, and you're taken to the FINAL CONFRONTATION. You wonder, 'man that demon is gonna be hard as, I better get ready to kick him in'. He asks you his name, if you have the right letters (the only possible confusion being in the house of lies, 3 of the letters being technically useless) then he basically says 'oh k well done lol'...&lt;br /&gt;
&lt;br /&gt;
...WHAT THE HELL, why doesnt he eat me! I fucking walked into his lair and wrecked up the place, he looks hard why is he such a wuss! I guess it's all in the name of 'style'. And when you look back, this game reeks of it. But, before you all stand gobsmacked remarking how much this game 'reminds you of forrester', remember that there are, tops, 2 minutes of gameplay in this game, and 0 replayability value, it's an interesting concept granted, and the way it was presented is definitely unique, but it's not really a game, it's more of an interactive short film. It does have it's charm though, don't assume I am not, somewhat, impressed.&lt;br /&gt;
&lt;br /&gt;
- Hang on, aren't we forgetting something -&lt;br /&gt;
&lt;br /&gt;
... let's see... game... uh... graphics... plot...&lt;br /&gt;
&lt;br /&gt;
oh yeah. Theme.&lt;br /&gt;
&lt;br /&gt;
What the hell is up with the theme here, unless I'm mistaken the topics were 'memory' and 'flight'. I think we can safely assume that there is NOTHING, associated with flight or any possible meaning of it, or if there is it's too damn obscure to be worth anything. So memory. Well, no, neither is there anything to do with memory here. The title screen was black and white I guess, and uh. It kinda reminded me of watching a movie and definitely not interacting with it at all. Oh hang on, there are some references to memory in the intro, well WHOOP DE DOO LET'S GIVE IT A THOUSAND SCORES shall we it definitely says the word 'memory'!. Not good enough.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     18/100''&lt;br /&gt;
&lt;br /&gt;
Nope, I'm not buying it. I can imagine what you were aiming for here but you trod a tight line with the theme and you fell flat on your face. Haha! you fell on your face! That's funny!&amp;lt;br&amp;gt;&lt;br /&gt;
The title screen and intro were about the only things that had anything to do with memory at all, you can argue to me that the game itself is 'in the past' but it's not really relevant, it could just as easily have been in the future (were it not said that the fog came before). Replace the words 'That this fog has been here before' with 'That this fog will be here in 20 days'. And the game suddenly becomes the opposite of memory! That's how shallow the theme is. Shallow, like a fox.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  31/90''&lt;br /&gt;
&lt;br /&gt;
It's not got a lot to it, it mainly consists of poorly made slider puzzles, and a little bit of thinking. If you don't belive me let's break it down.&lt;br /&gt;
&lt;br /&gt;
The whore - An interesting Slider puzzle, and a cock, oh boy!&amp;lt;br&amp;gt;&lt;br /&gt;
The Liar - A little logic, and, wait for it... TWO KEYS, but here's the catch , they open their OPPOSITE DOORS! Hah, that fooled me for a while!&amp;lt;br&amp;gt;&lt;br /&gt;
The Thief - A terrible Slider puzzle&amp;lt;br&amp;gt;&lt;br /&gt;
The Murderer - Ran out of ideas eh? This was about as fun as a minefield&lt;br /&gt;
&lt;br /&gt;
The final confrontation - Well, I shouldn't need to say anything.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  39/70''&lt;br /&gt;
&lt;br /&gt;
Yeah okay, I'll give you some leeway here, I understand that you went for the retro look and I can appreciate that, although the graphics are pretty simple the colours are excellent, and the char editing, when done, was sufficient. I liked the general mood the colours created. Board layout was a bit confusing at times but that's probably intentional, so fair enough. Retro perhaps, but I like some graphics.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  30/60''&lt;br /&gt;
&lt;br /&gt;
Basic and to the point, but functional and flawless. Whilst I'm not inspired to do great things after playing your game, I appreciate the fact that it works perfectly from start to finish, and to me that added polish is worth a lot of points. There's nothing else to give here though&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  34/50''&lt;br /&gt;
&lt;br /&gt;
For a little puzzler game lacking gameplay like this one did, it's generally up to the story and development to carry it, this game did so only so much successfully, it's a shame that the story was quite blunt and undeveloped. But to be fair, it was relevant and to the point, it did what it set out to do and you can't expect much more right? sort of.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  1/30''&lt;br /&gt;
&lt;br /&gt;
Some people might find Built in MZX sounds 'omg retro' and 'cool'. I don't. I think they're annoying and dumb. Unless they're done very well and somewhat subtley, exactly like they weren't here.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   153 / 400'''&lt;br /&gt;
&lt;br /&gt;
Below Average&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
I kind of wish I could give this game more, I liked it's style and I thought it was quite original for a doz entry. But, let's be honest, it's a game competition, and this game had about as much gameplay as a baking tray which refuses to play games. I did honestly like some aspects of this game so don't take that score as my absolute opinion on it.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
'''Team 12984 - [[Irreplaceable Memory]]'''&lt;br /&gt;
&lt;br /&gt;
- Title screen -&lt;br /&gt;
&lt;br /&gt;
Wow, nice title screen, I feel like I have to dedicate a subsection just to it! ok, there we go.&lt;br /&gt;
&lt;br /&gt;
- Moving on -&lt;br /&gt;
&lt;br /&gt;
The music that greets you on the title screen is nice, very nice, it includes organs and pianos, probably the two instruments that most shout 'memory' to me. Well done! It looks the part too, those moving clouds are all MEMORY INDUCING, I'm in awe of that title screen. Let's press P shall  we?&lt;br /&gt;
&lt;br /&gt;
- No seriously -&lt;br /&gt;
&lt;br /&gt;
Come on, press P you git, stop staring at that... entrancing pink clouds... soft music... oh god I can't stop, it haunts me&lt;br /&gt;
&lt;br /&gt;
Ok, I'm done, I've pressed P and am currently watching the intro as I write, I like the text. it's all Big, It's totally using up lots of char space though, unless there's some magic robotic being used here, I've lost track of what robotic can do these days, I must admit, I'm a more traditional 1 char text man!.&lt;br /&gt;
&lt;br /&gt;
This story is pretty intriguing, you can't say it's not well thought ou- WHOA, those are some purdy cutscenes there, although they... aren't really anything. They LOOK good sure, but uh, you know, you might as well have drawn some bumble bees or a kettle or something, in fact i'd rather you drew a kettle, can you draw me a kettle like that? I'd be grateful.&lt;br /&gt;
&lt;br /&gt;
What a sinister plot, you seem to be an absolute asshole, actually, what are you? oh man, mysteries. Okay, this music is even better, oh man I'm excited about this game. That's an odd name she has, why couldn't she just be called 'Jim' or something. Odd. Anyway, the musics stopped, the background fades, the text is long, the quest... goes on. Uh oh, the evil musics are on, why is the background red? This isn't fun anymore! I Suddenly feel depressed!&lt;br /&gt;
&lt;br /&gt;
- ACT 1 -&lt;br /&gt;
&lt;br /&gt;
Man this is a lot of dialog huh, you'd almost imagine there's a game attached... Oh god, it keeps going, LET ME KILL THINGS ALREADY. Oh man now there's some girl talking about her life, this is starting to sound like a harry potter soap. Any minute now, I'm going to be Thaumaturging the shit out of stuff.&lt;br /&gt;
&lt;br /&gt;
Or not. The music changes back to angst mode again. I admit I quite like this tune as well for an eerie one but. WHAT THE HECK ARE THOSE?. That's more like it. Blaa blaa blaa blaa blballalblab.&lt;br /&gt;
&lt;br /&gt;
Ok! Now there's some combat, now I read before I played this game on digimzx that Z X and C are all keys you'll need as well as H, although it doesn't mention them in game (tsk). So i go through this zone, killing stuff, It's quite fun, I've had more fun but I've definitely had less fun, the music and sounds are above average certainly, the graphics are impressive, and the attacks look good. I can't really fault anything here.&lt;br /&gt;
&lt;br /&gt;
Until I kill everything.&lt;br /&gt;
&lt;br /&gt;
Oh god, now what? NOW WHAT? I'M STUCK. What do i do? I try everything I can, I spend a good 5 minutes blasting walls and hacking things, to no avail, I'm trapped in this room and there's nothing I can do. I save and quit.&lt;br /&gt;
&lt;br /&gt;
The editor is little help :/ I can't really understand most of this coding and the fact it's all on few boards just confirms my fears.&lt;br /&gt;
&lt;br /&gt;
Upon further inspection I discovered that there was indeed, only one level! gasp! Who would have thought it, with an introduction that long I suppose it's only logical. You can't have an HOUR of words and a game.&lt;br /&gt;
&lt;br /&gt;
seriously, lots of words... too many, Anger.&lt;br /&gt;
&lt;br /&gt;
Not that they were bad. An interesting story to say the least and I would have been interested to see where it was going.&lt;br /&gt;
&lt;br /&gt;
- Act 2 -&lt;br /&gt;
&lt;br /&gt;
Act two was great!&lt;br /&gt;
&lt;br /&gt;
There was no act 2&lt;br /&gt;
&lt;br /&gt;
- Act 1 again -&lt;br /&gt;
&lt;br /&gt;
The Weapon system had potential to be excellent but it wasn't developed enough. It's a shame because I read the txt file that came with the game and it had some interesting stuff on it. I liked the ZAPPER weapon. Some of the enemies looks funky, I especially liked the tiny one with the hat, I thought he was cool, there's really not much else to say about this game I'm afraid. Good graphics all around, but little to support it. There's about 2 minutes of repetitive gameplay in there, it's good gameplay certainly, and if that's what floats your boat then go for it, but not me.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     61/100''&lt;br /&gt;
&lt;br /&gt;
It definitely looked like it was going places. I would have been interested to see where it WAS going. The game definitely has a sort of 'memory' feel to it. The music helps considerably here. The plot is obviously, quite heavily memory orientated, but it stops there, had this game progressed fully I could have seen it getting as high as 90 here.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  18/90''&lt;br /&gt;
&lt;br /&gt;
What's there is definitely fun, but unfortunately, you have to go through seven years of dialogue for two minutes of sword slashing. It's not worth it. Would have been good, were it longer&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  45/70''&lt;br /&gt;
&lt;br /&gt;
What's there was good, obviously there just wasn't enough of it. I always say that a lot of consistently decent graphics is better then a sparse helping of excellent graphics. The graphics, make no mistake, were excellent for a megazeux game, but there wasn't enough to warrant a higher score. The dialogues even looked better then some games, the game itself was spectacular, arguably.&lt;br /&gt;
&lt;br /&gt;
Screw me that title screen was hypnotic.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  28/60''&lt;br /&gt;
&lt;br /&gt;
I've heard that the combat has been called 'clunky'... I don't think so, it seems VERY smooth to me and non buggy. I was impressed with how solid it was.&lt;br /&gt;
&lt;br /&gt;
The reason there are so few points here, is because the actual game itself, is just too short. And I can't really take much more off gameplay!&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  21/50''&lt;br /&gt;
&lt;br /&gt;
Would have been good, had it got a bit further, as it stands, it's half a story, and therefore, it sucks.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  25/30''&lt;br /&gt;
&lt;br /&gt;
Very appropriate and nice sounding. I doubt it's original though so not maximum points here. The sounds were excellent&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   198 / 400'''&lt;br /&gt;
&lt;br /&gt;
Decent&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Again, the score is quite generous, I would have pegged it around 180ish, but, then again, some points of it were just excellent. It's always confusing when a broken game completely outscores lesser, complete games, but sometimes technique just wins through, and this game oozed quality. Just... very little of it.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
'''''Team 21079 - [[Fuzzy Loses His Memory|Fuzzy loses his memory]]'''''&lt;br /&gt;
&lt;br /&gt;
- Load 'er up -&lt;br /&gt;
&lt;br /&gt;
The first thing you have to notice when you load up this game is that it feels very 2000. The all-dominating bassline and the poor sounding Orchestralhitguitars have that mid schoolish effect to them. Mid school? Is that a word? It is now!. The title screen looks, simple enough, not very exciting really. Apparently this 'fuzzy' has lost his memory. Why should i care? do i care? I don't know.&lt;br /&gt;
&lt;br /&gt;
- Upon starting... -&lt;br /&gt;
&lt;br /&gt;
Buhh buhh story, simple enough, can't complain I guess. I like the way you have to go through the points IN NUMERICAL ORDER, why is there a numerical order, and WHAT HAPPENS IF I DO NOT go in numerical order? This game is already intriguing. Also, in this game, 'reach altitude above ground level' has replaced 'jump'. Eerie music! :O&lt;br /&gt;
&lt;br /&gt;
- Let's get on with it -&lt;br /&gt;
&lt;br /&gt;
Ok so we're on an island, with what I can only assume is lava or canned spaghetti hoops surrounding it, either way it looks quite hostile, true to the description we have 5 sites of interest, each with NUMBERS. Just for a HILARIOUS laugh I'm going to try #4 first, let's see what happens!&lt;br /&gt;
&lt;br /&gt;
Ahh ok, so you CAN'T you say. Well, I'm feeling that this kind of defeats the point of a world map. You can't seem to go anywhere apart from the first location, which, although numerically and logically sound, does not provide a very open game experience, The map promised many things but I can only do what it forces me to do : (, better to have forgotten the map altogether, it is no longer a world map, it is now an inter-chapter-restroom. Why is the sky purple&lt;br /&gt;
&lt;br /&gt;
- Nivel uno -&lt;br /&gt;
&lt;br /&gt;
Ok, I'm confronted with a standard sidescroller looking thing, I have a 'blaster' apparently and shall use it to blast things indeed, the graphics looks, averageish I guess but I've NEVER been a fan of that kind of fade-blocky graphic style, nice chilling music. Uh oh there's a hole! no matter how much you reach altitude above ground level, you cannot bypass it! You find a charging cell later on which lets you fire, interesting, somewhat original shooter engine. And there is a 'technique' to assist reaching altitude above ground level involving your gun. Oh my, this bu-'technique' (who's intention at creation i somewhat doubt), is rather fun, I just hope they don't overuse it though, it can get kind of annoying, and isn't really all THAT fun let's be honest.&lt;br /&gt;
&lt;br /&gt;
Well, still needing to use the technique, but you find some kind of hat and leave.&lt;br /&gt;
&lt;br /&gt;
- Nivel Dos -&lt;br /&gt;
&lt;br /&gt;
Urgh, I'm less fond of the graphics here, they seem too blended and indistinguishable, the music has gone from good to... mediocre too. I find a page of a journal after more reaching altitude above ground level techniques. The graphics were more distinguishable then I had feared they would be, but the viewport is too small too take advantage of this, it's too confusing in general.&lt;br /&gt;
&lt;br /&gt;
- Nivel Tres -&lt;br /&gt;
&lt;br /&gt;
This really is the worst song I have ever heard. I don't know why someone thought it would be hilarious to make a song with the worst sounding burp ever recorded, disgraceful, I award it negative 4 points. I've just noticed how scarily stupid and easy the enemies are, they pose no threat at all and have all the intelligence of a tractor.&lt;br /&gt;
&lt;br /&gt;
This song really is annoying.&lt;br /&gt;
&lt;br /&gt;
I find a locket.&lt;br /&gt;
&lt;br /&gt;
- Nivel Cuatro -&lt;br /&gt;
&lt;br /&gt;
More upbeat exciting music, I guess. Probably the most fun level so far, but that's not really saying much. You have to find 5 keys for 5 locks, the maze was not bad hence the most fun. The author(s) laid off the reaching altitude above ground level technique for the most part, which was a GOOD move on his/her part. Found a gitbox&lt;br /&gt;
&lt;br /&gt;
- Y la ultima -&lt;br /&gt;
&lt;br /&gt;
More Jumping, avoiding, buhh.&lt;br /&gt;
&lt;br /&gt;
You reach a rocket and touch it, and get in (I assume) and that's the end of the game.&lt;br /&gt;
&lt;br /&gt;
Now, call me crazy, but I have a few questions&lt;br /&gt;
&lt;br /&gt;
a) How did the rocket get into an underground cave?&amp;lt;br&amp;gt;&lt;br /&gt;
b) What good is a rocket in an underground cave? (apparently there's a volcano entry but I DONT SEE IT &amp;gt;:( )&amp;lt;br&amp;gt;&lt;br /&gt;
c) Ok so fuzzy lost his memory, and found a... ship...&amp;lt;br&amp;gt;&lt;br /&gt;
d) I understand that you find objects which somewhat jog your memory, but at the end of the game you don't seem to remember much more then when you started, You remember that you have a family, and you play guitar. Whoop! Now you just have to remember how to fly a spaceship right?&amp;lt;br&amp;gt;&lt;br /&gt;
e) ARARHAGHAHGRHRAGH&lt;br /&gt;
&lt;br /&gt;
The ending of the story did a little to help advance the plot I suppose, but it's still too basic. I dunno, maybe that's just me&lt;br /&gt;
&lt;br /&gt;
Okay, that's me done here.&lt;br /&gt;
&lt;br /&gt;
The last screen was your typical Doz credits screen, with the obligatory 'hope you had funs!!!11' message at the bottom.&lt;br /&gt;
&lt;br /&gt;
No I didn't&lt;br /&gt;
&lt;br /&gt;
Well that's too harsh, I did sort of I guess, but not as much as you probably thought I had.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     27/100''&lt;br /&gt;
&lt;br /&gt;
No dice, replace the word 'memory' in the title, with 'shit' and you pretty much get the same game. In fact, 'Fuzzy loses his shit' makes a lot more sense. See, he lost his guitar and rocket and everything. You 'remember' things at the end but it feels too much like a slap on job.&lt;br /&gt;
&lt;br /&gt;
There was no real sense of memory in the gameplay or graphics. The restricted viewport somewhat alluded to the theme, and the music helped a little bit (in places), but in general, nope.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  37/90''&lt;br /&gt;
&lt;br /&gt;
Pretty tedious, there's really not a huge amount to do here, it's a sidescroller with one or two types of simplistic enemy, and much too straightforward, I quite liked level 4 but that was about it. The 'technique' got old fast, but they were sensible enough not to overdo it. Kudos for that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  34/70''&lt;br /&gt;
&lt;br /&gt;
Pleasing at times, confusing at others, the colours and graphics did not reflect the theme in any way, the style of art they used is not one I'm too fond of but I've seen it done worse. The forest level was just annoying to decipher. Distinctly mid-range.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  23/60''&lt;br /&gt;
&lt;br /&gt;
Yeh, well, there were no bugs to speak of but there wasn't really the possibility for anything this simple to go wrong, the jumping technique was an interesting touch but nothing amazing.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  27/50''&lt;br /&gt;
&lt;br /&gt;
Enh, I know where you were going, but you didn't develop it nearly enough, you probably would have got more points if you just left out the plot altogether and went for more gameplay. The fact that you did try to develop the story, unsuccessfully, sets you back a bit.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  19/30''&lt;br /&gt;
&lt;br /&gt;
Great at times, annoying at others, no sounds to speak of.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   167 / 400'''&lt;br /&gt;
&lt;br /&gt;
Mediocre&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Destroyed by it's theme score, If this had been in the specific topic, arguably could have reached 220+, feels like it deserves a little more.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Team 32427 - [[Dislocated Memories]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- Back to roots -&lt;br /&gt;
&lt;br /&gt;
The first thing you have to notice about this game is how well it takes MZX back to the old days when smileys were cool, and slider puzzles could be mixed in with normal puzzles, and there were silly boss fights, and you had all sorts of different engines all over the place which all come together to make one game.&lt;br /&gt;
&lt;br /&gt;
This game wins the 'Most MZXy' game award, a special award given only to those games that remind me of being a kid and playing [[Daniel Balkin's Second Strike|Daniel Balkins Second Strike.]] Hoo boy.&lt;br /&gt;
&lt;br /&gt;
- Anyway, to business. -&lt;br /&gt;
&lt;br /&gt;
This game consists of 3 'levels' with bosses and then a final bossfight. The levels get progressively harder and more complex which is a good thing for any MZX game. Basically what happened was, you were 'inserted' into someone's memory, and then you are able (using some imaginary technique, hopefully) to kill them from inside, sort of... I'm not quite sure what exactly happens, but either way people die.&lt;br /&gt;
&lt;br /&gt;
This is one of the longer games of the DoZ and provides quite a bit of gameplay, unfortunately this game has a couple of major drawbacks.&lt;br /&gt;
&lt;br /&gt;
- Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
- Variation&lt;br /&gt;
&lt;br /&gt;
Emphasis on variation there. If they say variety is the spice of life, then this game was the blandest thing on the menu, or in the city for that matter, imagine scampi on toast, that's what we're talking. It's not that the game was boring, it's just that you felt like you were doing the same thing oover and oover again. the sequence of events was different (like the order things progressed in, such as in the first level where you steal the key, enter first class, crash the plane... etc... ) But it always ends up in some ridiculous bossfight where bullets are flying around all over the place and you really have no idea what's being shot at and what's shooting and &lt;br /&gt;
where these bullets are coming from, everything seems to have a gun. I did chuckle at the boss scene in the second level, where all chaos erupts and things start screaming, but that's just what this game was, it was unorderly in the bossfights and they were just kind of dull.&lt;br /&gt;
&lt;br /&gt;
Take the rooftop fight for instance, I don't know what the creator(s) were thinking but that's just a horrible idea for a fight, it took me like seven hours just to hit her once. And as if that wasn't enough, the final bossfight was essentially all the bossfights all over again. Wheefun!&lt;br /&gt;
&lt;br /&gt;
- Scampi please -&lt;br /&gt;
&lt;br /&gt;
There was a little variation provided, at two times in particular. First of all, the slider puzzles used in the club area, were pretty good, and provided much needed relief from shooting everything that moved (and being shot at by everything that moved). And the silly sidescroller bit, which, was terrible, was also a worthy addition to this game's arsenal of excitement.&lt;br /&gt;
&lt;br /&gt;
- Phin beats -&lt;br /&gt;
&lt;br /&gt;
The music was all decent, but it's all songs that have been in the MZX circulation for a while now. Perhaps this a good thing, maybe that's why I'm reminiscing about 1998.&lt;br /&gt;
&lt;br /&gt;
Did anyone else think that their choice of club music was a retarded idea? It sounded like the most depressing night club. I wouldn't want to even be NEAR it let alone go in. God that club looks like a depressing place.&lt;br /&gt;
&lt;br /&gt;
- Storylines -&lt;br /&gt;
&lt;br /&gt;
The story in this game was pretty average, it had a fair little twist on the end but nothing unexpected. Going to prison for 20 million is probably not something you'd want to 'roll with' though, since... you know... That's life without parole right there. Although I guess when you can kill someone just by... remembering them or something, it's all good.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     50/100''&lt;br /&gt;
&lt;br /&gt;
Yeh, I guess. It's so-so. The theme is interwoven into the plot and, to a lesser extent, the gameplay. But the graphics and sound do not reflect the theme at all.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  41/90''&lt;br /&gt;
&lt;br /&gt;
There's a lot of it, so it gets more then it would at first glance, but most of it is quite poor. The slider puzzles were probably the most fun thing in the game, and I've done a million in my time. THe bossfights were just bad.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  29/70''&lt;br /&gt;
&lt;br /&gt;
Tacky, yucky, sickly, ducky. They weren't anything to be proud of, in fact... I'd put them up for adoption, hopefully you'll get some return (but don't bank on it). What I mean to say is that they are bad.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  14/60''&lt;br /&gt;
&lt;br /&gt;
Nothing very new or amazing. Or fairly new or amazing. Or remotely new or amazing. Or amazing. Or impressive... Continue as you wish&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  37/50''&lt;br /&gt;
&lt;br /&gt;
Good enough! It gets the job done, and in a game with poor graphics and only moderate sound. It needs the plot to carry it some of the way.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  14/30''&lt;br /&gt;
&lt;br /&gt;
Nothing we haven't heard before, and most of it didn't really fit anywhere, it had nothing to do with the theme either. And god, that nightclub, disgraceful.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   185 / 400'''&lt;br /&gt;
&lt;br /&gt;
Allriiiiiight&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
MZX at it's finest. Nothing that will be stuck in your memory. But not a complete waste of 15 minutes. A good length of game which was let down because it's not 'hip' and 'with the times'.&lt;br /&gt;
&lt;br /&gt;
That and competition is much more fierce this time.&lt;br /&gt;
&lt;br /&gt;
Seriously, last DoZ I judged was an absolute disgrace.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 34249 - [[Fritz Blitz]]&lt;br /&gt;
&lt;br /&gt;
- Wow -&lt;br /&gt;
&lt;br /&gt;
What can you say about this game that I'm sure you haven't said anyway. It's shines of excellence all around. There aren't really any flaws with it apart from it's short length. Let's start at the beginning.&lt;br /&gt;
&lt;br /&gt;
- From the start then -&lt;br /&gt;
&lt;br /&gt;
The title screen looks good. It's just a simple ansi art picture (All the game is ANSI art actually) but, it's very appealing it looks very gamey, you can tell quite quickly that this game is probably not going to be about memory. I like the flight goggles :D. The music is also very fitting here.&lt;br /&gt;
&lt;br /&gt;
- No intro -&lt;br /&gt;
&lt;br /&gt;
The game thrusts you straight into the thick of things, which, for a game of this nature, is probably not a bad thing, it's a shoot em up, and as such you wouldn't really expect much of a story, it doesn't rock the boat here then, and has about as much story as a Mr.Men book. But let's not get off track, this game doesn't need a story for what it is.&lt;br /&gt;
&lt;br /&gt;
The first thing you have to notice about this game, is just how smooth it is. There has never been a shooter made in MZX that actually felt like a shoot em up, it just can't be done with small 1x1 graphics. This game brings you large sprites, which seriously help the fun factor, it's actually possible to not be perfectly aligned with a target and still hit it! The vast majority of enemies were bigger then you.&lt;br /&gt;
&lt;br /&gt;
The graphics, are, not the sharpest, nor the crispest graphics around, after all, they are only ANSI art, there is very little room for detail here, so there aren't many points on offer for that. What this game includes in mountainloads though, is smoothness. Yes the graphics aren't particularly detailed, but they're Big, they're bright, they're slick and there isn't a single graphical glitch to be seen. You can't help but be impressed by the visual aspect of the game, even if the detail is way below the standards set by a couple of the other games. It's one of the only MZX action games that has a 'frantic' feel to it.&lt;br /&gt;
&lt;br /&gt;
The cutscenes are nice enough, nothing amazing, but the ansi art is well done.&lt;br /&gt;
&lt;br /&gt;
- How does it play ? I'LL TELL YOU HOW IT PLAYS -&lt;br /&gt;
&lt;br /&gt;
Beautifully, it's as smooth as silk and has no flaws whatsoever, it's slightly short and lacks some more advanced features that you could have hoped to see in a shoot em up (Things like power ups)&lt;br /&gt;
but, it's still one of a kind, and hopefully this genre will get a bit more attention from now on,  I'm sure it will.&lt;br /&gt;
&lt;br /&gt;
It's pretty straightforward, You fly around with the keypad, and Z unleashes all hell on your&lt;br /&gt;
screen. The game has an excellent difficulty curve and is neither too hard nor too easy (Some of the bosses are excellently designed, like the 4th one). The length of the game leaves something to be desired, and there isn't a HUGELY noticeable difference between the two difficulty levels, but that's not a grave error.&lt;br /&gt;
&lt;br /&gt;
- Phat beats -&lt;br /&gt;
&lt;br /&gt;
The sound is definitely above average for a Doz game. The music fits perfectly to the game (It sounds like it COULD be originally tracked for the game but I'm going to guess not) The sounds, whilst simple, are adequate and get the point across.&lt;br /&gt;
&lt;br /&gt;
- So what's the catch? -&lt;br /&gt;
&lt;br /&gt;
It's not often a game this ambitious and unorthodoz comes in a doz that is not hampered with bugs, this game defies that trend, it is polished in almost every way. It's not PERFECT of course, but then again, nothing is. The story leaves something to be desired, it's true that for a game of this &lt;br /&gt;
genre the story is not an essential part of the game, but I'm sure with a little more time and thought a more involving storyline could have been created (revenge for your parents, anyone?) It's adherence to the th eme, is solid, but nothing amazing.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SPECIFIC TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     15/20''&lt;br /&gt;
&lt;br /&gt;
Adheres very tightly to the theme of flying, but doesn't do anything creative or exciting with it (you fly)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  87/120''&lt;br /&gt;
&lt;br /&gt;
The highest gameplay score I can remember giving any game in a doz. Let's be honest, this is a FUN waste of 5 minutes. But that's the problem, it's only 5 minutes. If this game were longer it could have got a fantastic score, as it stands, it's merely 'very good'.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;nowiki&amp;gt;  59/90''&lt;br /&gt;
&lt;br /&gt;
Not the most detailed graphics out there, but they were SMOOTH, you just can't substitute functionality right? The ansi art cutscenes were cool, and the backgrounds were sometimes inspiring, the enemy sprites were hit and miss, but the player sprite seemed a bit simple. The bosses looked good.&lt;br /&gt;
&lt;br /&gt;
THe most important thing is that they were nice to look at.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  72/80''&lt;br /&gt;
&lt;br /&gt;
Fantastic, It's flawless and one of a kind, you rarely see that in a megazeux game, yet alone a DOZ game. It was an ambitious project that just happened to come off right.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  25/50''&lt;br /&gt;
&lt;br /&gt;
I'll give this game mid-range in the story category since it's obviously not meant to have any regard to plot. It's a mindless action game and it's not ashamed of that. The story that was there, was sufficient, but weak.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  33/40''&lt;br /&gt;
&lt;br /&gt;
Very lively and fitting music, good sound effects.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   291 / 400'''&lt;br /&gt;
&lt;br /&gt;
Very Good.&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Very impressive, but you can always do better. I'd be amazed if this game wasn't in the top two. Easily the most fun I've had playing megazeux for a while, unfortunately it was short lived.&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 48625 - [[HELLO KITTY DOZ|This is Greg (And hello kitty)]]&lt;br /&gt;
&lt;br /&gt;
- Uhrr -&lt;br /&gt;
&lt;br /&gt;
Well, The title screen gave me mixed feelings, on on side, this WAS [[veloso|greg]], GREG was in the game, how could I not be at least somewhat excited about what lay in way. Also HELLO KITTY. This was a partnership with truely tremedous potential. That was all I really got from the title screen though. At first it appeared like it was just going to be some joke entry (especially when you press P and start on the title screen). But the team explains that they purposefully didn't make the game start properly (for some reason) and instead wanted you to waste your time loading it up yourself, where upon loading Hello kitty laughs at you, or wishes you luck, they're probably the same.&lt;br /&gt;
&lt;br /&gt;
- Why thanks -&lt;br /&gt;
&lt;br /&gt;
So the game tells you to start on 'level 1'. That makes sense. Most things begin at level 1. If they didn't they would begind somewhere else and that wouldn't make sense at all. If there's one thing that 'Fuzzy loses him memory' tought me it was that jumping was actually called reaching altitude abo- I mean, it was that all games must begin on level 1. DEFINITELY not level 4. Level one is certainly, where they begin. Armed with this knowledge I entered the pit of level 1.&lt;br /&gt;
&lt;br /&gt;
- Level 1, and onwards -&lt;br /&gt;
&lt;br /&gt;
What I was greeted with shocked me temporarily. BRIGHT colours, BALOONS, HELLO KITTY, and outrageous music. The graphics were, for the lack of a better phrase, unnerving yet very pleasing. They were clear, crisp, and nice to look at, there's nothing to complain about graphics wise, at least, apart from the lack of many different things.&lt;br /&gt;
&lt;br /&gt;
The gameplay was... interesting, the first thing that has to be said is that this game had no challenge at all, it was the easiest, most challenge..less thing I have played all DOZ (Yes I do appreciate the gravity of that statement) and this is saying something. This is not to say it wasn't somehow... fun.&lt;br /&gt;
&lt;br /&gt;
I must admit I was smiling like a madman whilst playing this game, something about running around with hello kitty, catching balloons and inflating your own just got to me. But I think with a little tweaking this game could have been great. (Perhaps a limited amount of times you can inflate? Maybe you can pick up extra red balloons or something, you could definitely make a &lt;br /&gt;
game out of that, I think you should. Do it)&lt;br /&gt;
&lt;br /&gt;
But alas, the game is short lived, there is not much to do in a game which the author admits (in the understatement of the year) is short. There is about 2 minutes of excitement in this game tops. A shame because I was really getting into it when it stopped.&lt;br /&gt;
&lt;br /&gt;
- Hang on -&lt;br /&gt;
&lt;br /&gt;
What the hell was up with that music, you can't do that, not to me, that was vicious.&lt;br /&gt;
&lt;br /&gt;
- Moving on -&lt;br /&gt;
&lt;br /&gt;
Okay so this game was about flight, well, it does that well enough, you fly a lot, definitely, there is certainly lots of flight related things in this game, such as ... balloons. OH and clouds, lots of clouds.&lt;br /&gt;
&lt;br /&gt;
But yeh, this game is incomplete, so is this review.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SPECIFIC TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     12/20''&lt;br /&gt;
&lt;br /&gt;
Balloons steal Greg, you must use balloons to collect balloons. The key factor here being that balloons fly. Had someone not been aware of that, the topic may have confused them.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  25/120''&lt;br /&gt;
&lt;br /&gt;
Oh MAN I was having fun until it ended, that sucks, make more.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  40/90''&lt;br /&gt;
&lt;br /&gt;
Fun, happy graphics, I enjoyed them. There just weren't enough of them. I liked the bright colours.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;nowiki&amp;gt;  37/80''&lt;br /&gt;
&lt;br /&gt;
Hit and miss. On the one hand almost everything was 2x1 basic blocks. Which was very nice, but unfortunately there were a few glitches, sometimes you got caught in the walls, and sometimes half of the balloons would disappear. Nothing fatal though&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  10/50''&lt;br /&gt;
&lt;br /&gt;
Again, obviously not focusing on plot, but this was just silly =(&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  18/40''&lt;br /&gt;
&lt;br /&gt;
I was torn between giving 35 or 5.  so I'll cut it in the middle, but uh... I probably should give you much less.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   142 / 400'''&lt;br /&gt;
&lt;br /&gt;
Poor.&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
I liked where it was going, but there wasn't enough.&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 51976 - [[The Show|It is time to compete games!]]&lt;br /&gt;
&lt;br /&gt;
- From humble beginnings -&lt;br /&gt;
&lt;br /&gt;
It was pretty obvious from the start that i should have been ON MY GUARD for something wacky and unpredictable here. But I have to admit, they got me, they got me good : (&lt;br /&gt;
&lt;br /&gt;
I was staring at the screen for like a minute before I figured out what was happening, and from then on I was just laughing all the way, i wouldn't say laughing maybe but... snorting... or chuckling, or whatever. Anyway, I was amused.&lt;br /&gt;
&lt;br /&gt;
Some of the quotes in that intro had me in stitches. 'Every milisecond we die' practically gave me asthma, and the final choice had me in tears. Obviously I chose correctly, then I got 4/7 in the big quiz. See, I pay attention.&lt;br /&gt;
&lt;br /&gt;
It was hard =(&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SOME SORT OF TOPIC PROBABLY MEMORY)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     10/100''&lt;br /&gt;
&lt;br /&gt;
You have to like remember bits of the dialogue or something&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  5/90''&lt;br /&gt;
&lt;br /&gt;
...You have to like remember bits of the dialogue or something&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  8/70''&lt;br /&gt;
&lt;br /&gt;
Dialogue, oh and a face.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  5/60''&lt;br /&gt;
&lt;br /&gt;
Frown&lt;br /&gt;
&lt;br /&gt;
''Story&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      5/50''&lt;br /&gt;
&lt;br /&gt;
Man, the goliath is a cool name&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  5/30''&lt;br /&gt;
&lt;br /&gt;
What a queer song&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   38 / 400'''&lt;br /&gt;
&lt;br /&gt;
oh no&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
THE GOLIATH&lt;br /&gt;
&lt;br /&gt;
---------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 65131 - [[Witch Switch]]&lt;br /&gt;
&lt;br /&gt;
- Tsk tsk -&lt;br /&gt;
&lt;br /&gt;
Ohh dear, what happened here? Oh wait, I know.&lt;br /&gt;
&lt;br /&gt;
This game, let's be honest with ourselves here, started off terribly in every way, it was looking like, so far, the worst contender in the doz so far, and then, basically, it sort of got back on track, then not.&lt;br /&gt;
&lt;br /&gt;
- From the beginning -&lt;br /&gt;
&lt;br /&gt;
Ok, first of all, that's a pretty dumb title screen. It's 'animated' somewhat and looks Zztesque but it's pretty cheap and does not represent the game well at all. I quite liked the Speaker sound effects though! (For once).&lt;br /&gt;
&lt;br /&gt;
Ok, so, upon pressing 'p' you are presented with the worst drawing ever. No kidding, this drawing makes the plague look good. I don't know what it's meant to be but it looks like a skull next to a waterfall. Anyway, enough of that, the story is revealed before you in terrificly bad ANSI art (Oh hey apparently it's... a statue), apparently you're a witch who's powers have been switched with another witch, hence the title of the game, ok then! Seems straightforward enough, there are probably a few ways this game could go and they could all be good, let's see what they do with it.&lt;br /&gt;
&lt;br /&gt;
What happens next is a MZX catastrophe. We have a 1x2 top view engine. Okay, that can't be too bad right? Wrong. VERY wrong.&lt;br /&gt;
&lt;br /&gt;
The engine is... 'buggy' to say the least (and trust me, that is the least), if you happen to press to arrow keys at once (As I'm sure many people did when playing this game, but if they don't then ok it's my fault), then your head multiplies, it becomes the undominable head, there is no defeating your head, your body is frail but the head always lives on. Plus, what the hell &lt;br /&gt;
is up with that body anyway, you look like a skeleton in a skirt. Anyway, you go around zapping little blobby things (which are actually kind of cool looking), I say zapping but... well you get the idea, you don't really zap as much as swat. Oh and you can only swat left and right, with A and D respectively. Seriously, this has to be the worst made thing I have seen in MZX for a while, and there's a lot of bad things in MZX.&lt;br /&gt;
&lt;br /&gt;
I... I don't know when I hit the things I was attacking, or when they hit me... every so often either you or they would go red, and they would seemingly die at random times. There is no logic to this combat at all :(.&lt;br /&gt;
&lt;br /&gt;
I'm sure I'm getting this point across to you that this engine and gameplay is horrific, but let's move on to the graphics. Heh, well, load up this game now, and look at the scenery. Please, just do it, do it for me, I want you to be looking at it while I say this.&lt;br /&gt;
&lt;br /&gt;
This is terrible.&lt;br /&gt;
&lt;br /&gt;
I have no idea where you're meant to be, it looks like some sort of forest building hybrid. The walls are flourescent green and the floor is brown, the background is a darker brown. The detail on the floors and walls, I'm not sure if you've noticed, is dots. Stare at that floor for a while, doesn't it look funny. I'm honestly not sure how to express my feelings on this floor. This floor not only killed the cat, but chopped it up into little pieces, and ATE it. The wall looks a little better, but that's it. Apart from these walls and floors, the enemies and yourself. There is no single other thing on the board apart from your objective in each level, which is, handily enough, a mushroom both times.&lt;br /&gt;
&lt;br /&gt;
The next level is the same, but has different colours and music! Also notice that the walls on the top are... inverted? is that the word? The wall begins at the top and ends at the bottom, or... something... those walls defy logic. It kind of looks like your not looking at it from a top down&lt;br /&gt;
perspective but that you've... looped over the top and are looking at it from behind somewhat... I don't know. It's stupid. I hate these boards.&lt;br /&gt;
&lt;br /&gt;
You have to find a mushroom again.&lt;br /&gt;
&lt;br /&gt;
- And then -&lt;br /&gt;
&lt;br /&gt;
Then after that, a miracle happens. The game suddenly becomes half decent!. You get a text box telling you the new controls, which was a little discouraging, but what followed was pleasing. Wait how come you can fly? Surely the whole point of the game, THE WHOLE POINT OF THOSE MUSHROOMS ON THOSE HORRIBLE BOARDS  ... oh fuck it I don't care anymore :-(&lt;br /&gt;
&lt;br /&gt;
These new zones are relatively fun though, and they look GOOD. Not like, amazingly good, but perhaps it's after what came before that you suddenly become thankful for what you have now, it's like your eyes are suddenly like 'Oh man, that was a close call, We're going to start appreciating all the good things in life'. Either way, you immediately notice that the colours are appropriate, things represent what they actually are, your player character works (and looks pretty funky), and you're not slowly dieing from brainrot.&lt;br /&gt;
&lt;br /&gt;
The gameplay here is, unfortunately, not as fun as it could have been. Sure it's definitely got SOME gameplay now, but there's no real challenge (Until the airship), the razor wire on the trees was just about the only tricky thing in the forest level. Your special attack, pretty much does less then your regular one (it freezes them for like, a second), the flying engine is pretty fun, but, wasn't tested well enough in the levels, had you lost life for hitting trees or things it could have worked really well, but you can just sort of maneouvre past them after slamming into obstacles. Nevertheless, there's a somewhat original engine, and that counts for something. The forest level is completed all to easy.&lt;br /&gt;
&lt;br /&gt;
I haven't mentioned so far that the music in this game is pretty nice, I doubt it's original but it sounds good and works for the game's atmosphere.&lt;br /&gt;
&lt;br /&gt;
The airship level is a little more fun, but only a little. There is some challenge in getting past those sliding guns and opening the doors, but it can only entertain for so long, and once you're done with that, the game is over. Oh well, I don't really think it was going anywhere anyway.&lt;br /&gt;
&lt;br /&gt;
The final message sums up this game pretty well! It has like a million spelling mistakes and the border of the text has overwritten some of the letters creating even more spelling mistakes. It's coloured in the worst way possible and is just annoying to read. Apparently I am to be thanked for making 'this fellow' appreciate fun teammates. Well, good, I rock like that.&lt;br /&gt;
&lt;br /&gt;
Whoever this is however, is not.&lt;br /&gt;
&lt;br /&gt;
Don't say you were never warned : )&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
(Editor's note: Shloob made a slight mistake. He graded this game based on the Memory theme, which&lt;br /&gt;
is, upon retrospect, I'm sure he'll feel very dumb about. He's incommunicado for several weeks, so&lt;br /&gt;
to fix it, I'm just going to reweight his scores, including the Theme score. This does seem a little unfair, but the score should be relatively what Shloob intended. I apologize for any inconvenience.)&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     23/100 (5/20)''&lt;br /&gt;
&lt;br /&gt;
Bleh it was an interesting concept but it didn't really involve memory too much, sure you forgot how to fly and all but that was because you were hit with a potion, or something, not really getting the memory jibe here. The game itself did not reflect the theme at all.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  28/90 (37/120)''&lt;br /&gt;
&lt;br /&gt;
This game goes from like an X- to a C+, The first stage was ridiculous but the second one, still, unfortunately, was average at best.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  29/70 (37/90)''&lt;br /&gt;
&lt;br /&gt;
Same as above except it goes up to a B+, the graphics in the second area were really quite good. Not really reflective of the topic in any way though.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  17/60 (23/80)''&lt;br /&gt;
&lt;br /&gt;
Bleh, the engine in the second half was good and warrants about 15 on it's own, but... come on... I don't even have to say it.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      21/50 (21/50)''&lt;br /&gt;
&lt;br /&gt;
Could have gone places, didn't&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  17/30 (23/40)''&lt;br /&gt;
&lt;br /&gt;
Nice music all around, unfortunately music is only an accopaniment to the game itself, and in the first stage, although there was nice music, there was no game. In the second stage the music did help quite a bit. The sound effects that were there were good also. One point for the speaker effects on the title screen :-)&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   135 / 400 (146/400)'''&lt;br /&gt;
&lt;br /&gt;
Very Poor&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Well what did you expect? Not only was the game hampered for obvious reasons but there was very little attachment to the theme, which will kill you on the general topic.&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 77665 - [[Relapse]]&lt;br /&gt;
&lt;br /&gt;
- Ohh... er -&lt;br /&gt;
&lt;br /&gt;
The title screen is one of those ones where it could be hiding a really good game or a really bad one, you just can't tell, I was somewhat hopeful when I loaded up this game. Here is an account of my first game, written as I am playing it.&lt;br /&gt;
&lt;br /&gt;
- Chapter 1 -&lt;br /&gt;
&lt;br /&gt;
This house looks terrible, I'm sorry, it really is. It's a bunch of lines with black background everywhere. The house is apparently empty (when it is blatantly not, there was a small bear in the corner of a room somewhere).&lt;br /&gt;
&lt;br /&gt;
I see I am a smiley, I can pretty much assume that the whole game is going to look this poor, hopefully it can develop a good plot or have some good gameplay to compensate (I'm not very hopeful about this but enhhh...' Anyway.&lt;br /&gt;
&lt;br /&gt;
Okay, I'm slightly hopeful, having just seen some kind of flashback about you killing some girl, (apparently you are a total bitch!) but then feeling bad about it. The plot seems like it could be going places, the gameplay, so far has consisted of moving around a little bit, and then pushing something into a blue zone, bleh. The graphics, oh god, they're just horrible, I thought that was a beach or... something then you're on this brown square... I ... I Don't know what that brown square&lt;br /&gt;
is, or how you got onto it, apparently you pushed her into the sea from the brown square but... the&lt;br /&gt;
square's on the beach bit... you saw her splash into (I think) water with bubbles... but then she's dead on the beach bit? I dunno, I don't want to think about it. Moving on&lt;br /&gt;
&lt;br /&gt;
Ooh, bits have appeared in the house that weren't there before, I'm getting good vibes about the plot here.&lt;br /&gt;
&lt;br /&gt;
... oh MAN this is a fucked up plot right here. I'm loving what this game is doing with the story, and how they do it... holy crap your dead daughter just rose up from the ground. This is freaking me out right here.&lt;br /&gt;
&lt;br /&gt;
- I'm finished! -&lt;br /&gt;
&lt;br /&gt;
Wow... That was fantastic. I'm almost sad that the game is over!. The game was short but sweet... In a way.&lt;br /&gt;
&lt;br /&gt;
I can't express enough how involved I was in the plot, even if it was for just like 5 minutes, I've never been that attentive to the screen. I am impressed.&lt;br /&gt;
&lt;br /&gt;
The graphics suck, let's get that straight. The gameplay is almost non-existant. Hell, this may as well just be an interactive short film. But I was stuck to it. It just could have been so much MORE. And I wish it had been. What little sound was there was very good. Very moody, very ambiental. The song at the end was exactly what it should have been. It just... sound could have made that game so much more. And the team squandered an opportunity to turn what is merely 'good' into something excellent, and that saddens me :-(.&lt;br /&gt;
&lt;br /&gt;
Seriously man, the graphics are terrible. I could have cried if it wasn't a bunch of smiley faces going around murdering each other and such.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     71/100''&lt;br /&gt;
&lt;br /&gt;
Yes YES -YES-. This is a game that uses the theme well, in almost all aspects of the game (except graphics... kinda... it uses the theme of 'terrible' here), but that's not to say the visual aspect didn't help. In some ways, I suppose, my earlier comments about the house being just lines, grey, dark and with a black background... I suppose in retrospect that helped the game hugely. Yeh, I'm pretty sure it did. That doesn't excuse the beach areas and the outside for looking like a landfill though. The music was themed to the max. And the plot... well... obviously.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  9/90''&lt;br /&gt;
&lt;br /&gt;
The game falls apart in two places, here, and graphics. The gameplay score is ridiculously low here as... you guessed it, it's not a game. A game implies challenge, a game implies a way to win and a way to lose. This was non-linear the whole way through (at least in pacman there were TWO possible &lt;br /&gt;
endings to the game).&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  11/70''&lt;br /&gt;
&lt;br /&gt;
Worst of the doz, and clearly. But in a way, somehow fitting... I don't know... they do kind of stick in my memory.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  10/60''&lt;br /&gt;
&lt;br /&gt;
Very little robotic of any kind, but what was there was flawless.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      35/50''&lt;br /&gt;
&lt;br /&gt;
The way the story develops was novel, I hugely liked the way more items appeared on the table the more you remembered, an excellent idea. The game was too linear and too... short to get anything higher then this though.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  15/30''&lt;br /&gt;
&lt;br /&gt;
The two music pieces that were there fitted PERFECTLY (and it was just a piano!) these could very well have been originally made, and if so, well done!, but that's besides the point. There were only 1.5 songs, and no sound effects to speak of. Could have been so much more had you played your cards right. The silence though, was never going to be a bad thing.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   151 / 400'''&lt;br /&gt;
&lt;br /&gt;
Poor&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
This game was probably the most 'stand apart' game of the bunch. I liked it a lot. But, realistically, those scores are accurate.&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 83038 - [[Marty the Mage|Bionic commando!]]&lt;br /&gt;
&lt;br /&gt;
- No messing about -&lt;br /&gt;
&lt;br /&gt;
This game really jumps straight into it, it challenges me to get 80,000. Let's see how I do!&lt;br /&gt;
&lt;br /&gt;
Ok, horribly. In my defence though, I spent like a minute shooting the demons to the left of the starting area which didnt seem to die. :( To the review!&lt;br /&gt;
&lt;br /&gt;
- Dun dudu dun!!! -&lt;br /&gt;
&lt;br /&gt;
Why is this game called bionic commando, I don't see anything remotely bionic or commandoish in this game. It's a fun little timewaster, you spend a little while zooming around on your stick and shooting demons, killing as many as possible before time runs out.&lt;br /&gt;
&lt;br /&gt;
Unfortunately it just wasn't very well done.&lt;br /&gt;
&lt;br /&gt;
It was quite an ambitious task... and unlike some of the other ambitious tasks in this game, (I hate to compare games but...) such as Fritz Blitz, this game felt very shoddy and badly put together. This game was almost everything Fritz Blitz was not. It was buggy, choppy, had poor controls, felt absolutely UNsolid, and just generally annoying to play sometimes. I commend the team on their efforts but they just didn't pull it off.&lt;br /&gt;
&lt;br /&gt;
The sprite collision (or whatever they used) was poor. Bullets would sort of 'overlap' the enemies when they hit and it just looked very messy. The control system, while very novel I'll give them that, was annoying and hard to get used to. The enemies were boring and there was just not much variation in the style of the game. There were no sound effects to speak of (which I think are essential in action games), although the music was certainly nice. There was almost no plot (although arguably it wasn't needed), and the lack of any real purpose to the game just helps bring it's overrall rating down.&lt;br /&gt;
&lt;br /&gt;
I liked what I was seeing when I first loaded the game. I thought it was pretty good and exciting, but urgh... I just don't want to play it again, I'm sorry.&lt;br /&gt;
&lt;br /&gt;
It was all choppy and shoddy and the like.&lt;br /&gt;
&lt;br /&gt;
It's a shame, because it could have been really good.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SPECIFIC TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     12/20''&lt;br /&gt;
&lt;br /&gt;
You fly, they fly, nuff said.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  45/120''&lt;br /&gt;
&lt;br /&gt;
Close, but the game falls at the last hurdle. There just wasn't enough to hold the players attention. The mouse controls were just.. annoying and there was no real challenge after you figure out the enemies.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  42/90''&lt;br /&gt;
&lt;br /&gt;
Not very well animated but it was actually quite good looking. There wasn't very much of it though. Not nearly enough.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  42/80''&lt;br /&gt;
&lt;br /&gt;
Arghhh, mid-range. On the one hand the game has some ambitious engines working for it, but on the other, there are too many little glitches and graphical problems with the game for it to get a perfect score. only being able to shoot straight too was a restriction. There were no FATAL flaws though which is a good thing indeed.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      20/50''&lt;br /&gt;
&lt;br /&gt;
Nahhh, not really very good at all. Even for an action game, you can put a BIT more effort into it. At least there was something though!&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  12/40''&lt;br /&gt;
&lt;br /&gt;
One song, which was pretty nice, no sound effects to speak of&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   173 / 400'''&lt;br /&gt;
&lt;br /&gt;
Mediocre&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Bleh, had potential, but just lacked a lot of things. Fun little waste of 5 minutes though.&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 86715 - [[86715|The stupid pile of rank shit.]]&lt;br /&gt;
&lt;br /&gt;
- Oh well -&lt;br /&gt;
&lt;br /&gt;
Yeh I'm not gonna bother.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL TOPIC)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     4/100''&lt;br /&gt;
&lt;br /&gt;
You remember stuff on the sign (or do you?)&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  5/90''&lt;br /&gt;
&lt;br /&gt;
I guess i played until the end, but only because the energizer song is cool&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  1/70''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  1/60''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      2/50''&lt;br /&gt;
&lt;br /&gt;
Hooray! There's something&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  2/30''&lt;br /&gt;
&lt;br /&gt;
EnergIIIIZerrr&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   14 / 400'''&lt;br /&gt;
&lt;br /&gt;
Why do you bother living&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
Seriously.&lt;br /&gt;
&lt;br /&gt;
-------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 90100 - [[The Red Giant]]&lt;br /&gt;
&lt;br /&gt;
- The title -&lt;br /&gt;
&lt;br /&gt;
I liked the title screen, something about it (perhaps the combination of the music and the graphics) just clicked for me. It was relaxing and i felt relaxed :-).&lt;br /&gt;
&lt;br /&gt;
Wow, Gorka wasn't kidding when he said that the big parasite is tough, that was one angry looking dude.&lt;br /&gt;
&lt;br /&gt;
I'm not sure about this game, on one hand, it's pretty original, but it's unfinished (as in short) and kind of annoying to play.&lt;br /&gt;
&lt;br /&gt;
The graphics are great, fantastic even, for a doz game, the people actually (and i shudder to say this in MZX) look like people. It's insane! The rooms were nicely detailed and the scenery in&lt;br /&gt;
general was very nice to look at.&lt;br /&gt;
&lt;br /&gt;
- Battles -&lt;br /&gt;
&lt;br /&gt;
Interesting Battles. I liked the RPG-Action hybrid, it was an interesting combination and with a little more work/care it could have been really good. As it stood though it was mediocre. The target floated about half a screen down from the colours, so it was hard to see what you're aiming for (even if this is intentional, it's still kind of dumb :D). The RPG battles were pretty easy in general, obviously, until you meet Lord Doom, which is what I've dubbed that last guy, he kills everything. I bet he could kill the world if he tried, Even my gun does nothing.&lt;br /&gt;
&lt;br /&gt;
But yeh, it's short and somewhat sweet. But that's about the limit of it.&lt;br /&gt;
&lt;br /&gt;
The RPG system with the look, use, talk commands and such were interesting and reasonably well implemented, the one big annoyance to me being that once you right clicked you could leave the menu without clicking on an option. But in the room with the random encounters there just wasn't enough time to do anything useful, so you just had to run away basically. The icons were too small to be of any use in real time.&lt;br /&gt;
&lt;br /&gt;
But yeh, the graphics were awesome. And the ideas were too.&lt;br /&gt;
&lt;br /&gt;
The plot was good, I liked where it was going but obviously it ended too quickly, that and... It's not really very related to the theme. Ok, spaceships do fly, I guess. But... you know... it's not enough.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (SPECIFIC CATEGORY)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     7/20''&lt;br /&gt;
&lt;br /&gt;
Poor poor use of the theme. Could have been about anything really.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  41/120''&lt;br /&gt;
&lt;br /&gt;
It was a great idea, and the battles were really fun, but there wasn't much to do, and there wasn't enough done with the RPG engine.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  66/90''&lt;br /&gt;
&lt;br /&gt;
What's there was excellent, things looked exactly like they should, the lack of animation was a bit disappointing but there you go. There weren't enough graphics in the game to get a higher score. Good use of colour.&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  48/80''&lt;br /&gt;
&lt;br /&gt;
It was good, it was generally non buggy and worked well, especially the battles. But the way it was implemented was somewhat poor. I had very mixed feelings about the RPG engine.&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      25/50''&lt;br /&gt;
&lt;br /&gt;
Could have gone somewhere good, but I guess time ran out.&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  21/40''&lt;br /&gt;
&lt;br /&gt;
Pretty good, nice songs but not all that appropriate for the game.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   208 / 400'''&lt;br /&gt;
&lt;br /&gt;
You should finish this! : )&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
If it was complete, it would be AWESOME.. but it's too short to be of any use.&lt;br /&gt;
&lt;br /&gt;
-----------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Team 99115 - [[Memory Leak]]&lt;br /&gt;
&lt;br /&gt;
- Can't be helped -&lt;br /&gt;
&lt;br /&gt;
Sigh... another underachieving game.&lt;br /&gt;
&lt;br /&gt;
This one was a REAL shame because it looked like it had incredible potential. As it stands however, it is just a bug-ridden engine with a few monsters thrown in for some gameplay. There's more to it, but you pretty much have to access it via the editor, as everything sort of craps out after a few boards anyway, I did take a look at what was there though.&lt;br /&gt;
&lt;br /&gt;
Some interesting stuff. But let's start at the beginning&lt;br /&gt;
&lt;br /&gt;
- As most things do -&lt;br /&gt;
&lt;br /&gt;
What we have here, is a smooth pixel-by-pixel engine, similar to the one used in [[Cheese's Adventure|Cheese's adventure]] but with two differences. Firstly, the character is much bigger, so commendments for accomplishing that task, but unfortunately, it just doesn't work as well as the one used in Cheese's adventure. I'm not judging code complexity, or code efficiency or anything&lt;br /&gt;
like that, bottom line is I wouldn't really know, all I know is that this engine glitches up increasingly as the game progresses. At the start, all is well, it works like a charm and you really don't think anything could go wrong. Then, for seemingly no reason (it's not like anything specific happesn to trigger it) Your character, and everything else that moves, gets hit by this disease, which turns them into big moving blocks. Admittedly, these are very smooth scrolling blocks which was somewhat cool, but yeh... It was ambitious and it just kind of wasn't pulled off.&lt;br /&gt;
&lt;br /&gt;
The gameplay basically consists of walking around and using this 'power' you get to shoot stuff. Basically you have a yoyo, it's a pretty powerful yoyo admittedly but it can, for all purposes, be called one nonetheless. The Yoyo of power is quite an interesting weapon because you can aim it&lt;br /&gt;
even after you've fired, which is... somewhat novel for a mzx game, and this worked almost flawlessly (occasionally the collision detection was off).&lt;br /&gt;
&lt;br /&gt;
The thing that I found... SO annoying in the game was the fact that the creators of the game decided to make each and every passageway exactly your size and width. In a normal MZX game, this would not have been a problem obviously, but with a pixel perfect engine such as this, it's just&lt;br /&gt;
asking for problems. It's tricky to get aligned correctly with the exit. The best way was to find something parallel to it and sort of 'anchor' your position on it, but even so, this is a stupid way to do things and it really should have been tended to. Not that  I doubt the team had other pressing matters to attend to.&lt;br /&gt;
&lt;br /&gt;
- Plot -&lt;br /&gt;
&lt;br /&gt;
If you get a chance to read some of the story boards, do so. They're quite an interesting read, it's one of the more engrossing plots of the doz, and you get the feeling that had the game worked, the plot could have been very well woven in to the game. As it stands though, the plot is all but&lt;br /&gt;
unaccessable apart from through the editor.&lt;br /&gt;
&lt;br /&gt;
- Monsters -&lt;br /&gt;
&lt;br /&gt;
The monsters were odd to say the least. They were somewhat similar to built-in MZX snakes. In that they charged along until they hit something, then re-honed their senses for another charge. The difficulty they posed was... average generally but if you got double teamed by one of them it was&lt;br /&gt;
practically insta-death. What the hell were they anyway. They were like... Well the first ones seemed like those fuzzy little balls with feet you sometimes see in souvenir shops, you know the ones, the ones that squeak when you squeeze them, yeh those ones. The other enemies... probably&lt;br /&gt;
looked good, but after the engine craps in you can't see anything but a block.&lt;br /&gt;
&lt;br /&gt;
- Closing up -&lt;br /&gt;
&lt;br /&gt;
The music was nice. Very appropriate. It gave a sense of adventure combined with mystery, it was a nice accompaniment when I was reading the plot. But of course it's not going to carry this game, there weren't really any sound effects.&lt;br /&gt;
&lt;br /&gt;
Also why were there like 10 .mzx files &amp;gt;:(. I spent a while looking through all of them (I kept checking DOZREAL.mzx, it promised me it was the real one) which... seemed to have a different game altogether? Unless that was just the initial working title. When I finally found the right one, the &lt;br /&gt;
title screen jumped out at me. It looks ... good... but I just wasn't too fond of it, it was a bit flashy and just sort of, to me at least, seemed like it had that falling effect, just for the sake of having some kind of graphical effect on the word, but they couldn't think of anything better. I suppose a few games do that anyway though... But at least they normally do it for a reason. Take Witch Switch for example.&lt;br /&gt;
&lt;br /&gt;
'''- - - SCORE - - -  (GENERAL CATEGORY)'''&lt;br /&gt;
&lt;br /&gt;
''Theme&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;     38/100''&lt;br /&gt;
&lt;br /&gt;
It was going places here, but it never really developed. The music stuck to the theme well, as did the plot. The graphics and boards themselves though... Just seemed indifferent to it.&lt;br /&gt;
&lt;br /&gt;
''Gameplay&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  24/90''&lt;br /&gt;
&lt;br /&gt;
The Yoyo was pretty fun for a while I guess, I've had more fun, but I've had less fun. Getting through the passageways though, and just navigating the boards in general, was frustrating as anything in this doz. As fun as shooting the enemies was though, it wasn't enough by far, and the rest of the game is navigating a sticky maze.&lt;br /&gt;
&lt;br /&gt;
''Graphics&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;  53/70''&lt;br /&gt;
&lt;br /&gt;
Impressive, everything looks pretty good (Until the engine fizzled out), and what's more, people looked like people. The backgrounds and board designs were rich and colourful (how gay does that sound) and I like the cactuses.&lt;br /&gt;
&lt;br /&gt;
'THERE ARE NO TREES ANYWHERE' but plenty of plants and cactii, just definitely no trees.&lt;br /&gt;
&lt;br /&gt;
'THE LAND IS FLAT'... apart from all those pyramids and walls and blocks and cactuses and the fact that almost everything blocks your way&lt;br /&gt;
&lt;br /&gt;
'I HAVE FOUND THIS MYSTERIOUS POWER, IT ISN'T WORTH EXPLAINING', interesting comment when it's like, a hugely powerful yo yo that saves your life every minute, I would have thought that was worth something : (&lt;br /&gt;
&lt;br /&gt;
I'm done now :D&lt;br /&gt;
&lt;br /&gt;
''Technique&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;---------&amp;lt;/nowiki&amp;gt;  49/60''&lt;br /&gt;
&lt;br /&gt;
Coulda, shoulda, woulda, kinda did. The pixel-perfect movement was very fun to play with, and the movement side of the engine worked perfectly. Unfortunately the graphical side of it fizzles out after a minute or so.&lt;br /&gt;
&lt;br /&gt;
The Yo-yo was good fun but the collision detection could use some work.&lt;br /&gt;
&lt;br /&gt;
If there were none of these little flaws, it would have gotten 55+ here.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Story&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;      20/50''&lt;br /&gt;
&lt;br /&gt;
Now, I want to give this game something good just for what I read on that board. But I haven't been able to reach that board by conventional means, and even if I could, the game doesn't seem to progress after that stage anyway. This means that the worth of the story is only a fraction of what it was. A completed story is worth 10 times it's half-done brother. Remember that quote folks, that will be famous one day. I will be famous one day &amp;lt;:(&lt;br /&gt;
&lt;br /&gt;
''Music&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;-----&amp;lt;/nowiki&amp;gt;  22/30''&lt;br /&gt;
&lt;br /&gt;
I liked, very ambiental. No sound effects to speak of.&lt;br /&gt;
&lt;br /&gt;
'''- TOTAL SCORE -   204 / 400'''&lt;br /&gt;
&lt;br /&gt;
Decent&lt;br /&gt;
&lt;br /&gt;
- Final Word -&lt;br /&gt;
&lt;br /&gt;
For something incomplete this is an impressive score. The Technique and graphics carry it most of the way though. Probably the most ambitious project of the doz, but it shows by also being the least complete. Still, credit where it's due, this was a good effort.&lt;br /&gt;
&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
In Conclusion !&lt;br /&gt;
&lt;br /&gt;
------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Final Scores&lt;br /&gt;
&amp;lt;nowiki&amp;gt;------------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Team 525   - Aviation Aspiration                 - 166&amp;lt;br&amp;gt;&lt;br /&gt;
Team 5389  - The thing what came from beneath    - 153&amp;lt;br&amp;gt;&lt;br /&gt;
Team 12984 - Irreplacable Memory                 - 198&amp;lt;br&amp;gt;&lt;br /&gt;
Team 21079 - Fuzzy loses his memory              - 167&amp;lt;br&amp;gt;&lt;br /&gt;
Team 32427 - Dislocated Memories                 - 185&amp;lt;br&amp;gt;&lt;br /&gt;
Team 34329 - Fritz Blitz                         - 291&amp;lt;br&amp;gt;&lt;br /&gt;
Team 48625 - This is Greg (And hello Kitty)      - 142&amp;lt;br&amp;gt;&lt;br /&gt;
Team 51976 - It is time to compete games!        - 38&amp;lt;br&amp;gt;&lt;br /&gt;
Team 65131 - Witch Switch                        - 135&amp;lt;br&amp;gt;&lt;br /&gt;
Team 77665 - Relapse                             - 151&amp;lt;br&amp;gt;&lt;br /&gt;
Team 83038 - Bionic commando!                    - 173&amp;lt;br&amp;gt;&lt;br /&gt;
Team 86715 - Quite a poor game                   - 14&amp;lt;br&amp;gt;&lt;br /&gt;
Team 90100 - The Red Giant                       - 208&amp;lt;br&amp;gt;&lt;br /&gt;
Team 99115 - Memory Leak                         - 204&lt;br /&gt;
&lt;br /&gt;
Rankings&lt;br /&gt;
&amp;lt;nowiki&amp;gt;--------&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
1st GOLD   Team 34329 - Fritz Blitz&lt;br /&gt;
&lt;br /&gt;
2nd SILVER   Team 90100 - The Red Giant&lt;br /&gt;
&lt;br /&gt;
3rd SHEEP   Team 99115 - Memory Leak&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4.  Team 12984 - Irreplacable Memory&amp;lt;br&amp;gt;&lt;br /&gt;
5.  Team 32427 - Dislocated Memories&amp;lt;br&amp;gt;&lt;br /&gt;
6.  Team 83038 - Bionic commando!&amp;lt;br&amp;gt;&lt;br /&gt;
7.  Team 21079 - Fuzzy loses his memory&amp;lt;br&amp;gt;&lt;br /&gt;
8.  Team 525   - Aviation Aspiration&amp;lt;br&amp;gt;&lt;br /&gt;
9.  Team 5389  - The thing what came from beneath&amp;lt;br&amp;gt;&lt;br /&gt;
10. Team 77665 - Relapse                      (My personal favourite :D)&amp;lt;br&amp;gt;&lt;br /&gt;
11. Team 48625 - This is Greg (And hello Kitty)&amp;lt;br&amp;gt;&lt;br /&gt;
12. Team 65131 - Witch Switch&amp;lt;br&amp;gt;&lt;br /&gt;
13. Team 51976 - It is time to compete games!&amp;lt;br&amp;gt;&lt;br /&gt;
14. Team 86715 - Whatever&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
The problem with this doz is that there were pretty much no games that were good in ALL categories. Most of the game with good graphics, were poor in that they were either incomplete, or were buggy, or were not related to the theme (Memory Leak, Irreplaceable Memory). Likewise, the games that were high on plot, generally failed to deliver in other parts of the competition (Relapse, Aviation Aspiration) The only real exception to this rule was, not surprisingly, Fritz Blitz. Where, although the plot was not amazing, the game as a whole was simply solid, and this is reflected in having a score almost 100 points higher then anyone elses. Yes, it was that far a gap in terms of game quality.&lt;br /&gt;
&lt;br /&gt;
It's a shame. But there you go.&lt;br /&gt;
&lt;br /&gt;
Also, it's worth a mention, that the overrall gameplay rating of this doz was quite low, not many of the games were fun to play.&lt;br /&gt;
&lt;br /&gt;
[[Category:Christmas 2006 Dualstream Day of Zeux Judging Sheets]]&lt;/div&gt;</summary>
		<author><name>Old-Sckool</name></author>
	</entry>
</feed>