-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
1,892 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.