Skip to content

Commit

Permalink
Add JSW
Browse files Browse the repository at this point in the history
  • Loading branch information
alvieboy committed May 21, 2012
1 parent 456f576 commit c34c439
Show file tree
Hide file tree
Showing 5 changed files with 1,892 additions and 0 deletions.
212 changes: 212 additions & 0 deletions jsw/jsw.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<html>
<head>
<title>Jet Set Willy 48K information</title>
<link rel="stylesheet" type="text/css" href="style.css" media="screen" />
</head>

<body>
<div id="content">

This document presents some technical information about Jet Set Willt 48 original implementation
for ZX Spectrum 48K. It was written as a result of a implementation of the game engine to ZPUino
SoC with a compatible VGA interface.<p>

<h1>ZX Spectrum 48K</h1>
The ZX Spectrum 48K was a computer designed by Sinclair Research based on a Z80 CPU running at 3.5MHz, and a
special purpose chip built using a Ferranti ULA (so called the ZX Spectrum ULA). The ULA was responsable for
the video graphics and for the (limited) audio support.<p>
The ZX 80 memory map is roughly as follows:<p>
<table border="1">
<tr> <td>Start</td> <td>End</td> <td>Size</td> <td>Description</td> </tr>
<tr> <td>0x0000</td> <td>0x3FFF</td> <td> 16384 bytes (16KB) </td> <td>ZX Spectrum ROM</td> </tr>
<tr> <td>0x4000</td> <td>0x3FFF</td> <td> 6144 bytes </td> <td>Main screen area</td> </tr>
<tr> <td>0x5800</td> <td>0x5CFF</td> <td> 768 bytes </td> <td>Screen attributes area</td> </tr>
<tr> <td>0x5B00</td> <td>0xFFFF</td> <td> 42240 bytes </td> <td>Program/Data area</td> </tr>
</table>

<h2>The screen</h2>

The ZX Spectrum screen has an unusual memory layout. It's composed of a 256x192 pixel display with a 32x24 attribute block area.
Each attribute block entry sets the color for a 8x8 bit block on the screen.<p>

<h1>JSW game</h1>
The game consists of several rooms, filled with enemies and objects.
The objective of the game is to successfully collect all items in the game so Maria will allow you to go to bed.<p>

<h2>The rooms</h2>
The room is displayed on the game area, which is 32x16 blocks (8x8). Lives, time and other information are displayed below this area.
Each room consists of several actors and the room design itself.<p>
<h3>The room design</h3>
All rooms are composed of 4 types of blocks:
<ul>
<li>Background (empty) block</li>
<li>Floor block</li>
<li>Wall block</li>
<li>Nasty block (touch this, Willy gets killed)</li>
</ul>
The game engine uses the color (attribute) to distinguish from all block types, so each block type
should use it's own distinct color (attribute).</p>
Each of these types include a bitmap (8x8) per room, so each of this block type is drawn using the same color
and same bitmap. See below for the room binary description and where this data comes from.

<h2>The guardians</h2>
The guardians are the little fellows that protect the objects from being collected. The guardians can be:
<ul>
<li>Normal guardians (horizontal-moving and vertical-moving)</li>
<li>Arrows (going left or right) </li>
<li>Ropes </li>
</ul>

<h3>Other entities</h2>
Besides all the entities above, each room can also have:
<ul>
<li>One optional slope, either climbing or falling</li>
<li>An optional conveyor</li>
</ul>

<div align="center">
<img src="screen1.png">
<div>
Some elements of the game: <p>
1 - Arrow, 2 - Guardian, 3 - Nasty block, 4 - Slope
</div>
</div>

<div align="center">
<img src="screen2.png">
<div>
Some other elements of the game: <p>
5 - Wall block, 6 - Floor block, 7 - Conveyor, 8 - Object
</div>
</div>

<h2>Collision detection</h2>
Most collision detection is done using the attribute buffer, except for guardians (normal and arrows), where pixel-based collision
detection is used.


<h2>Overall game memory layout</h2>
The memory layout of the game (from 0x5B00, where screen attributes end) is as follows:
<table border="1">
<tr> <td>Start</td> <td>End</td> <td>Size</td> <td>Description</td> </tr>
<tr><td>0x5C00</td> <td>0x5DFF</td> <td>512 bytes</td> <td>2nd attribute buffer (32x16)</td> </tr>
<tr><td>0x5E00</td> <td>0x5EFF</td> <td>512 bytes</td> <td>1nd attribute buffer (32x16)</td> </tr>
<tr><td>0x6000</td> <td>0x6FFF</td> <td>4096 bytes</td> <td>2nd screen buffer (32x16x8)</td> </tr>
<tr><td>0x7000</td> <td>0x7FFF</td> <td>4096 bytes</td> <td>1st screen buffer (32x16x8)</td> </tr>

<tr><td>0x8000</td> <td>0x80FF</td> <td>256 bytes</td> <td>Current room definition</td> </tr>
<tr><td>0x8100</td> <td>0x8141</td> <td>64+2 bytes</td> <td>Current room guardians</td> </tr>
<tr><td>0x8142</td> <td>0x81FF</td> <td>190 bytes</td> <td>Not used</td> </tr>

<tr><td>0x8200</td> <td>0x82FF</td> <td>256 bytes</td> <td>Pixel-buffer lookup table</td> </tr>
<tr><td>0x8300</td> <td>0x83FF</td> <td>256 bytes</td> <td>Rope structure table</td> </tr>
<tr><td>0x8400</td> <td>0x96FF</td> <td>4863 bytes</td> <td>Program code</td> </tr>
<tr><td>0x9700</td> <td>0x9FFF</td> <td>2306 bytes</td> <td>Not used</td> </tr>

<tr><td>0xA000</td> <td>0xA3FE</td> <td>1023 bytes</td> <td>Guardian table</td> </tr>
<tr><td>0xA3FF</td> <td>0xAAFF</td> <td>1 + 1792 bytes</td> <td>Objects table (1st byte depicts number of objects)</td> </tr>
<tr><td>0xAB00</td> <td>0xBFFF</td> <td>5376 bytes</td> <td>Sprites</td> </tr>
<tr><td>0xC000</td> <td>0xFFFF</td> <td>16384 bytes</td> <td>Room definitions (256 bytes per room)</td> </tr>
<table>

<h2>The room definition</h2>
Each room is described by a 256-byte block. Whenever a new room is loaded, it's definition is copied from the room definition area (0xC000) to
the current room area (0x8000).<p>
The room structure is defined like this:
<table border="1">
<tr> <td>Start</td> <td>End</td> <td>Size</td> <td>Description</td> </tr>
<tr> <td>0</td> <td>127</td> <td>128 bytes</td> <td>Main room blocks, packed into 2 bit each</td> </tr>
<tr> <td>128</td> <td>159</td> <td>32 bytes</td> <td>Room name</td> </tr>

<tr> <td>160</td> <td>160</td> <td>1 byte</td> <td>Background attribute</td> </tr>
<tr> <td>161</td> <td>168</td> <td>8 bytes</td> <td>Background 8x8 pixel data</td> </tr>

<tr> <td>169</td> <td>169</td> <td>1 byte</td> <td>Floor attribute</td> </tr>
<tr> <td>170</td> <td>177</td> <td>8 bytes</td> <td>Floor 8x8 pixel data</td> </tr>

<tr> <td>178</td> <td>178</td> <td>1 byte</td> <td>Wall attribute</td> </tr>
<tr> <td>179</td> <td>186</td> <td>8 bytes</td> <td>Wall 8x8 pixel data</td> </tr>

<tr> <td>187</td> <td>187</td> <td>1 byte</td> <td>Nasty attribute</td> </tr>
<tr> <td>188</td> <td>195</td> <td>8 bytes</td> <td>Nasty 8x8 pixel data</td> </tr>

<tr> <td>196</td> <td>196</td> <td>1 byte</td> <td>Slope attribute</td> </tr>
<tr> <td>197</td> <td>204</td> <td>8 bytes</td> <td>Slope 8x8 pixel data</td> </tr>

<tr> <td>205</td> <td>205</td> <td>1 byte</td> <td>Conveyor attribute</td> </tr>
<tr> <td>206</td> <td>213</td> <td>8 bytes</td> <td>Conveyor 8x8 pixel data</td> </tr>

<tr> <td>214</td> <td>214</td> <td>1 byte</td> <td>Conveyor direction</td> </tr>
<tr> <td>215</td> <td>216</td> <td>2 bytes</td> <td>Conveyor start position <a href="#">a)</a></td> </tr>
<tr> <td>217</td> <td>217</td> <td>1 byte</td> <td>Conveyor length</a></td> </tr>

<tr> <td>218</td> <td>218</td> <td>1 byte</td> <td>Slope direction</td> </tr>
<tr> <td>219</td> <td>220</td> <td>2 bytes</td> <td>Slope start position <a href="#">a)</a></td> </tr>
<tr> <td>221</td> <td>221</td> <td>1 byte</td> <td>Slope length</a></td> </tr>

<tr> <td>222</td> <td>224</td> <td>3 bytes</td> <td>Screen (border) Background ?</td> </tr>
<tr> <td>225</td> <td>232</td> <td>8 bytes</td> <td>Objects on this map (up to 8)</td> </tr>

<tr> <td>233</td> <td>233</td> <td>1 byte</td> <td>Map ID if we exit left</td> </tr>
<tr> <td>234</td> <td>234</td> <td>1 byte</td> <td>Map ID if we exit right</td> </tr>
<tr> <td>235</td> <td>235</td> <td>1 byte</td> <td>Map ID if we exit up</td> </tr>
<tr> <td>236</td> <td>236</td> <td>1 byte</td> <td>Map ID if we exit down</td> </tr>

<tr> <td>237</td> <td>238</td> <td>2 bytes</td> <td>Willy start position on map <a href="#">a)</a></td> </tr>
<tr> <td>239</td> <td>255</td> <td>16 bytes</td> <td>Guardian instances (2 bytes each)</td> </tr>
</table>

Let's look at more detail into each field.

<h3>Main room blocks</h3>
This data defines the whole 32x16 room area, in terms of 4 basic block types: background, floor, wall and nasty.
The encoding is done in MSB->LSB order, 2 bits at a time. So a binary value of <b>AABBCCDD</b>b depicts 4 consequent blocks,
where <b>AA</b> is the first block, <b>BB</b> the second one, and so on.<p>
These two bits, if multiplied by 9, give the offset of the block type in relation to the "Background attribute" in the room definition.

<table border="1">
<tr> <td>Bits</td> <td>Block type</td> </tr>
<tr> <td>00</td> <td>Background</td> </tr>
<tr> <td>01</td> <td>Floor</td> </tr>
<tr> <td>10</td> <td>Wall</td> </tr>
<tr> <td>11</td> <td>Nasty</td> </tr>
</table>
Since the game area is 32x16 blocks, and each block takes 2 bits, the room definition is 32x16x2 bits (1024 bits), or 128 bytes wide.

<h4>Block definitions</h4>
The block definitions include Background, Floor, Wall and Nasty. These are used by the 128-byte room definition. In addition there
are two other block definitions, Slope and Conveyor.

Each of those block definitions is 9-bytes wide. The 1st byte depicts the attribute (which is written to the attribute buffer and used
to test for collisions. The other 8 bytes are a 8x8 bitmap of the block itself.

<h4>Slopes</h4>
Each map can have a slope. A slope is defined by its attribute and bitmap (like basic blocks), plus three other fields: direction, start
position and lenght. If length is zero, then no slope exists on this map. <p>
If lenght is not zero, then a slope is rendered to screen, using the direction (they are drawn left to right, so direction means either
a climbing slope or a falling slope), it's start position (which is an absolute value, and maps into the attribute buffer), and it's lenght
in 8x8 blocks in the horizontal direction.

<h4>Conveyor</h4>
Each map can have a conveyor. A conveyor forces Willy into one direction (or to stop moving) when he's standing on it.
The Conveyor is similar to the Slope, except direction means the real conveyor direction (whether it forces Willy to go left
or right). They are always drawn horizontally.

<h4>Border</h4>
Not yet sure.
<h4>Object</h4>
This is a 8-bit object bitmap for objects on this room.
<h4>Left, Right, Up and Down</h4>
These four fields depict the room number where to switch to when we go though each direction.

<h4>Willy start position</h4>
This depicts the starting Willy position on this map. It's an absolute value, maps into the attribute buffer.
<h4>Guardians</h4>
This is perhaps the most complex field of the room definition.


<h1>Links</h1>
<a href="http://gfxzone.planet-d.net/articles/zx_spectrum_graphics-article_01.html">ZX-Spectrum graphics modes</a>
</div>
</body>
</html>
Loading

0 comments on commit c34c439

Please sign in to comment.