├── .gitignore ├── README.markdown ├── Wolfenstein 3D ├── map_objects.rst ├── enemy-tables.rst └── file-formats.rst └── Age of Wonders └── Addendum.rst /.gitignore: -------------------------------------------------------------------------------- 1 | ################ 2 | # OS generated # 3 | ################ 4 | .DS_Store 5 | .DS_Store? 6 | ._* 7 | .Spotlight-V100 8 | .Trashes 9 | Icon? 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | ################# 14 | # Vim generated # 15 | ################# 16 | *.swapfile 17 | *.swp 18 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Game Source Documentation 2 | ========================= 3 | 4 | The goal of this project is to produce complete language-independent 5 | documentations of video game source codes. A game's documentation can be 6 | considered mature once the information contained is sufficient enough for 7 | someone to produce an accurate port from that information alone without need for 8 | the original source code. 9 | 10 | The documentation has to cover interpreting assets and implementation of game 11 | mechanics. It is not necessary, although appreciated, to document the exact 12 | implementation of a feature, as long as the documentation is sufficient enough 13 | to produce similar *looking* results. Hard-or software related implementation 14 | details only need to be documented if they are relevant, such as the endianess 15 | of numbers in asset files. 16 | 17 | License 18 | ------- 19 | 20 | In short, there is no real license. For the information I have gathered feel 21 | free to make use of it, even commercially (unlikely, but just in case). As for 22 | information copied from somewhere else the source is always listed, so check the 23 | source directly. It would be nice if you credit me, but you don't have to. 24 | -------------------------------------------------------------------------------- /Wolfenstein 3D/map_objects.rst: -------------------------------------------------------------------------------- 1 | .. default-role:: code 2 | 3 | ================ 4 | Map object codes 5 | ================ 6 | 7 | The following is a list of words (two bytes) and their corresponding map 8 | objects. Some objects are walls and only used on the *Architecture* map, others 9 | are decoration objects and used on the *Objects* map. No two objects have the 10 | same byte even though they always appear on different maps. The list was adapted 11 | from the *MAPDATA.DEF* file of the *Nmap* editor by Nathan Lineback. See below 12 | for acknowledgements. 13 | 14 | The codes are similar, but not exactly the same for Wolfenstein 3D and Spear of 15 | Destiny, so there are extra columns for the two of them. The SoD mission packs 16 | on the other hand are just using re-drawn graphics while the hard-coded data is 17 | the same as for SoD, so there are no colums for them. 18 | 19 | ======== ============================ ===================== =================== =================== 20 | Word Wolf3D Architecture Wofl3D Objects SoD Architecture SoD Objects 21 | ======== ============================ ===================== =================== =================== 22 | `0x0000` Nothing/Undefined Nothing/Undefined Nothing/Undefined Nothing/Undefined 23 | `0x0001` Grey Stone 1 Grey stone 1 24 | `0x0002` Grey Stone 2 Grey stone 2 25 | `0x0003` Grey with banner Grey w/banner 26 | `0x0004` Grey with Hitler Grey w/hitler 27 | `0x0005` Cell Cell 28 | `0x0006` Grey with eagle Grey w/eagle 29 | `0x0007` Grey with skeleton Cell w/skeleton 30 | `0x0008` Blue Stone 1 Blue stone 1 31 | `0x0009` Blue Stone 2 Blue stone 2 32 | `0x000A` Wood w/eagle Wood w/eagle 33 | `0x000B` Wood w/hitler Wood w/hitler 34 | `0x000C` Wood panelling Wood panelling 35 | `0x000D` Entrance to level Entrance to level 36 | `0x000E` Steel w/signs Steel w/signs 37 | `0x000F` Steel plate Steel plate 38 | `0x0010` Landscape Landscape 39 | `0x0011` Red brick Red brick 40 | `0x0012` Red w/wreath Red w/wreath 41 | `0x0013` Purple wall Start, face N Purple wall Start, face N 42 | `0x0014` Red w/shield Start, face E Red w/shield Start, face E 43 | `0x0015` Elevator <> Start, face S Elevator <> Start, face S 44 | `0x0016` Elevator 2 ^v Start, face W Elevator 2 ^v Start, face W 45 | `0x0017` Wood w/symbol Water Wood w/symbol Water 46 | `0x0018` stone w/yellow stf Oil drum stone w/yellow stf Oil drum 47 | `0x0019` Purple w/blood Table & Chairs Purple w/blood Table & Chairs 48 | `0x001A` stone w/yellow2 Floor lamp stone w/yellow2 Floor lamp 49 | `0x001B` Grey stone 3 Chandelier Grey stone 3 Chandelier 50 | `0x001C` Grey stone w/signs Hanging skeleton Grey stone w/signs Hanging skeleton 51 | `0x001D` Tan design Dog food Tan design Dog food 52 | `0x001E` Tan W blood Column Tan W blood Column 53 | `0x001F` Tan W blood 2 Potted tree Tan W blood 2 Potted tree 54 | `0x0020` Tan W blood 3 Skeleton Tan W blood 3 Skeleton 55 | `0x0021` Wblock/Hitler Washbasin Wblock/Hitler Skulls on stick 56 | `0x0022` Blueblock/Face Potted bush Blueblock/Face Potted bush 57 | `0x0023` White block Vase White block Vase 58 | `0x0024` Bblock W symbol Table Bblock W symbol Table 59 | `0x0025` Wblock W Bit Overhead lamp Wblock W Bit Overhead lamp 60 | `0x0026` R/W/Y/bricks Pot & Pan rack R/W/Y/bricks Cage W guts 61 | `0x0027` Wbrick W crack Armor Wbrick W crack Armor 62 | `0x0028` Blue Block Cage, empty Blue Block Cage, empty 63 | `0x0029` Blue stone/sign Cage, with skeleton Blue stone/sign Cage, with skeleton 64 | `0x002A` Tan pannel Bones Tan pannel Bones 65 | `0x002B` Wblock w map Key 1 (yellow) Wblock w map Key 1 (yellow) 66 | `0x002C` Tan stone Key 2 (grey) Tan stone Key 2 (grey) 67 | `0x002D` Tan stone2 Bed Tan stone2 Cage w skulls 68 | `0x002E` Tan pannel 2 Pot Tan pannel 2 Pot 69 | `0x002F` Tan Pannel/flag Food Tan Pannel/flag Food 70 | `0x0030` Plasterboard First aid kit Plasterboard First aid kit 71 | `0x0031` Wblock w Pic Ammunition Wblock w Pic Ammunition 72 | `0x0032` Machine gun Rock wall 1 Machine gun 73 | `0x0033` Huge gun Rock wall 2 Huge gun 74 | `0x0034` Cross Rock /w banner Cross 75 | `0x0035` Cup Rock /w reath Cup 76 | `0x0036` Jewels Grey marble 1 Jewels 77 | `0x0037` Crown Grey marble 2 Crown 78 | `0x0038` Sphere / life Hot wall Sphere / life 79 | `0x0039` Bloody bones Grey flat marble Bloody bones 80 | `0x003A` Brown barrel Stone fence 1 Brown barrel 81 | `0x003B` Well with water Stone fence 2 Well with water 82 | `0x003C` Well empty Elevator decoration Well empty 83 | `0x003D` Blood White wall Blood 84 | `0x003E` Flag Brown Marble Flag 85 | `0x003F` Call Apogee Purple Brick Overhead lamp2 86 | `0x0040` Trash 1 Trash 1 87 | `0x0041` Trash 2 Trash 2 88 | `0x0042` Trash 3 Trash 3 89 | `0x0043` Pot/Pan Rack2 Animal skull stick 90 | `0x0044` Oven Pool of guts 91 | `0x0045` Spear Rack Demon statue 92 | `0x0046` Vines Vines 93 | `0x0047` Tan pillar 94 | `0x0048` Ammo Box 95 | `0x0049` Truck 96 | `0x004A` Spear 97 | `0x004B` 98 | `0x004C` 99 | `0x004D` 100 | `0x004E` 101 | `0x004F` 102 | `0x0050` 103 | `0x0051` 104 | `0x0052` 105 | `0x0053` 106 | `0x0054` 107 | `0x0055` 108 | `0x0056` 109 | `0x0057` 110 | `0x0058` 111 | `0x0059` 112 | `0x005A` Door Move East Door Move > 113 | `0x005B` Door Move North-East Door Move /> 114 | `0x005C` Locked door Move ^ Locked door Move ^ 115 | `0x005D` Locked door Move <\ Locked door Move <\ 116 | `0x005E` Locked door 2 Vertical Move < Locked door 2 Move < 117 | `0x005F` Locked door 2 Horizontal Move Fixed door - Move \> 120 | `0x0062` Fixed door Vertical Secret door Fixed door Secret door 121 | `0x0063` Fixed door Horizontal End of game trigger Fixed door - End of game trigger 122 | `0x0064` Elevator entrance Vertical Elevator entrance 123 | `0x0065` Elevator entrance Horizontal Elevator entrance - 124 | `0x0066` 125 | `0x0067` 126 | `0x0068` 127 | `0x0069` 128 | `0x006A` Stasis Area 6A Stasis Area 6A WEIRD THING 129 | `0x006B` LAST SOD GUY 130 | `0x006C` Area 6C Guard 1 East Area 6C Guard 1 > 131 | `0x006D` Area 6D Guard 1 ^ Area 6D Guard 1 ^ 132 | `0x006E` Area 6E Guard 1 < Area 6E Guard 1 < 133 | `0x006F` Area 6F Guard 1 v Area 6F Guard 1 v 134 | `0x0070` Area 70 Guard 1 > moving Area 70 Guard 1 > moving 135 | `0x0071` Area 71 Guard 1 ^ moving Area 71 Guard 1 ^ moving 136 | `0x0072` Area 72 Guard 1 < moving Area 72 Guard 1 < moving 137 | `0x0073` Area 73 Guard 1 v moving Area 73 Guard 1 v moving 138 | `0x0074` Area 74 W Guard 1 East Area 74 W Guard 1 > 139 | `0x0075` Area 75 W Guard 1 ^ Area 75 W Guard 1 ^ 140 | `0x0076` Area 76 W Guard 1 < Area 76 W Guard 1 < 141 | `0x0077` Area 77 W Guard 1 v Area 77 W Guard 1 v 142 | `0x0078` Area 78 W Guard 1 > moving Area 78 W Guard 1 > moving 143 | `0x0079` Area 79 W Guard 1 ^ moving Area 79 W Guard 1 ^ moving 144 | `0x007A` Area 7A W Guard 1 < moving Area 7A W Guard 1 < moving 145 | `0x007B` Area 7B W Guard 1 v moving Area 7B W Guard 1 v moving 146 | `0x007C` Area 7C Dead guard Area 7C Dead guard 147 | `0x007D` Area 7D Area 7D SOD GUY1 148 | `0x007E` Area 7E Officer 1 East Area 7E Officer 1 > 149 | `0x007F` Area 7F Officer 1 ^ Area 7F Officer 1 ^ 150 | `0x0080` Area 80 Officer 1 < Area 80 Officer 1 < 151 | `0x0081` Area 81 Officer 1 v Area 81 Officer 1 v 152 | `0x0082` Area 82 Officer 1 > moving Area 82 Officer 1 > moving 153 | `0x0083` Area 83 Officer 1 ^ moving Area 83 Officer 1 ^ moving 154 | `0x0084` Area 84 Officer 1 < moving Area 84 Officer 1 < moving 155 | `0x0085` Area 85 Officer 1 v moving Area 85 Officer 1 v moving 156 | `0x0086` Area 86 Area 86 157 | `0x0087` Area 87 Area 87 158 | `0x0088` Area 88 Area 88 159 | `0x0089` Area 89 Area 89 160 | `0x008A` Area 8A Dog 1 East Area 8A Dog 1 > 161 | `0x008B` Area 8B Dog 1 ^ Area 8B Dog 1 ^ 162 | `0x008C` Area 8C Dog 1 < Area 8C Dog 1 < 163 | `0x008D` Area 8D Dog 1 v Area 8D Dog 1 v 164 | `0x008E` Area 8E Area 8E SOD GUY4 165 | `0x008F` Area 8F Area 8F SOD GUY2 166 | `0x0090` Guard 2 East Guard 2 > 167 | `0x0091` Guard 2 ^ Guard 2 ^ 168 | `0x0092` Guard 2 < Guard 2 < 169 | `0x0093` Guard 2 v Guard 2 v 170 | `0x0094` Guard 2 East moving Guard 2 > moving 171 | `0x0095` Guard 2 ^ moving Guard 2 ^ moving 172 | `0x0096` Guard 2 < moving Guard 2 < moving 173 | `0x0097` Guard 2 v moving Guard 2 v moving 174 | `0x0098` W Guard 2 East W Guard 2 > 175 | `0x0099` W Guard 2 ^ W Guard 2 ^ 176 | `0x009A` W Guard 2 < W Guard 2 < 177 | `0x009B` W Guard 2 v W Guard 2 v 178 | `0x009C` W Guard 2 East moving W Guard 2 > moving 179 | `0x009D` W Guard 2 ^ moving W Guard 2 ^ moving 180 | `0x009E` W Guard 2 < moving W Guard 2 < moving 181 | `0x009F` W Guard 2 v moving W Guard 2 v moving 182 | `0x00A0` Floating guy Floating guy 183 | `0x00A1` SOD GUY3 184 | `0x00A2` Officer 2 East Officer 2 > 185 | `0x00A3` Officer 2 ^ Officer 2 ^ 186 | `0x00A4` Officer 2 < Officer 2 < 187 | `0x00A5` Officer 2 v Officer 2 v 188 | `0x00A6` Officer 2 > moving Officer 2 > moving 189 | `0x00A7` Officer 2 ^ moving Officer 2 ^ moving 190 | `0x00A8` Officer 2 < moving Officer 2 < moving 191 | `0x00A9` Officer 2 v moving Officer 2 v moving 192 | `0x00AA` 193 | `0x00AB` 194 | `0x00AC` 195 | `0x00AD` 196 | `0x00AE` Dog 2 E Dog 2 E 197 | `0x00AF` Dog 2 N Dog 2 N 198 | `0x00B0` Dog 2 W Dog 2 W 199 | `0x00B1` Dog 2 S Dog 2 S 200 | `0x00B2` Robo Hitler Robo Hitler 201 | `0x00B3` General General 202 | `0x00B4` Guard 3 E Guard 3 E 203 | `0x00B5` Guard 3 N Guard 3 N 204 | `0x00B6` Guard 3 W Guard 3 W 205 | `0x00B7` Guard 3 S Guard 3 S 206 | `0x00B8` Guard 3 E moving Guard 3 E moving 207 | `0x00B9` Guard 3 N moving Guard 3 N moving 208 | `0x00BA` Guard 3 W moving Guard 3 W moving 209 | `0x00BB` Guard 3 S moving Guard 3 S moving 210 | `0x00BC` W Guard 3 E W Guard 3 E 211 | `0x00BD` W Guard 3 N W Guard 3 N 212 | `0x00BE` W Guard 3 W W Guard 3 W 213 | `0x00BF` W Guard 3 S W Guard 3 S 214 | `0x00C0` W Guard 3 E moving W Guard 3 E moving 215 | `0x00C1` W Guard 3 N moving W Guard 3 N moving 216 | `0x00C2` W Guard 3 W moving W Guard 3 W moving 217 | `0x00C3` W Guard 3 v moving W Guard 3 S moving 218 | `0x00C4` Dr Schabbs Dr Schabbs 219 | `0x00C5` BIG Guardet! BIG Guardet! 220 | `0x00C6` Officer 3 East Officer 3 > 221 | `0x00C7` Officer 3 ^ Officer 3 ^ 222 | `0x00C8` Officer 3 < Officer 3 < 223 | `0x00C9` Officer 3 v Officer 3 v 224 | `0x00CA` Officer 3 East moving Officer 3 > moving 225 | `0x00CB` Officer 3 ^ moving Officer 3 ^ moving 226 | `0x00CC` Officer 3 < moving Officer 3 < moving 227 | `0x00CD` Officer 3 v moving Officer 3 v moving 228 | `0x00CE` 229 | `0x00CF` 230 | `0x00D0` 231 | `0x00D1` 232 | `0x00D2` Dog 3 > Dog 3 > 233 | `0x00D3` Dog 3 ^ Dog 3 ^ 234 | `0x00D4` Dog 3 < Dog 3 < 235 | `0x00D5` Dog 3 v Dog 3 v 236 | `0x00D6` Hans Grösse (boss) BIG Guard! 237 | `0x00D7` Big officer Big officer 238 | `0x00D8` Zombie 1 East Zombie 1 > 239 | `0x00D9` Zombie 1 ^ Zombie 1 ^ 240 | `0x00DA` Zombie 1 < Zombie 1 < 241 | `0x00DB` Zombie 1 v Zombie 1 v 242 | `0x00DC` Zombie 1 East Zombie 1 > moving 243 | `0x00DD` Zombie 1 ^ Zombie 1 ^ moving 244 | `0x00DE` Zombie 1 < Zombie 1 < moving 245 | `0x00DF` Zombie 1 v Zombie 1 v moving 246 | `0x00E0` Blinky (red ghost) Red Ghost 247 | `0x00E1` Clyde (orange ghost Orange Ghost 248 | `0x00E2` Pinky (pink ghost) Light red Ghost 249 | `0x00E3` Inky (blue ghost) Blue Ghost 250 | `0x00E4` 251 | `0x00E5` 252 | `0x00E6` 253 | `0x00E7` 254 | `0x00E8` 255 | `0x00E9` 256 | `0x00EA` Zombie 2 East Zombie 2 > 257 | `0x00EB` Zombie 2 ^ Zombie 2 ^ 258 | `0x00EC` Zombie 2 < Zombie 2 < 259 | `0x00ED` Zombie 2 v Zombie 2 v 260 | `0x00EE` Zombie 2 East Zombie 2 > moving 261 | `0x00EF` Zombie 2 ^ Zombie 2 ^ moving 262 | `0x00F0` Zombie 2 < Zombie 2 < moving 263 | `0x00F1` Zombie 2 v Zombie 2 v moving 264 | `0x00F2` 265 | `0x00F3` 266 | `0x00F4` 267 | `0x00F5` 268 | `0x00F6` 269 | `0x00F7` 270 | `0x00F8` 271 | `0x00F9` 272 | `0x00FA` 273 | `0x00FB` 274 | `0x00FC` Zombie 3 E Zombie 3 E 275 | `0x00FD` Zombie 3 N Zombie 3 N 276 | `0x00FE` Zombie 3 W Zombie 3 W 277 | `0x00FF` Zombie 3 S Zombie 3 S 278 | `0x0100` Zombie 3 East Zombie 3 > moving 279 | `0x0101` Zombie 3 North Zombie 3 ^ moving 280 | `0x0102` Zombie 3 < Zombie 3 < moving 281 | `0x0103` Zombie 3 v Zombie 3 v moving 282 | ======== ============================ ===================== =================== =================== 283 | 284 | Ackgnowledgements 285 | ================= 286 | NMAP Wolf3d map editor by Nathan Lineback [http://toastytech.com/files/nmap.html] 287 | -------------------------------------------------------------------------------- /Wolfenstein 3D/enemy-tables.rst: -------------------------------------------------------------------------------- 1 | .. default-role:: math 2 | 3 | ################# 4 | Tables for actors 5 | ################# 6 | 7 | 8 | List of actor classes and starting hit points 9 | ############################################# 10 | 11 | The following is a list of all types of actors defined in Wolfenstein 3D and 12 | their description, as well as their starting hit points for every dificulty. 13 | They are ordered by their appearance in the game. 14 | 15 | ======= ================================= ==== ==== ====== ==== 16 | Name Description Baby Easy Normal Hard 17 | ======= ================================= ==== ==== ====== ==== 18 | Guard Brown guards 25 25 25 25 19 | Officer White soldiers 50 50 50 50 20 | SS Blue soldiers 100 100 100 100 21 | Dog Shepherd dogs 1 1 1 1 22 | Hans Hans Grosse 850 950 1050 1200 23 | Schabbs Dr. Schabbs 850 950 1550 2400 24 | Fake Fake Hitler 200 300 400 500 25 | Mecha Mecha Hitler 800 950 1050 1200 26 | Hitler Real Hitler 500 700 800 900 27 | Mutant Mutant soldier 45 55 55 65 28 | Blinky Red Pac-Man ghost 25 25 25 25 29 | Clyde Orange Pac-Man ghost 25 25 25 25 30 | Pinky Pink Pac-Man ghost 25 25 25 25 31 | Inky Cyan Pac-Man ghost 25 25 25 25 32 | Gretel Gretel Grosse 850 950 1050 1200 33 | Gift Otto Gifmacher 850 950 1050 1200 34 | Fat General Fettgesicht 850 950 1050 1200 35 | 36 | Needle Syringe thrown by Schabbs 0 0 0 0 37 | Fire Fireball from Fake Hitler 0 0 0 0 38 | Rocket Some bosses have rocket launchers 0 0 0 0 39 | Smoke Smoke from rockets 0 0 0 0 40 | 41 | BJ BJ doing the victory jump 100 100 100 100 42 | ======= ================================= ==== ==== ====== ==== 43 | 44 | Spear of destiny adds the following actors as well: 45 | 46 | ======= ================ ==== ==== ====== ==== 47 | Name Description Baby Easy Normal Hard 48 | ======= ================ ==== ==== ====== ==== 49 | Spark ??? 0 0 0 0 50 | hrocket ??? 0 0 0 0 51 | hsmoke ??? 0 0 0 0 52 | 53 | Spectre Spectre enemy 10 10 15 25 54 | Angel Angle of Death 1550 1550 1650 2000 55 | Trans Trans Grosse 950 950 1050 1200 56 | Uber Ubermutant 1150 1150 1250 1400 57 | Will Barnacle Wilhelm 1050 1050 1150 1300 58 | Death Death Knight 1350 1350 1450 1600 59 | ======= ================ ==== ==== ====== ==== 60 | 61 | The mission packs introduce the following enemies: 62 | 63 | ===== ===================== ==== ==== ====== ==== 64 | Name Description Baby Easy Normal Hard 65 | ===== ===================== ==== ==== ====== ==== 66 | Bat Bats, replace mutants 10 10 15 25 67 | Willi Sumbarine Willi 1550 1550 1650 2000 68 | Quark Dr. Quarkblitz 950 950 1050 1200 69 | Axe The Axe 1150 1150 1250 1400 70 | Robot The Robot 1050 1050 1150 1300 71 | Devil Devil Incarnate 1350 1350 1450 1600 72 | ===== ===================== ==== ==== ====== ==== 73 | 74 | Due to the hardcoded nature of the Wolfenstein 3D engine all the enemies in the 75 | mission packs are just re-skins of enemies from Spear of Destiny, so their 76 | starting hit points are the same. 77 | 78 | 79 | 80 | List of state classes 81 | ##################### 82 | 83 | The following is a list of all types of actor states in the order they are 84 | defined in the original source. Sticking to that order is not strictly 85 | necessary, but one has to make sure to keep the mapping correct. 86 | 87 | ``path`` means patrolling around before having spotted the player, ``die`` is 88 | the state of dying when the death animation is being played. ``dead`` is the 89 | state of being acctually dead. 90 | 91 | ======= ===== 92 | State Index 93 | ======= ===== 94 | stand 0 95 | 96 | path1 1 97 | path1s 2 98 | path2 3 99 | path3 4 100 | path3s 5 101 | path4 6 102 | 103 | pain 7 104 | pain1 8 105 | 106 | shoot1 9 107 | shoot2 10 108 | shoot3 11 109 | shoot4 12 110 | shoot5 13 111 | shoot6 14 112 | shoot7 15 113 | shoot8 16 114 | shoot9 17 115 | 116 | chase1 18 117 | chase1s 19 118 | chase2 20 119 | chase3 21 120 | chase3s 22 121 | chase4 23 122 | 123 | die1 24 124 | die2 25 125 | die3 26 126 | die4 27 127 | die5 28 128 | die6 29 129 | die7 30 130 | die8 31 131 | die9 32 132 | 133 | dead 33 134 | 135 | remove 34 136 | ======= ===== 137 | 138 | :TODO: A list of all actor states for each actor would be too large for this 139 | document, so it will have its own file. 140 | 141 | 142 | Table of actor states 143 | ##################### 144 | 145 | The following tables list the states for every actor class and state class. If a 146 | field is empty, then there is nothing defined for it. In the case of a function 147 | pointer it means the pointer is ``NULL`` and in the case of a sprite the sprite 148 | is just some useless junk sprite. 149 | 150 | 151 | Guard 152 | ===== 153 | 154 | =========== ========== ============== ======= ======= ============ ========== 155 | State Can Rotate Base Sprite Timeout Thought Action Next State 156 | =========== ========== ============== ======= ======= ============ ========== 157 | **stand** true SPR_GRD_S_1 0 Stand stand 158 | 159 | **path1** true SPR_GRD_W1_1 20 Path path1s 160 | **path1s** true SPR_GRD_W1_1 5 path2 161 | **path2** true SPR_GRD_W2_1 15 Path path3 162 | **path3** true SPR_GRD_W3_1 20 Path path3s 163 | **path3s** true SPR_GRD_W3_1 5 path4 164 | **path4** true SPR_GRD_W4_1 15 Path path1 165 | 166 | **pain** false SPR_GRD_PAIN_1 10 chase1 167 | **pain1** false SPR_GRD_PAIN_2 10 chase1 168 | 169 | **shoot1** false SPR_GRD_SHOOT1 20 shoot2 170 | **shoot2** false SPR_GRD_SHOOT2 20 Shoot shoot3 171 | **shoot3** false SPR_GRD_SHOOT3 20 chase1 172 | **shoot4** false 0 chase1 173 | **shoot5** false 0 chase1 174 | **shoot6** false 0 chase1 175 | **shoot7** false 0 chase1 176 | **shoot8** false 0 chase1 177 | **shoot9** false 0 chase1 178 | 179 | **chase1** true SPR_GRD_W1_1 10 Chase chase1s 180 | **chase1s** true SPR_GRD_W1_1 3 chase2 181 | **chase2** true SPR_GRD_W2_1 8 Chase chase3 182 | **chase3** true SPR_GRD_W3_1 10 Chase chase3s 183 | **chase3s** true SPR_GRD_W3_1 3 chase4 184 | **chase4** true SPR_GRD_W4_1 8 Chase chase1 185 | 186 | **die1** false SPR_GRD_DIE_1 15 Death Scream die2 187 | **die2** false SPR_GRD_DIE_2 15 die3 188 | **die3** false SPR_GRD_DIE_3 15 dead 189 | **die4** false 0 dead 190 | **die5** false 0 dead 191 | **die6** false 0 dead 192 | **die7** false 0 dead 193 | **die8** false 0 dead 194 | **die9** false 0 dead 195 | 196 | **dead** false SPR_GRD_DEAD 0 dead 197 | =========== ========== ============== ======= ======= ============ ========== 198 | 199 | 200 | Officer 201 | ======= 202 | 203 | =========== ========== ============== ======= ======= ============ ======== 204 | State Can Rotate Base Sprite Timeout Thought Action Next State 205 | =========== ========== ============== ======= ======= ============ ======== 206 | **stand** true SPR_OFC_S_1 0 Stand stand 207 | 208 | **path1** true SPR_OFC_W1_1 20 Path path1s 209 | **path1s** true SPR_OFC_W1_1 5 path2 210 | **path2** true SPR_OFC_W2_1 15 Path path3 211 | **path3** true SPR_OFC_W3_1 20 Path path3s 212 | **path3s** true SPR_OFC_W3_1 5 path4 213 | **path4** true SPR_OFC_W4_1 15 Path path1 214 | 215 | **pain** false SPR_GRD_PAIN_1 10 chase1 216 | **pain1** false SPR_GRD_PAIN_2 10 chase1 217 | 218 | **shoot1** false SPR_GRD_SHOOT1 6 shoot2 219 | **shoot2** false SPR_GRD_SHOOT2 20 Shoot shoot3 220 | **shoot3** false SPR_GRD_SHOOT3 10 chase1 221 | **shoot4** false 0 chase1 222 | **shoot5** false 0 chase1 223 | **shoot6** false 0 chase1 224 | **shoot7** false 0 chase1 225 | **shoot8** false 0 chase1 226 | **shoot9** false 0 chase1 227 | 228 | **chase1** true SPR_OFC_W1_1 10 Chase chase1s 229 | **chase1s** true SPR_OFC_W1_1 3 chase2 230 | **chase2** true SPR_OFC_W2_1 8 Chase chase3 231 | **chase3** true SPR_OFC_W3_1 10 Chase chase3s 232 | **chase3s** true SPR_OFC_W3_1 3 chase4 233 | **chase4** true SPR_OFC_W4_1 8 Chase chase1 234 | 235 | **die1** false SPR_OFC_DIE_1 11 Death Scream die2 236 | **die2** false SPR_OFC_DIE_2 11 die3 237 | **die3** false SPR_OFC_DIE_3 11 dead 238 | **die4** false 0 dead 239 | **die5** false 0 dead 240 | **die6** false 0 dead 241 | **die7** false 0 dead 242 | **die8** false 0 dead 243 | **die9** false 0 dead 244 | 245 | **dead** false SPR_OFC_DEAD 0 dead 246 | =========== ========== ============== ======= ======= ============ ======== 247 | 248 | 249 | SS 250 | ==== 251 | 252 | =========== ========== ============= ======= ======= ============ ========== 253 | State Can Rotate Base Sprite Timeout Thought Action Next State 254 | =========== ========== ============= ======= ======= ============ ========== 255 | **stand** true SPR_SS_S_1 0 Stand stand 256 | 257 | **path1** true SPR_SS_W1_1 20 Path path1s 258 | **path1s** true SPR_SS_W1_1 5 path2 259 | **path2** true SPR_SS_W2_1 15 Path path3 260 | **path3** true SPR_SS_W3_1 20 Path path3s 261 | **path3s** true SPR_SS_W3_1 5 path4 262 | **path4** true SPR_SS_W4_1 15 Path path1 263 | 264 | **pain** false SPR_SS_PAIN_1 10 chase1 265 | **pain1** false SPR_SS_PAIN_2 10 chase1 266 | 267 | **shoot1** false SPR_SS_SHOOT1 20 shoot2 268 | **shoot2** false SPR_SS_SHOOT2 20 Shoot shoot3 269 | **shoot3** false SPR_SS_SHOOT3 10 chase1 270 | **shoot4** false SPR_SS_SHOOT2 10 Shoot chase1 271 | **shoot5** false SPR_SS_SHOOT3 10 chase1 272 | **shoot6** false SPR_SS_SHOOT2 10 Shoot chase1 273 | **shoot7** false SPR_SS_SHOOT3 10 chase1 274 | **shoot8** false SPR_SS_SHOOT2 10 Shoot chase1 275 | **shoot9** false SPR_SS_SHOOT3 10 chase1 276 | 277 | **chase1** true SPR_SS_W1_1 10 Chase chase1s 278 | **chase1s** true SPR_SS_W1_1 3 chase2 279 | **chase2** true SPR_SS_W2_1 8 Chase chase3 280 | **chase3** true SPR_SS_W3_1 10 Chase chase3s 281 | **chase3s** true SPR_SS_W3_1 3 chase4 282 | **chase4** true SPR_SS_W4_1 8 Chase chase1 283 | 284 | **die1** false SPR_SS_DIE_1 15 Death Scream die2 285 | **die2** false SPR_SS_DIE_2 15 die3 286 | **die3** false SPR_SS_DIE_3 15 dead 287 | **die4** false 0 dead 288 | **die5** false 0 dead 289 | **die6** false 0 dead 290 | **die7** false 0 dead 291 | **die8** false 0 dead 292 | **die9** false 0 dead 293 | 294 | **dead** false SPR_SS_DEAD 0 dead 295 | =========== ========== ============= ======= ======= ============ ========== 296 | 297 | 298 | Dog 299 | ==== 300 | 301 | Dogs have no pain because they have only one hit point. 302 | 303 | =========== ========== ============= ======= ======= ============ ========== 304 | State Can Rotate Base Sprite Timeout Thought Action Next State 305 | =========== ========== ============= ======= ======= ============ ========== 306 | **stand** false 0 stand 307 | 308 | **path1** true SPR_DOG_W1_1 20 Path path1s 309 | **path1s** true SPR_DOG_W1_1 5 path2 310 | **path2** true SPR_DOG_W2_1 15 Path path3 311 | **path3** true SPR_DOG_W3_1 20 Path path3s 312 | **path3s** true SPR_DOG_W3_1 5 path4 313 | **path4** true SPR_DOG_W4_1 15 Path path1 314 | 315 | **pain** false 10 chase1 316 | **pain1** false 10 chase1 317 | 318 | **shoot1** false SPR_DOG_JUMP1 20 shoot2 319 | **shoot2** false SPR_DOG_JUMP2 20 Shoot shoot3 320 | **shoot3** false SPR_DOG_JUMP3 10 chase1 321 | **shoot4** false SPR_DOG_JUMP2 10 Shoot chase1 322 | **shoot5** false SPR_DOG_W1_1 10 chase1 323 | **shoot6** false 10 Shoot chase1 324 | **shoot7** false 10 chase1 325 | **shoot8** false 10 Shoot chase1 326 | **shoot9** false 10 chase1 327 | 328 | **chase1** true SPR_DOG_W1_1 10 Chase chase1s 329 | **chase1s** true SPR_DOG_W1_1 3 chase2 330 | **chase2** true SPR_DOG_W2_1 8 Chase chase3 331 | **chase3** true SPR_DOG_W3_1 10 Chase chase3s 332 | **chase3s** true SPR_DOG_W3_1 3 chase4 333 | **chase4** true SPR_DOG_W4_1 8 Chase chase1 334 | 335 | **die1** false SPR_DOG_DIE_1 15 Death Scream die2 336 | **die2** false SPR_DOG_DIE_2 15 die3 337 | **die3** false SPR_DOG_DIE_3 15 dead 338 | **die4** false 0 dead 339 | **die5** false 0 dead 340 | **die6** false 0 dead 341 | **die7** false 0 dead 342 | **die8** false 0 dead 343 | **die9** false 0 dead 344 | 345 | **dead** false SPR_DOG_DEAD 0 dead 346 | =========== ========== ============= ======= ======= ============ ========== 347 | 348 | 349 | Hans Grosse 350 | =========== 351 | 352 | Hans has no pain and no patrol. 353 | 354 | =========== ========== =============== ======= ======= =============== ========== 355 | State Can Rotate Base Sprite Timeout Thought Action Next State 356 | =========== ========== =============== ======= ======= =============== ========== 357 | **stand** true SPR_BOSS_W1 0 Stand stand 358 | 359 | **path1** true 0 Path path1s 360 | **path1s** true 0 path2 361 | **path2** true 0 Path path3 362 | **path3** true 0 Path path3s 363 | **path3s** true 0 path4 364 | **path4** true 0 Path path1 365 | 366 | **pain** false 0 chase1 367 | **pain1** false 0 chase1 368 | 369 | **shoot1** false SPR_BOSS_SHOOT1 30 shoot2 370 | **shoot2** false SPR_BOSS_SHOOT2 10 Shoot shoot3 371 | **shoot3** false SPR_BOSS_SHOOT3 10 Shoot chase4 372 | **shoot4** false SPR_BOSS_SHOOT2 10 Shoot chase5 373 | **shoot5** false SPR_BOSS_SHOOT3 10 Shoot chase6 374 | **shoot6** false SPR_BOSS_SHOOT2 10 Shoot chase7 375 | **shoot7** false SPR_BOSS_SHOOT3 10 Shoot chase8 376 | **shoot8** false SPR_BOSS_SHOOT1 10 chase1 377 | **shoot9** false 0 chase1 378 | 379 | **chase1** true SPR_BOSS_W1 10 Chase chase1s 380 | **chase1s** true SPR_BOSS_W1 3 chase2 381 | **chase2** true SPR_BOSS_W2 8 Chase chase3 382 | **chase3** true SPR_BOSS_W3 10 Chase chase3s 383 | **chase3s** true SPR_BOSS_W3 3 chase4 384 | **chase4** true SPR_BOSS_W4 8 Chase chase1 385 | 386 | **die1** false SPR_BOSS_DIE_1 15 Death Scream die2 387 | **die2** false SPR_BOSS_DIE_2 15 die3 388 | **die3** false SPR_BOSS_DIE_3 15 dead 389 | **die4** false 0 dead 390 | **die5** false 0 dead 391 | **die6** false 0 dead 392 | **die7** false 0 dead 393 | **die8** false 0 dead 394 | **die9** false 0 dead 395 | 396 | **dead** false SPR_BOSS_DEAD 0 Start Death Cam dead 397 | =========== ========== =============== ======= ======= =============== ========== 398 | 399 | 400 | Dr. Schabbs 401 | =========== 402 | 403 | =========== ========== ====================== ======= ========== =============== ========== 404 | State Can Rotate Base Sprite Timeout Thought Action Next State 405 | =========== ========== ====================== ======= ========== =============== ========== 406 | **stand** false SPR_SCHABB_W1 0 Stand stand 407 | 408 | **path1** false 0 path1s 409 | **path1s** false 0 path2 410 | **path2** false 0 path3 411 | **path3** false 0 path3s 412 | **path3s** false 0 path4 413 | **path4** false 0 path1 414 | 415 | **pain** false 0 chase1 416 | **pain1** false 0 chase1 417 | 418 | **shoot1** false SPR_SCHABB_SHOOT1 30 shoot2 419 | **shoot2** false SPR_SCHABB_SHOOT2 10 Launch chase1 420 | **shoot3** false 10 chase1 421 | **shoot4** false 10 chase1 422 | **shoot5** false 10 chase1 423 | **shoot6** false 10 chase1 424 | **shoot7** false 10 chase1 425 | **shoot8** false 10 chase1 426 | **shoot9** false 0 chase1 427 | 428 | **chase1** false SPR_SCHABB_W1 10 Boss Chase chase1s 429 | **chase1s** false SPR_SCHABB_W1 3 chase2 430 | **chase2** false SPR_SCHABB_W2 8 Boss Chase chase3 431 | **chase3** false SPR_SCHABB_W3 10 Boss Chase chase3s 432 | **chase3s** false SPR_SCHABB_W3 3 chase4 433 | **chase4** false SPR_SCHABB_W4 8 Boss Chase chase1 434 | 435 | **die1** false SPR_SCHABB_SCHABB_W1 10 Death Scream die2 436 | **die2** false SPR_SCHABB_SCHABB_W1 10 die3 437 | **die3** false SPR_SCHABB_SCHABB_DIE1 10 die4 438 | **die4** false SPR_SCHABB_SCHABB_DIE2 10 die5 439 | **die5** false SPR_SCHABB_SCHABB_DIE3 10 die6 440 | **die6** false 0 dead 441 | **die7** false 0 dead 442 | **die8** false 0 dead 443 | **die9** false 0 dead 444 | 445 | **dead** false SPR_SCHABB_DEAD 0 Start Death Cam dead 446 | =========== ========== ====================== ======= ========== =============== ========== 447 | 448 | 449 | Fake Hitler 450 | =========== 451 | 452 | =========== ========== ============== ======= ========== ============ ========== 453 | State Can Rotate Base Sprite Timeout Thought Action Next State 454 | =========== ========== ============== ======= ========== ============ ========== 455 | **stand** false SPR_FAKE_W1 0 Stand stand 456 | 457 | **path1** false 0 path1s 458 | **path1s** false 0 path2 459 | **path2** false 0 path3 460 | **path3** false 0 path3s 461 | **path3s** false 0 path4 462 | **path4** false 0 path1 463 | 464 | **pain** false 0 chase1 465 | **pain1** false 0 chase1 466 | 467 | **shoot1** false SPR_FAKE_SHOOT 8 Launch shoot2 468 | **shoot2** false SPR_FAKE_SHOOT 8 Launch shoot3 469 | **shoot3** false SPR_FAKE_SHOOT 8 Launch shoot4 470 | **shoot4** false SPR_FAKE_SHOOT 8 Launch shoot5 471 | **shoot5** false SPR_FAKE_SHOOT 8 Launch shoot6 472 | **shoot6** false SPR_FAKE_SHOOT 8 Launch shoot7 473 | **shoot7** false SPR_FAKE_SHOOT 8 Launch shoot8 474 | **shoot8** false SPR_FAKE_SHOOT 8 Launch shoot9 475 | **shoot9** false SPR_FAKE_SHOOT 8 chase1 476 | 477 | **chase1** false SPR_FAKE_W1 10 Fake chase1s 478 | **chase1s** false SPR_FAKE_W1 3 chase2 479 | **chase2** false SPR_FAKE_W2 8 Fake chase3 480 | **chase3** false SPR_FAKE_W3 10 Fake chase3s 481 | **chase3s** false SPR_FAKE_W3 3 chase4 482 | **chase4** false SPR_FAKE_W4 8 Fake chase1 483 | 484 | **die1** false SPR_FAKE_DIE1 10 Death Scream die2 485 | **die2** false SPR_FAKE_DIE2 10 die3 486 | **die3** false SPR_FAKE_DIE3 10 die4 487 | **die4** false SPR_FAKE_DIE4 10 die5 488 | **die5** false SPR_FAKE_DIE5 10 dead 489 | **die6** false 0 dead 490 | **die7** false 0 dead 491 | **die8** false 0 dead 492 | **die9** false 0 dead 493 | 494 | **dead** false SPR_FAKE_DEAD 0 dead 495 | =========== ========== ============== ======= ========== ============ ========== 496 | 497 | 498 | Mecha Hitler 499 | ============ 500 | 501 | =========== ========== ================ ======= ========== ============ ========== 502 | State Can Rotate Base Sprite Timeout Thought Action Next State 503 | =========== ========== ================ ======= ========== ============ ========== 504 | **stand** false SPR_MECHA_W1 0 Stand stand 505 | 506 | **path1** false 0 path1s 507 | **path1s** false 0 path2 508 | **path2** false 0 path3 509 | **path3** false 0 path3s 510 | **path3s** false 0 path4 511 | **path4** false 0 path1 512 | 513 | **pain** false 0 chase1 514 | **pain1** false 0 chase1 515 | 516 | **shoot1** false SPR_MECHA_SHOOT1 30 shoot2 517 | **shoot2** false SPR_MECHA_SHOOT2 10 Shoot shoot3 518 | **shoot3** false SPR_MECHA_SHOOT3 10 Shoot shoot4 519 | **shoot4** false SPR_MECHA_SHOOT2 10 Shoot shoot5 520 | **shoot5** false SPR_MECHA_SHOOT3 10 Shoot shoot6 521 | **shoot6** false SPR_MECHA_SHOOT2 10 Shoot shoot7 522 | **shoot7** false 0 shoot8 523 | **shoot8** false 0 shoot9 524 | **shoot9** false 0 chase1 525 | 526 | **chase1** false SPR_MECHA_W1 10 Chase Mecha Sound chase1s 527 | **chase1s** false SPR_MECHA_W1 6 chase2 528 | **chase2** false SPR_MECHA_W2 8 Chase chase3 529 | **chase3** false SPR_MECHA_W3 10 Chase Mecha Sound chase3s 530 | **chase3s** false SPR_MECHA_W3 6 chase4 531 | **chase4** false SPR_MECHA_W4 8 Chase chase1 532 | 533 | **die1** false SPR_MECHA_DIE1 10 Death Scream die2 534 | **die2** false SPR_MECHA_DIE2 10 die3 535 | **die3** false SPR_MECHA_DIE3 10 Hitler Morph dead 536 | **die4** false 0 dead 537 | **die5** false 0 dead 538 | **die6** false 0 dead 539 | **die7** false 0 dead 540 | **die8** false 0 dead 541 | **die9** false 0 dead 542 | 543 | **dead** false SPR_MECHA_DEAD 0 dead 544 | =========== ========== ================ ======= ========== ============ ========== 545 | 546 | 547 | Adolf Hitler 548 | ============ 549 | 550 | =========== ========== ================= ======= ========== =============== ========== 551 | State Can Rotate Base Sprite Timeout Thought Action Next State 552 | =========== ========== ================= ======= ========== =============== ========== 553 | **stand** false 0 Stand stand 554 | 555 | **path1** false 0 path1s 556 | **path1s** false 0 path2 557 | **path2** false 0 path3 558 | **path3** false 0 path3s 559 | **path3s** false 0 path4 560 | **path4** false 0 path1 561 | 562 | **pain** false 0 chase1 563 | **pain1** false 0 chase1 564 | 565 | **shoot1** false SPR_HITLER_SHOOT1 30 shoot2 566 | **shoot2** false SPR_HITLER_SHOOT2 10 Shoot shoot3 567 | **shoot3** false SPR_HITLER_SHOOT3 10 Shoot shoot4 568 | **shoot4** false SPR_HITLER_SHOOT2 10 Shoot shoot5 569 | **shoot5** false SPR_HITLER_SHOOT3 10 Shoot shoot6 570 | **shoot6** false SPR_HITLER_SHOOT2 10 Shoot shoot7 571 | **shoot7** false 0 shoot8 572 | **shoot8** false 0 shoot9 573 | **shoot9** false 0 chase1 574 | 575 | **chase1** false SPR_HITLER_W1 6 Chase chase1s 576 | **chase1s** false SPR_HITLER_W1 4 chase2 577 | **chase2** false SPR_HITLER_W2 2 Chase chase3 578 | **chase3** false SPR_HITLER_W3 6 Chase chase3s 579 | **chase3s** false SPR_HITLER_W3 4 chase4 580 | **chase4** false SPR_HITLER_W4 2 Chase chase1 581 | 582 | **die1** false SPR_HITLER_W1 1 Death Scream die2 583 | **die2** false SPR_HITLER_W1 10 die3 584 | **die3** false SPR_HITLER_DIE1 10 Hitler Morph die4 585 | **die4** false SPR_HITLER_DIE2 10 die5 586 | **die5** false SPR_HITLER_DIE3 10 die6 587 | **die6** false SPR_HITLER_DIE4 10 die7 588 | **die7** false SPR_HITLER_DIE5 10 die8 589 | **die8** false SPR_HITLER_DIE6 10 die9 590 | **die9** false SPR_HITLER_DIE7 10 dead 591 | 592 | **dead** false SPR_HITLER_DEAD 0 Start Death Cam dead 593 | =========== ========== ================= ======= ========== =============== ========== 594 | 595 | 596 | Mutant 597 | ====== 598 | 599 | =========== ========== ============== ======= ========== ============ ========== 600 | State Can Rotate Base Sprite Timeout Thought Action Next State 601 | =========== ========== ============== ======= ========== ============ ========== 602 | **stand** true SPR_MUT_S_1 0 Stand stand 603 | 604 | **path1** true SPR_MUT_W1_1 20 Path path1s 605 | **path1s** true SPR_MUT_W1_1 5 path2 606 | **path2** true SPR_MUT_W2_1 15 Path path3 607 | **path3** true SPR_MUT_W3_1 20 Path path3s 608 | **path3s** true SPR_MUT_W3_1 5 path4 609 | **path4** true SPR_MUT_W4_1 15 Path path1 610 | 611 | **pain** false SPR_MUT_PAIN_1 10 chase1 612 | **pain1** false SPR_MUT_PAIN_2 10 chase1 613 | 614 | **shoot1** false SPR_MUT_SHOOT1 6 shoot2 615 | **shoot2** false SPR_MUT_SHOOT2 20 Shoot shoot3 616 | **shoot3** false SPR_MUT_SHOOT3 10 Shoot shoot4 617 | **shoot4** false SPR_MUT_SHOOT4 20 Shoot shoot5 618 | **shoot5** false 0 Shoot shoot6 619 | **shoot6** false 0 Shoot chase1 620 | **shoot7** false 0 chase1 621 | **shoot8** false 0 chase1 622 | **shoot9** false 0 chase1 623 | 624 | **chase1** true SPR_MUT_W1_1 10 Chase chase1s 625 | **chase1s** true SPR_MUT_W1_1 3 chase2 626 | **chase2** true SPR_MUT_W2_1 8 Chase chase3 627 | **chase3** true SPR_MUT_W3_1 10 Chase chase3s 628 | **chase3s** true SPR_MUT_W3_1 3 chase4 629 | **chase4** true SPR_MUT_W4_1 8 Chase chase1 630 | 631 | **die1** false SPR_MUT_DIE_1 7 Death Scream die2 632 | **die2** false SPR_MUT_DIE_2 7 die3 633 | **die3** false SPR_MUT_DIE_3 7 die4 634 | **die4** false SPR_MUT_DIE_4 7 dead 635 | **die5** false 0 dead 636 | **die6** false 0 dead 637 | **die7** false 0 dead 638 | **die8** false 0 dead 639 | **die9** false 0 dead 640 | 641 | **dead** false SPR_MUT_DEAD 0 dead 642 | =========== ========== ============== ======= ========== ============ ========== 643 | 644 | 645 | Blinky 646 | ====== 647 | 648 | =========== ========== ============= ======= ======= ====== ========== 649 | State Can Rotate Base Sprite Timeout Thought Action Next State 650 | =========== ========== ============= ======= ======= ====== ========== 651 | **stand** false 0 stand 652 | 653 | **path1** false 0 path1s 654 | **path1s** false 0 path2 655 | **path2** false 0 path3 656 | **path3** false 0 path3s 657 | **path3s** false 0 path4 658 | **path4** false 0 path1 659 | 660 | **pain** false 0 chase1 661 | **pain1** false 0 chase1 662 | 663 | **shoot1** false 0 shoot2 664 | **shoot2** false 0 shoot3 665 | **shoot3** false 0 shoot4 666 | **shoot4** false 0 shoot5 667 | **shoot5** false 0 shoot6 668 | **shoot6** false 0 chase1 669 | **shoot7** false 0 shoot8 670 | **shoot8** false 0 shoot9 671 | **shoot9** false 0 chase1 672 | 673 | **chase1** false SPR_BLINKY_W1 10 Ghosts chase2 674 | **chase1s** false 0 chase2 675 | **chase2** false SPR_BLINKY_W2 10 Ghosts chase1 676 | **chase3** false 0 chase3s 677 | **chase3s** false 0 chase4 678 | **chase4** false 0 chase1 679 | 680 | **die1** false 10 die2 681 | **die2** false 10 die3 682 | **die3** false 10 dead 683 | **die4** false 0 dead 684 | **die5** false 0 dead 685 | **die6** false 0 dead 686 | **die7** false 0 dead 687 | **die8** false 0 dead 688 | **die9** false 0 dead 689 | 690 | **dead** false 0 dead 691 | =========== ========== ============= ======= ======= ====== ========== 692 | 693 | 694 | Clyde 695 | ===== 696 | 697 | =========== ========== ============ ======= ======= ====== ========== 698 | State Can Rotate Base Sprite Timeout Thought Action Next State 699 | =========== ========== ============ ======= ======= ====== ========== 700 | **stand** false 0 stand 701 | 702 | **path1** false 0 path1s 703 | **path1s** false 0 path2 704 | **path2** false 0 path3 705 | **path3** false 0 path3s 706 | **path3s** false 0 path4 707 | **path4** false 0 path1 708 | 709 | **pain** false 0 chase1 710 | **pain1** false 0 chase1 711 | 712 | **shoot1** false 0 shoot2 713 | **shoot2** false 0 shoot3 714 | **shoot3** false 0 shoot4 715 | **shoot4** false 0 shoot5 716 | **shoot5** false 0 shoot6 717 | **shoot6** false 0 chase1 718 | **shoot7** false 0 shoot8 719 | **shoot8** false 0 shoot9 720 | **shoot9** false 0 chase1 721 | 722 | **chase1** false SPR_CLYDE_W1 10 Ghosts chase2 723 | **chase1s** false 0 chase2 724 | **chase2** false SPR_CLYDE_W2 10 Ghosts chase1 725 | **chase3** false 0 chase3s 726 | **chase3s** false 0 chase4 727 | **chase4** false 0 chase1 728 | 729 | **die1** false 10 die2 730 | **die2** false 10 die3 731 | **die3** false 10 dead 732 | **die4** false 0 dead 733 | **die5** false 0 dead 734 | **die6** false 0 dead 735 | **die7** false 0 dead 736 | **die8** false 0 dead 737 | **die9** false 0 dead 738 | 739 | **dead** false 0 dead 740 | =========== ========== ============ ======= ======= ====== ========== 741 | 742 | 743 | Pinky 744 | ===== 745 | 746 | =========== ========== ============ ======= ======= ====== ========== 747 | State Can Rotate Base Sprite Timeout Thought Action Next State 748 | =========== ========== ============ ======= ======= ====== ========== 749 | **stand** false 0 stand 750 | 751 | **path1** false 0 path1s 752 | **path1s** false 0 path2 753 | **path2** false 0 path3 754 | **path3** false 0 path3s 755 | **path3s** false 0 path4 756 | **path4** false 0 path1 757 | 758 | **pain** false 0 chase1 759 | **pain1** false 0 chase1 760 | 761 | **shoot1** false 0 shoot2 762 | **shoot2** false 0 shoot3 763 | **shoot3** false 0 shoot4 764 | **shoot4** false 0 shoot5 765 | **shoot5** false 0 shoot6 766 | **shoot6** false 0 chase1 767 | **shoot7** false 0 shoot8 768 | **shoot8** false 0 shoot9 769 | **shoot9** false 0 chase1 770 | 771 | **chase1** false SPR_PINKY_W1 10 Ghosts chase2 772 | **chase1s** false 0 chase2 773 | **chase2** false SPR_PINKY_W2 10 Ghosts chase1 774 | **chase3** false 0 chase3s 775 | **chase3s** false 0 chase4 776 | **chase4** false 0 chase1 777 | 778 | **die1** false 10 die2 779 | **die2** false 10 die3 780 | **die3** false 10 dead 781 | **die4** false 0 dead 782 | **die5** false 0 dead 783 | **die6** false 0 dead 784 | **die7** false 0 dead 785 | **die8** false 0 dead 786 | **die9** false 0 dead 787 | 788 | **dead** false 0 dead 789 | =========== ========== ============ ======= ======= ====== ========== 790 | 791 | 792 | Inky 793 | ==== 794 | 795 | =========== ========== =========== ======= ======= ====== ========== 796 | State Can Rotate Base Sprite Timeout Thought Action Next State 797 | =========== ========== =========== ======= ======= ====== ========== 798 | **stand** false 0 stand 799 | 800 | **path1** false 0 path1s 801 | **path1s** false 0 path2 802 | **path2** false 0 path3 803 | **path3** false 0 path3s 804 | **path3s** false 0 path4 805 | **path4** false 0 path1 806 | 807 | **pain** false 0 chase1 808 | **pain1** false 0 chase1 809 | 810 | **shoot1** false 0 shoot2 811 | **shoot2** false 0 shoot3 812 | **shoot3** false 0 shoot4 813 | **shoot4** false 0 shoot5 814 | **shoot5** false 0 shoot6 815 | **shoot6** false 0 chase1 816 | **shoot7** false 0 shoot8 817 | **shoot8** false 0 shoot9 818 | **shoot9** false 0 chase1 819 | 820 | **chase1** false SPR_INKY_W1 10 Ghosts chase2 821 | **chase1s** false 0 chase2 822 | **chase2** false SPR_INKY_W2 10 Ghosts chase1 823 | **chase3** false 0 chase3s 824 | **chase3s** false 0 chase4 825 | **chase4** false 0 chase1 826 | 827 | **die1** false 10 die2 828 | **die2** false 10 die3 829 | **die3** false 10 dead 830 | **die4** false 0 dead 831 | **die5** false 0 dead 832 | **die6** false 0 dead 833 | **die7** false 0 dead 834 | **die8** false 0 dead 835 | **die9** false 0 dead 836 | 837 | **dead** false 0 dead 838 | =========== ========== =========== ======= ======= ====== ========== 839 | -------------------------------------------------------------------------------- /Age of Wonders/Addendum.rst: -------------------------------------------------------------------------------- 1 | .. The following is an accurate replication of the *Age of Wonders* Mannual 2 | Addendum, as published by the Stratos Group, in reStructuredText format. 3 | 4 | The source of original document is not available, only pre-built PDFs are in 5 | circulation and the Stratos Group no longer exits. This is an effort to 6 | preserve the addendum in an open format for possible further conversion. 7 | 8 | The original format and content have been preserved as much as possible, 9 | including all hyperlinks, regardless of whether their targets actually exist 10 | anymore. Similarly, the text has been copy-pasted, so any errors that might 11 | exist are from the original source and will not be fixed. 12 | 13 | Changes from original: 14 | ---------------------- 15 | 16 | - Centered text on first page is left-aligned because text alignment cannot 17 | be specified in reST. 18 | - Same with the note below *Manual Correction and Updates*. 19 | - Not applicable table items are written as ``\-\``, this is needed to escape 20 | the dashes to prevent them form being rendred as bullets. The string still 21 | renders as a ``-``, like in the original. 22 | 23 | ============================== 24 | Age of Wonders Manual Addendum 25 | ============================== 26 | 27 | About this Addendum: 28 | ==================== 29 | 12-20-99 Version 2.3 30 | 31 | This represents the second release of the Age of Wonders manual addendum. 32 | Version 2.3 reflects the changes made with the Age of Wonders 1.2 patch and 33 | corrections to errors in the previous version. If you have any suggestions for 34 | future improvements, please keep the constructive criticism coming. Please visit 35 | the `Age of Wonders Website `_ and post your 36 | thoughts to the forum. 37 | 38 | Written for the Players 39 | 40 | **Special Thanks to:** 41 | 42 | Lennart, Ray, Josh, Arno and everyone at Triumph who works on the game and whom 43 | make a Wonderous effort to listen to the players ideas and make them a reality. 44 | 45 | Thanks to peZLand for formatting the Addendum as cool as possible. 46 | 47 | Feedback or questions about the addendum can be e-mailed to Nordramor at 48 | nordramor@stratosgroup.com 49 | 50 | ©1999 Gathering of Developers I, Ltd. All rights reserved. The software and 51 | related manual for this product are copyrighted. `Gathering of Developers 52 | Website `_ 53 | 54 | Age of Wonders, the Age of Wonders logo, Triumph Software, and the Triumph logo 55 | are trademarks of Triumph Software, Inc. Copyright © 1999 Triumph Software, Inc. 56 | All Rights Reserved. 57 | 58 | Compiled and authored by the Stratos Group™, ©1999, `Stratos Group Website 59 | `_ 60 | 61 | Race Relations and Morale 62 | ========================= 63 | 64 | Default Initial Race Relations 65 | ------------------------------ 66 | (These can vary due to different scenario settings) 67 | 68 | ========= ===== ===== ====== ===== ====== ======== ===== ===== ======= ===== ====== ====== 69 | .. Human Azrac Lizard Frost Elf Halfling Dwarf High D\. Elf Orc Goblin Undead 70 | ========= ===== ===== ====== ===== ====== ======== ===== ===== ======= ===== ====== ====== 71 | Human *F* P P P N N N P N N N W 72 | Azrac P *F* N N N N N W N N P W 73 | Lizard P N *F* P N N N W N N N W 74 | Frostling P N P *F* N N N W N N N W 75 | Elf N N N N *F* *F* P *F* **H** **H** **H** **H** 76 | Halfling N N N N *F* *F* *F* P **H** **H** **H** **H** 77 | Dwarf N N N N P *F* *F* *F* **H** **H** **H** **H** 78 | Highmen P W W W *F* P *F* *F* **H** **H** **H** **H** 79 | Dark Elf *F* N N N **H** **H** **H** **H** *F* *F* P P 80 | Orc N N N N **H** **H** **H** **H** *F* *F* *F* P 81 | Goblin N P N N **H** **H** **H** **H** P *F* *F* P 82 | Undead W W W W **H** **H** **H** **H** P P P *F* 83 | ========= ===== ===== ====== ===== ====== ======== ===== ===== ======= ===== ====== ====== 84 | 85 | .. Comment: the slash in front of the *D* for the Dark Elves escapes it, 86 | otherwise the *D.* will be treated like the fourth item in a numbered list. 87 | 88 | :F: Friendly 89 | :P: Polite 90 | :N: Neutral 91 | :W: Wary 92 | :H: Hate 93 | 94 | Race Relation Modifiers 95 | ----------------------- 96 | Each race relation type has a point range assigned to it: 97 | 98 | ============= ========================= 99 | Race Relation Race Relation Point Range 100 | ============= ========================= 101 | Friendly 80 - 100 102 | Polite 60 - 79 103 | Neutral 40 - 59 104 | Wary 20 - 39 105 | Hate 0 - 19 106 | ============= ========================= 107 | 108 | The following actions will either improve or worsen your race relationships: 109 | 110 | ============================================== ============================ 111 | Action Towards Race Race Realtion Point Modifier 112 | ============================================== ============================ 113 | Raze city of race \- 30 114 | Loot city of race \- 30 115 | Migrate from race \- 15 116 | Migrate to race \+ 10 117 | Upgrade city of race \+ 5 118 | Upgrade walls of race's city \+ 5 119 | Cancel looting of race's city \+ 20 120 | New game turn (until default relation reached) \+ 1 or - 1 121 | ============================================== ============================ 122 | 123 | .. Comment: The slash in front of the plus and minus signs is to escape them, 124 | otherwise they will be interpreted as bullets for an unnumbered list. 125 | 126 | ============================== ============================ 127 | Diplomatic Action Towards Race Race Realtion Point Modifier 128 | ============================== ============================ 129 | Making Alliance \+ 20 130 | Breaking Alliance \+ 20 131 | Making Peace \+ 20 132 | Breaking Peace/Declaring War \+ 20 133 | ============================== ============================ 134 | 135 | Diplomatic actions can affects your race relationship with races not directly 136 | involved in the action. Example: Declaring war on the Elves will likely hurt 137 | your race relationship with the Halflings, but help your race relationship with 138 | the Orcs. The indirect impact of diplomatic actions varies from race to race and 139 | from action to action. The stronger the action, the greater the indirect race 140 | relation impact. 141 | 142 | Unit Morale 143 | ----------- 144 | Unit morale is a reflection of a unit’s willingness to fight for your empire. A 145 | unit’s morale is equal to your race relation with the unit’s race plus or minus 146 | and modifiers. Machines, like Battering Rams, have no morale value and never 147 | receive stat penalties or figure into party status decisions. 148 | 149 | =========== ======================= ========================= 150 | Unit Morale Unit Morale Point Range Unit Stat Modifiers 151 | =========== ======================= ========================= 152 | High 80 - 100 None 153 | Good 60 - 79 None 154 | Okay 40 - 59 None 155 | Poor 20 - 39 -1 Defense, -1 Resistance 156 | Terrible 0 - 19 -2 Defense, -2 Resistance 157 | =========== ======================= ========================= 158 | 159 | If applicable, the following factors are added or subtracted from your race 160 | relation points when determining a unit’s morale. 161 | 162 | ================================ ========================== 163 | Name Unit Morale Point Modifier 164 | ================================ ========================== 165 | Friendly Terrain +10 166 | Hostile Terrain -10 167 | Panicked -40 168 | Fear Trauma -40 169 | Insufficient upkeep 0 to -50 (5 turns) 170 | Unit with Bard’s skills in party +10 171 | Hostile unit in party -10 (each unit) 172 | ================================ ========================== 173 | 174 | Party Status 175 | ------------ 176 | Party status is a reflection of the overall morale of all units in the party. If 177 | the majority of the party contains units with okay, good, or high morale, the 178 | party status will be stable, content, or cheerful. A stable or better party 179 | status means no units in that party will desert or rebel. If, however, units 180 | with poor or terrible morale are in the majority, the party status will fall 181 | into unrest or unruly and their will be a chance each turn the units from that 182 | party will defect or rebel against your leadership. Higher-level units exert 183 | more influence in party status decisions than do lower- level units. Examples: 184 | An Orc Red Dragon with terrible morale will require a multiple Dwarven Giants 185 | with high morale to effectively suppress, while an Elf Archer with good morale 186 | can typically suppress a Goblin Spearman with poor morale. 187 | 188 | ================= ============================ 189 | Party Status Name Chance of Desertion per Turn 190 | ================= ============================ 191 | Cheerful 0% 192 | Content 0% 193 | Stable 0% 194 | Unrest 10% 195 | Unruly 50% 196 | ================= ============================ 197 | 198 | City Status 199 | ----------- 200 | Each city has a unique relationship with your empire. City status falls into two 201 | separate scales, hostile cities and friendly cities. To determine a city’s 202 | status, start with your race relation value point value, then apply any 203 | applicable modifiers listed below. There are two separate scales listed, the 204 | first is for cities with whom your race relation (not city status) with the 205 | population is neutral, polite, or friendly. The second scale is for cities with 206 | whom your race relation (not city status) with the population is wary or hate. 207 | 208 | +---------------------------+-------------------------+---------------------+ 209 | | City Status for Friendly, | City Status Point Range | Chance of Rebellion | 210 | | Polite, and Neutral Race | | per Turn | 211 | | Relations | | | 212 | +===========================+=========================+=====================+ 213 | | Cheerful | 80 - 100 | 0% | 214 | +---------------------------+-------------------------+---------------------+ 215 | | Content | 60 - 79 | 0% | 216 | +---------------------------+-------------------------+---------------------+ 217 | | Stable | 40 - 59 | 0% | 218 | +---------------------------+-------------------------+---------------------+ 219 | 220 | +-------------------------+-------------------------+---------------------+ 221 | | City Status for Hate, | City Status Point Range | Chance of Rebellion | 222 | | and Wary Race Relations | | per Turn | 223 | +=========================+=========================+=====================+ 224 | | Enslaved | 80 - 100 | 0% | 225 | +-------------------------+-------------------------+---------------------+ 226 | | Oppressed | 60 - 79 | 0% | 227 | +-------------------------+-------------------------+---------------------+ 228 | | Stable | 40 - 59 | 0% | 229 | +-------------------------+-------------------------+---------------------+ 230 | | Unrest | 20 - 39 | 10% | 231 | +-------------------------+-------------------------+---------------------+ 232 | | Unruly | 0 - 19 | 50% | 233 | +-------------------------+-------------------------+---------------------+ 234 | 235 | ======================= ============================ 236 | Name City Relation Point Modifier 237 | ======================= ============================ 238 | Friendly Terrain +50 239 | Hostile Terrain +50 240 | Wooden Wall +50 241 | Stone Wall +50 242 | Hate relation +50 243 | Wary relation +50 244 | Neutral relation +50 245 | Polite relation +50 246 | Friendly relation +50 247 | Strong occupied forces +50 248 | Average occupied forces +50 249 | Weak occupied forces +50 250 | ======================= ============================ 251 | 252 | Racial Friendly/Hostile Terrains for City Status/Unit Morale 253 | ============================================================ 254 | 255 | ========= ========================== ========================== 256 | Race Name Racial Friendly Terrains Racial Hostile Terrains 257 | ========= ========================== ========================== 258 | Acrac Desert Snow, Ice, Underground Ice 259 | Dark Elf Dirt None 260 | Dwarf Dirt None 261 | Elf Grass Wasteland 262 | Frostling Snow, Ice, Underground Ice Desert 263 | Goblin Dirt None 264 | Halfling Grass Wasteland 265 | Highman None None 266 | Human None None 267 | Lizardman Water Desert, Wasteland 268 | Orc None None 269 | Undead Wasteland Grass 270 | ========= ========================== ========================== 271 | 272 | Upkeep Costs 273 | ============ 274 | 275 | ============= =============================== 276 | Name Gold Upkeep per Turn 277 | ============= =============================== 278 | Level 1 Unit 4 279 | Level 2 Unit 6 280 | Level 3 Unit 8 281 | Level 4 Unit 10 282 | Hero Upkeep 5 + (2 * Hero Experience Level) 283 | Leader Upkeep 0 284 | ============= =============================== 285 | 286 | =============== ==================== 287 | Name Mana Upkeep per Turn 288 | =============== ==================== 289 | Air Elemental 12 290 | Black Dragon 12 291 | Black Spider 6 292 | Earth Elemental 12 293 | Fire Elemental 12 294 | Fire Sprite 6 295 | Giant Frog 4 296 | Gold Dragon 8 297 | Great Eagle 6 298 | Water Elemental 12 299 | Wild Boar 4 300 | =============== ==================== 301 | 302 | Attack Ranges 303 | ============= 304 | 305 | ========== ============== 306 | Range Name Range in Hexes 307 | ========== ============== 308 | Touch 0 309 | Melee 0 310 | Short 4 311 | Medium 8 312 | Long 12 313 | ========== ============== 314 | 315 | Attack Abilities 316 | ================ 317 | 318 | +---------------------+--------+----------+----------+------------+------------+ 319 | | Name | Range | Attack | Damage | Repetition | Type | 320 | +=====================+========+==========+==========+============+============+ 321 | | Archery | Medium | 4 | 2 | 2 | Physical | 322 | +---------------------+--------+----------+----------+------------+------------+ 323 | | Black Bolts | Medium | 6 | 3 | 1 | Death | 324 | +---------------------+--------+----------+----------+------------+------------+ 325 | | Black Breath | Short | 7 | 5 | 1 | Death | 326 | +---------------------+--------+----------+----------+------------+------------+ 327 | | Call Flames | Medium | 5 | 4 | 1 | Fire | 328 | +---------------------+--------+----------+----------+------------+------------+ 329 | | Charm | Touch | 5 | X | 1 | Special | 330 | +---------------------+--------+----------+----------+------------+------------+ 331 | | Cold Breath | Short | 7 | 5 | 1 | Cold | 332 | +---------------------+--------+----------+----------+------------+------------+ 333 | | Cold Strike | Melee | Unit’s | Unit’s | 2 | Cold, | 334 | | | | Attack | Damage | | Physical | 335 | +---------------------+--------+----------+----------+------------+------------+ 336 | | Death Strike | Melee | Unit’s | Unit’s | 2 | Death, | 337 | | | | Attack | Damage | | Physical | 338 | +---------------------+--------+----------+----------+------------+------------+ 339 | | Divine Breath | Short | 7 | 5 | 1 | Holy | 340 | +---------------------+--------+----------+----------+------------+------------+ 341 | | Dominate | Touch | 6 | X | 1 | Special | 342 | +---------------------+--------+----------+----------+------------+------------+ 343 | | Doom Gaze | Long | 6 | 5 | 1 | Death | 344 | +---------------------+--------+----------+----------+------------+------------+ 345 | | Entangle | Touch | 7 | X | 1 | Special | 346 | +---------------------+--------+----------+----------+------------+------------+ 347 | | Entagle Strike | Melee | Unit's | Unit's | 2 | Entangle, | 348 | | | | Attack | Damage | | Physical | 349 | +---------------------+--------+----------+----------+------------+------------+ 350 | | Fire Breath | Short | 7 | 5 | 1 | Fire | 351 | +---------------------+--------+----------+----------+------------+------------+ 352 | | Fire Cannon | Long | 5 | 8 | 1 | Physical, | 353 | | | | | | | Wall | 354 | +---------------------+--------+----------+----------+------------+------------+ 355 | | Fire Musket | Long | 7 | 5 | 1 | Physical | 356 | +---------------------+--------+----------+----------+------------+------------+ 357 | | Fire Strike | Melee | Unit's | Unit's | 2 | Fire, | 358 | | | | Attack | Damage | | Physical | 359 | +---------------------+--------+----------+----------+------------+------------+ 360 | | Flame Throwing | Short | 4 | 3 | 1 | Fire | 361 | +---------------------+--------+----------+----------+------------+------------+ 362 | | Frost Bolts | Medium | 6 | 3 | 1 | Cold | 363 | +---------------------+--------+----------+----------+------------+------------+ 364 | | Holy Bolts | Medium | 6 | 3 | 1 | Holy | 365 | +---------------------+--------+----------+----------+------------+------------+ 366 | | Holy Strike | Melee | Unit's | Unit's | 2 | Holy, | 367 | | | | Attack | Damage | | Physical | 368 | +---------------------+--------+----------+----------+------------+------------+ 369 | | Hurl Boulder | Long | 3 | 7 | 1 | Physical, | 370 | | | | | | | Wall | 371 | +---------------------+--------+----------+----------+------------+------------+ 372 | | Hurl Boulder | Medium | 3 | 1 | 4 | Physical | 373 | +---------------------+--------+----------+----------+------------+------------+ 374 | | Invoke Death | Touch | 6 | X | 1 | Death | 375 | +---------------------+--------+----------+----------+------------+------------+ 376 | | Lightning Bolts | Medium | 6 | 3 | 1 | Lightning | 377 | +---------------------+--------+----------+----------+------------+------------+ 378 | | Lightning Strike | Melee | Unit's | Unit's | 2 | Lightning, | 379 | | | | Attack | Damage | | Physical | 380 | +---------------------+--------+----------+----------+------------+------------+ 381 | | Magic Bolts | Medium | 7 | 3 | 1 | Magic | 382 | +---------------------+--------+----------+----------+------------+------------+ 383 | | Magic Strike | Melee | Unit's | Unit's | 2 | Magic, | 384 | | | | Attack | Damage | | Physical | 385 | +---------------------+--------+----------+----------+------------+------------+ 386 | | Poison Darts | Medium | 4 | 1 | 3 | Poison | 387 | +---------------------+--------+----------+----------+------------+------------+ 388 | | Poison Strike | Melee | Unit's | Unit's | 2 | Physical, | 389 | | | | Attack | Damage | | Poison | 390 | +---------------------+--------+----------+----------+------------+------------+ 391 | | Possess | Touch | 5 | X | 1 | Special | 392 | +---------------------+--------+----------+----------+------------+------------+ 393 | | Round Attack | Melee | Unit's | Unit's | 2 | Physical | 394 | | | | Attack | Damage | | | 395 | +---------------------+--------+----------+----------+------------+------------+ 396 | | Seduce | Touch | 4 | X | 1 | Special | 397 | +---------------------+--------+----------+----------+------------+------------+ 398 | | Self Destruct | Touch | 7 | 6 | 1 | Fire, Wall | 399 | +---------------------+--------+----------+----------+------------+------------+ 400 | | Shoot Black Javelin | Long | 5 | 5 | 2 | Death, | 401 | | | | | | | Physical | 402 | +---------------------+--------+----------+----------+------------+------------+ 403 | | Shoot Javelin | Long | 5 | 5 | 2 | Physical | 404 | +---------------------+--------+----------+----------+------------+------------+ 405 | | Strike | Melee | Unit's | Unit's | 2 | Physical | 406 | | | | Attack | Damage | | | 407 | +---------------------+--------+----------+----------+------------+------------+ 408 | | Turn Undead | Touch | 3 + Turn | 3 + Turn | 1 | Special | 409 | | | | Level | Level | | | 410 | +---------------------+--------+----------+----------+------------+------------+ 411 | | Venomous Spit | Short | 5 | 4 | 1 | Poison | 412 | +---------------------+--------+----------+----------+------------+------------+ 413 | | Wall Crushing | Touch | 6 | 6 | 1 | Special | 414 | +---------------------+--------+----------+----------+------------+------------+ 415 | | Web | Touch | 4 | X | 1 | Special | 416 | +---------------------+--------+----------+----------+------------+------------+ 417 | 418 | Attack Ability Types 419 | ==================== 420 | 421 | ========= =============================================================== 422 | Name Attack Effects 423 | ========= =============================================================== 424 | Entagle Traps enemy in vines for 3 combat turns 425 | Fir Sets target aflame for 3 combat turns 426 | Cold Freezes the target for 3 combat turns 427 | Death Curses the target for 3 days 428 | Holy Curses target to suffer from vertigo for the duration of combat 429 | Lightning Stuns the target for 1 combat turn 430 | Magic None 431 | Physical None 432 | Poison Poisons target for 3 days 433 | Wall None, but attack can damage walls 434 | ========= =============================================================== 435 | 436 | Combat Mechanics 437 | ================ 438 | Each attack, spell, and ability will compare two stats and make a random roll 439 | to see if it succeeds. Some forms of attacks, abilities, and spells require 440 | multiple successful rolls to have any effect. Some attacks, abilities, and 441 | spells with multiple, different effects will make separate, individual rolls 442 | for each effect and apply only the effects that had successful rolls. Most 443 | rolls involve only the comparison of two stats to determine chance of success. 444 | 445 | +-------------------------------------+----------------------------------------+ 446 | | Default chance of success | 50% | 447 | +-------------------------------------+----------------------------------------+ 448 | | Difference in stats being compared | +10% for each point Attacker is higher | 449 | | (Attacker's Stat - Defender's Stat) | -10% for each point Defender is higher | 450 | +-------------------------------------+----------------------------------------+ 451 | | Minimum Chance of Success | 10% | 452 | +-------------------------------------+----------------------------------------+ 453 | | Maximum Chance of Success | 90% | 454 | +-------------------------------------+----------------------------------------+ 455 | 456 | Damage rolls are calculated differently. Damage is calculated and applied 457 | immediately after each successful hit, before any other rolls. Defender’s 458 | current Hit Points are subtracted by the final Damage amount. Units “die” 459 | immediately when their current Hit Points reach 0. A unit’s listed Damage stat 460 | is only used for melee damage calculations. Any shown Damage stat applies 461 | individually to each missile or melee strike in a volley. Attacks with high 462 | Attack stats (5+ greater than the targets Defense stat) have a higher Minimum 463 | Damage, but do not have a higher Maximum Damage. 464 | 465 | +--------------------------------+---------------------------------------------+ 466 | | Minimum Damage for when Attack | | 467 | | stat is not 5 greater than | 1 | 468 | | Defense Stat | | 469 | +--------------------------------+---------------------------------------------+ 470 | | Minimum Damage for when Attack | Minimum Damage increases above 1, but never | 471 | | stat is 5 or more greater than | exceeds Max Damage. The more the Attack | 472 | | Defense Stat | stat exceeds the Defense stat by 5, the | 473 | | | more Minimum Damage is raised. | 474 | +--------------------------------+---------------------------------------------+ 475 | | Maximum Damage | Stat listed on attacker's ability, spell | 476 | | | or unit. Archery's Damage stat = 2 = Max | 477 | | | Damage 2. Solar Flare Damage stat = 4 = Max | 478 | | | Damage 4. Unit's Damage stat = 3 = Max | 479 | | | Damage 4. | 480 | +--------------------------------+---------------------------------------------+ 481 | | Defender has Protection verus | Half (50%) Damage applied | 482 | | the Attack type. | | 483 | +--------------------------------+---------------------------------------------+ 484 | | Defender has Immunity versus | No (0%) Damage applied | 485 | | the Attack type | | 486 | +--------------------------------+---------------------------------------------+ 487 | 488 | Builder’s Guild and Shipyard Units 489 | ================================== 490 | 491 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 492 | | Name | Attack | Defense | Resistance | Damage | Hits | Moves | Abilities | 493 | +===========+========+=========+============+========+======+=======+==================+ 494 | | Builder | 1 | 2 | 3 | 1 | 5 | 20 | Walking, | 495 | | | | | | | | | Cold | 496 | | | | | | | | | Immunity, Poison | 497 | | | | | | | | | Immunity, | 498 | | | | | | | | | Fearless, | 499 | | | | | | | | | Construct | 500 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 501 | | Drill | 2 | 2 | 2 | 3 | 6 | 10 | Walking, Poison | 502 | | | | | | | | | Immunity, | 503 | | | | | | | | | Tunneling, | 504 | | | | | | | | | Fearless, Cold | 505 | | | | | | | | | Protection, Wall | 506 | | | | | | | | | Crushing | 507 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 508 | | Flame | 1 | 2 | 3 | 1 | 8 | 20 | Walking, Poison | 509 | | Thrower | | | | | | | Immunity, Flame | 510 | | | | | | | | | Throwing, | 511 | | | | | | | | | Fearless, | 512 | | | | | | | | | Cold Protection | 513 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 514 | | Dragon | 1 | 3 | 3 | 1 | 20 | 32 | Sailing, Poison | 515 | | Ship | | | | | | | Immunity, Shoot | 516 | | | | | | | | | Javelin, Vision | 517 | | | | | | | | | II, Fearless, | 518 | | | | | | | | | Cold Protection | 519 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 520 | | Galley | 1 | 3 | 3 | 1 | 25 | 36 | Sailing, Shoot | 521 | | | | | | | | | Javelin, Vision | 522 | | | | | | | | | II, Fearless, | 523 | | | | | | | | | Cold, Protection | 524 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 525 | | Galleon | 1 | 3 | 3 | 1 | 30 | 40 | Sailing, Poison | 526 | | | | | | | | | Immunity, | 527 | | | | | | | | | Marksmanship I, | 528 | | | | | | | | | Shoot Javelin, | 529 | | | | | | | | | Vision II, | 530 | | | | | | | | | Fearless, Cold | 531 | | | | | | | | | Protection | 532 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 533 | | Transport | 1 | 3 | 3 | 1 | 20 | 28 | Sailing, Poison | 534 | | Ship | | | | | | | Immunity, Vision | 535 | | | | | | | | | II, Fearless, | 536 | | | | | | | | | Cold Protection | 537 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 538 | 539 | Summoned Units 540 | ============== 541 | 542 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 543 | | Name | Attack | Defense | Resistance | Damage | Hits | Moves | Abilities | 544 | +===========+========+=========+============+========+======+=======+==================+ 545 | | Air | 5 | 2 | 3 | 3 | 12 | 32 | Flying, Fire | 546 | | Elemental | | | | | | | Immunity, Cold, | 547 | | | | | | | | | Immunity, | 548 | | | | | | | | | Lightning | 549 | | | | | | | | | Immunity, Poison | 550 | | | | | | | | | Immunity, | 551 | | | | | | | | | Physical | 552 | | | | | | | | | Immunity, | 553 | | | | | | | | | Strike, Vision | 554 | | | | | | | | | II | 555 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 556 | | Black | 6 | 5 | 8 | 6 | 20 | 32 | Flying, Death | 557 | | Dragon | | | | | | | Immunity, | 558 | | | | | | | | | Strike, Vision | 559 | | | | | | | | | II, Fearless, | 560 | | | | | | | | | Poison, | 561 | | | | | | | | | Protection, | 562 | | | | | | | | | Black Breath | 563 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 564 | | Black | 4 | 3 | 4 | 3 | 6 | 28 | Walking, Cave | 565 | | | | | | | | | Crawling, Poison | 566 | | | | | | | | | Immunity, Poison | 567 | | | | | | | | | Strike, Strike, | 568 | | | | | | | | | Web, Wall | 569 | | Spider | | | | | | | Climbing | 570 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 571 | | Earth | 6 | 4 | 4 | 8 | 20 | 20 | Walking, Cave | 572 | | Elemental | | | | | | | Crawling, | 573 | | | | | | | | | Mountaineering, | 574 | | | | | | | | | Poison Immunity, | 575 | | | | | | | | | Strike, | 576 | | | | | | | | | Tunneling, Fire | 577 | | | | | | | | | Protection, | 578 | | | | | | | | | Lightning | 579 | | | | | | | | | Protection, | 580 | | | | | | | | | Wall Crushing | 581 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 582 | | Fire | 6 | 4 | 8 | 5 | 17 | 26 | Walking, Fire | 583 | | Elemental | | | | | | | Immunity, | 584 | | | | | | | | | Lightning, Fire | 585 | | | | | | | | | Strike, Strike, | 586 | | | | | | | | | Call Flames, | 587 | | | | | | | | | Ignition, | 588 | | | | | | | | | Physical | 589 | | | | | | | | | Protection | 590 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 591 | | Fire | 5 | 2 | 4 | 3 | 7 | 24 | Walking, Fire, | 592 | | Sprite | | | | | | | Immunity, | 593 | | | | | | | | | Lightning | 594 | | | | | | | | | Immunity, Poison | 595 | | | | | | | | | Immunity, Fire | 596 | | | | | | | | | Strike, Strike, | 597 | | | | | | | | | Ignition | 598 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 599 | | Giant | 4 | 1 | 2 | 3 | 5 | 28 | Walking, | 600 | | Frog | | | | | | | Swimming, Strike | 601 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 602 | | Gold | 5 | 7 | 8 | 5 | 20 | 32 | Flying, Holy | 603 | | Dragon | | | | | | | Immunity, | 604 | | | | | | | | | Strike, Vision | 605 | | | | | | | | | II, Fearless, | 606 | | | | | | | | | Fire Protection, | 607 | | | | | | | | | Divine Breath | 608 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 609 | | Great | 4 | 2 | 3 | 3 | 7 | 40 | Flying, Strike, | 610 | | Eagle | | | | | | | Vision II | 611 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 612 | | Water | 6 | 2 | 3 | 4 | 14 | 24 | Walking, | 613 | | Elemenatl | | | | | | | Swimming, | 614 | | | | | | | | | Strike, | 615 | | | | | | | | | Physical | 616 | | | | | | | | | Protection, | 617 | | | | | | | | | Water | 618 | | | | | | | | | Concealment | 619 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 620 | | Wid Boar | 3 | 3 | 3 | 3 | 5 | 36 | Walking, Strike, | 621 | | | | | | | | | Charge | 622 | +-----------+--------+---------+------------+--------+------+-------+------------------+ 623 | 624 | Terrain and Movement Types 625 | ========================== 626 | 627 | ================================================ =================== 628 | Terrain and Mevement Types Movement Point Cost 629 | ================================================ =================== 630 | City 3 631 | Desert 4 632 | Dirt (with Cave Crawling ability) 4 (3) 633 | Flying and Floating (over Mountains) 4 (8) 634 | Forest (with Forestry ability) 6 (4) 635 | Grassland 4 636 | Hill (with Mountaineering skill) 6 (3) 637 | Ice 4 638 | Lava (with Fire Halo spell enchantment) Impassable (4) 639 | Mountain (with Mountaineering ability) Impassable (8) 640 | Road (with Enchant Roads spell in effect) 3 (2) 641 | Snow 4 642 | Steppe 4 643 | Tunneling (Actually digging the tunnel, per hex) 10 644 | Water (Swimming and Sailing movement types) 4 645 | ================================================ =================== 646 | 647 | Experience and Gaining Levels 648 | ============================= 649 | 650 | Units and Heroes alike each earn experience when they deliver the killing 651 | attack to a unit. Each unit is worth experience equal to its level when killed. 652 | 653 | *Examples:* 654 | A Dwarf Axeman, a level 1 unit, is worth 1 experience when killed. A Goblin 655 | Karagh, a level 4 unit, is worth 4 experience when killed. Units require 2 x 656 | their level to earn a silver medal and 6 x their level to earn a gold medal. 657 | 658 | *Example:* 659 | An Elf Archer, a level 1 unit, require 2 experience to earn its silver medal and 660 | 6 experience to earn its gold medal. 661 | 662 | ======================= ========================== ========================= 663 | Unit Experience Level Earned Experience Required Unit Stat Modifiers 664 | ======================= ========================== ========================= 665 | Silver Medal [Veteran] 2 x Level of Unit +1 Attack, +1 Defense, 666 | +1 Hit Point 667 | Gold Medal [Elite] 6 x Level of Unit +1 Damage, +1 Resistance, 668 | +1 Hit Point 669 | ======================= ========================== ========================= 670 | 671 | Additionally, some units gain abilities when they earn their medals, but this 672 | varies from unit to unit. Most archer / ranged units gain the Marksmanship 673 | ability or increase their current Marksmanship ability when they earn medals. 674 | 675 | Heroes and Leaders require more experience to level up. Heroes and Leaders 676 | receive 1 experience at the start of each new turn. When a Hero or Leader levels 677 | up, they earn 10 skill points to spend. These points are stored up over multiple 678 | levels if not spent. 679 | 680 | ========== ============================ 681 | Hero Level Experience Required to Level 682 | ========== ============================ 683 | 1 - 10 15 per level 684 | 11 - 20 20 per level 685 | 21 - 30 25 per level 686 | ========== ============================ 687 | 688 | ========== ======================= 689 | Stat Name Skill Point Cost Per +1 690 | ========== ======================= 691 | Attack 5 692 | Defense 5 693 | Damage 10 694 | Resistance 5 695 | Movement 2 696 | Hit Point 5 697 | ========== ======================= 698 | 699 | Spell Spheres and Mana Node Generation 700 | ====================================== 701 | 702 | ====================== ======================================== 703 | Number of Sphere Picks Mana Generation per Matching Sphere Node 704 | ====================== ======================================== 705 | 0 0 706 | 1 15 707 | 2 20 708 | 3 25 709 | 4 30 710 | **Power Node** **10 [Regardless of Sphere Picks]** 711 | ====================== ======================================== 712 | 713 | Spell Reference Lists 714 | ===================== 715 | Currently, only the Ranges, Attack, and Damage values of combat spells are 716 | listed. Radius stands for the number of hexes outward from the center hex the 717 | spell covers. Radius 0 spells affect only 1 hex, radius 1 is 7 hexes, radius 2 718 | is 19 hexes, radius 3 is 37 hexes, and radius 4 is 61 hexes. Cone spells affect 719 | 12 hexes in a triangle shaped pattern. 720 | 721 | Life Spells 722 | ----------- 723 | 724 | ============== ===== ====== ====== ========== ====== ==== 725 | Name Range Attack Damage Repetition Radius Type 726 | ============== ===== ====== ====== ========== ====== ==== 727 | Rejuvenate \-\ \-\ \-\ \-\ 2 \-\ 728 | Solar Flare Long 8 4 1 0 Holy 729 | Holy Woods \-\ \-\ \-\ \-\ 1 Holy 730 | Turn Undead Long 6 5 1 0 \-\ 731 | Recall Spirits \-\ \-\ \-\ \-\ 1 \-\ 732 | Sacred Wrath \-\ 5 5 1 \-\ Holy 733 | Divine Storm \-\ \-\ \-\ \-\ 4 Holy 734 | ============== ===== ====== ====== ========== ====== ==== 735 | 736 | Death Spells 737 | ------------ 738 | 739 | ================ ===== ====== ====== ========== ====== ======= 740 | Name Range Attack Damage Repetition Radius Type 741 | ================ ===== ====== ====== ========== ====== ======= 742 | Death Ray Long 8 4 1 0 Death 743 | Disease Cloud Long 8 3 1 1 Death 744 | Evil Woods \-\ \-\ \-\ \-\ 1 Death 745 | Animate Dead \-\ \-\ \-\ \-\ 1 \-\ 746 | Terror \-\ 5 \-\ 1 \-\ Special 747 | Pestilence Cloud \-\ \-\ \-\ \-\ 2 Poison 748 | Mind Decay Long 5 \-\ 1 1 Special 749 | Death Storm \-\ \-\ \-\ \-\ 4 Death 750 | ================ ===== ====== ====== ========== ====== ======= 751 | 752 | Air Spells 753 | ---------- 754 | 755 | =============== ===== ====== ====== ========== ====== ========= 756 | Name Range Attack Damage Repetition Radius Type 757 | =============== ===== ====== ====== ========== ====== ========= 758 | Vaporize Long 7 5 1 0 Physical 759 | Chain Lightning Long 6 5 Special 0 Lightning 760 | Winds of Fury Long 8(10) 5 1 0 Physical 761 | Freeze Water \-\ \-\ \-\ \-\ 1 \-\ 762 | Cold Breath Short 6 5 1 Cone Cold 763 | Shockwave 0 8 5 1 3 Physical, 764 | Wall 765 | Lightning Storm \-\ \-\ \-\ \-\ 1 Lightning 766 | =============== ===== ====== ====== ========== ====== ========= 767 | 768 | Earth Spells 769 | ------------ 770 | 771 | ============= ====== ====== ====== ========== ======= ========= 772 | Name Range Attack Damage Repetition Radius Type 773 | ============= ====== ====== ====== ========== ======= ========= 774 | Entangle Long 7 \-\ 1 \-\ Entagle 775 | Slow \-\ 9 \-\ 1 \-\ Special 776 | Poison Woods \-\ \-\ \-\ \-\ 1 Poison 777 | Stoning Long 5 2 6 0 Physical 778 | Level Terrain \-\ \-\ \-\ \-\ 1 \-\ 779 | Tremors \-\ 5 5 1 \-\ Physical, 780 | Wall 781 | Raise Terrain \-\ \-\ \-\ \-\ 1 \-\ 782 | ============= ====== ====== ====== ========== ======= ========= 783 | 784 | Fire Spells 785 | ----------- 786 | 787 | ================= ====== ====== ====== ========== ======= ============== 788 | Name Range Attack Damage Repetition Radius Type 789 | ================= ====== ====== ====== ========== ======= ============== 790 | Flame Arrow Long 8 4 1 0 Fire, Physical 791 | Call Flames Medium 9 3 1 0 Fire 792 | Cloud of Ashes \-\ \-\ \-\ \-\ 3 \-\ 793 | Fire Breath Short 6 5 1 Cone Fire 794 | Swarm Long 6 1 Special Special Fire 795 | Fire Barrier \-\ \-\ \-\ \-\ 1 Fire 796 | Fireball Long 8 6 1 1 Fire, Wall 797 | Sacrificial Flame Long 8 5 1 2 Fire 798 | Fire Storm \-\ \-\ \-\ \-\ 1 Fire 799 | ================= ====== ====== ====== ========== ======= ============== 800 | 801 | Water Spells 802 | ------------ 803 | 804 | =============== ====== ====== ====== ========== ====== ============== 805 | Name Range Attack Damage Repetition Radius Type 806 | =============== ====== ====== ====== ========== ====== ============== 807 | Ice Shards Long 6 5 3 0 Physical 808 | Ooze Medium \-\ \-\ \-\ 2 \-\ 809 | Vortex \-\ \-\ \-\ 1 0 Physical 810 | Geyser Long 9 5 1 0 Physical 811 | Frost Beam Long 9 3 1 1 Cold 812 | Great Hail Long 5 5 3 1 Physical, Wall 813 | Healing Showers \-\ \-\ \-\ \-\ 1 \-\ 814 | Ice Showers \-\ \-\ \-\ \-\ 4 Cold 815 | =============== ====== ====== ====== ========== ====== ============== 816 | 817 | All global, terrain altering spells without an upkeep cost last for three turns. 818 | Level Terrain, Animate Ruins, and Rejuvenate are exceptions to this rule. This 819 | includes all cloud spells (except Cloud of Ashes which has an upkeep cost) and 820 | all Holy Woods type spells. 821 | 822 | Manual Corrections and Updates 823 | ============================== 824 | (If you mark any corrections in the Manual, USE PENCIL, these changes are not 825 | necessarily final!) 826 | 827 | Spells 828 | ------ 829 | 830 | Hold Champion, Life, 2nd Level 831 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 832 | *Corrected Description:* Gives a +2 bonus to Attack and Damage against units of 833 | Evil alignment. 834 | 835 | High Prayer, Life, 3rd Level 836 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 837 | *Corrected Description:* Blesses all friendly units during combat, increasing 838 | Defense (+1), Resistance (+1), and restores up to 5 lost Hit Points. 839 | 840 | Evil Champion, Death, 2nd Level 841 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 842 | *Corrected Name:* Unholy Champion* 843 | 844 | *Corrected Description:* 845 | Gives a +2 bonus to Attack and Damage against units of Good alignment. 846 | 847 | Terror, Death, 2nd Level 848 | ~~~~~~~~~~~~~~~~~~~~~~~~ 849 | *Corrected Description:* 850 | All enemy units that fail a resist roll are panicked, severely hurting their 851 | morale (- 40 to morale) for the duration of combat. 852 | 853 | Mind Decay, Death, 3rd Level 854 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 855 | *Corrected Description:* 856 | Evil spirits attempt to Dominate non-Undead units. If successful, the victims 857 | fall under your control and loose 1 hit point per turn. At the end of combat, 858 | all units controlled by Mind Decay die. 859 | 860 | Haste, Air, 1st Level 861 | ~~~~~~~~~~~~~~~~~~~~~ 862 | *Corrected Description:* 863 | All terrain types require 2 less movement points to move over, down to a minimum 864 | of 2. 865 | 866 | Winds of Fury, Air, 2nd Level 867 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 868 | *Added effect with versions 1.1+:* 869 | Receives a +2 Attack bonus when targeting flying units. 870 | 871 | Wind Walking, Air, 3rd Level 872 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 873 | *Corrected Description:* 874 | Gives enchanted unit the ability to Float over terrain. 875 | 876 | Entangle, Earth, 2nd Level 877 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 878 | *Updated Description:* 879 | Attempts to entangle the target in vines, paralyzing them for 3 combat turns and 880 | lowering their defense by 2. 881 | 882 | Stoning, Earth, 2nd Level 883 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 884 | *Corrected Description:* 885 | Sends 6 small stones towards an enemy during combat, each with a separate chance 886 | to hit and do damage. 887 | 888 | Concealment, Earth, 3rd Level 889 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 890 | *Updated Description:* 891 | Allows the enchanted unit to hide in forests and thick underbrush. While hidden, 892 | the enchanted unit may only be seen on the global map by enemies directly 893 | adjacent to the unit or by units with True Seeing. 894 | 895 | Level Terrain, Earth, 3rd Level 896 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 897 | *Updated Description:* 898 | Permanently lowers mountains, hills, forests, and underbrush to flatter, more 899 | easily passable terrain. 900 | 901 | Fire Mastery, Fire, 4th Level 902 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 903 | *Added Bonus:* 904 | Also bestows Fire Protection upon all of the caster’s units. 905 | 906 | Warmonger, Fire, 4th Level 907 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 908 | *Clarification:* 909 | Veteran experience level is the same as if the unit earned the experience for a 910 | Silver Medal. (+1 to Attack, Defense, and Hit Points) 911 | 912 | Dispel Magic, Cosmos, 1st Level 913 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 914 | *Clarification:* 915 | Can also be used to randomly remove an enchantment on an enemy unit. 916 | 917 | Units 918 | ----- 919 | 920 | Elves 921 | ~~~~~ 922 | 923 | Nymph 924 | """"" 925 | :Correction: Damage = 2 926 | 927 | Ranger 928 | """""" 929 | :Correction: Movement = 32 930 | 931 | Nature Elemental 932 | """""""""""""""" 933 | :Updated, Version 1.2+: Entagle ability removed, Entagle Strike added, Healing 934 | ability added 935 | 936 | Halflings 937 | ~~~~~~~~~ 938 | 939 | Rogue 940 | """"" 941 | :Correction: Parry ability added 942 | 943 | Centaur 944 | """"""" 945 | :Correction: Defense = 4 946 | 947 | Dwarves 948 | ~~~~~~~~ 949 | 950 | Berserker 951 | """"""""" 952 | :Update, Version 1.1+: Cave Crawling ability added 953 | 954 | Boar Rider 955 | """""""""" 956 | :Correction: Defense = 3 957 | 958 | Balloon 959 | """"""" 960 | :Clarification: Transports 5 units 961 | 962 | Mole 963 | """" 964 | :Error: Unit picture is that of the Drill unit 965 | :Correction: Unit picture is that of a giant Mole (No weasels or badgers, just a 966 | mole) 967 | 968 | Highmen 969 | ~~~~~~~ 970 | 971 | Avenger 972 | """"""" 973 | :Correction: Damage = 4 974 | 975 | Human 976 | ~~~~~ 977 | 978 | Air Galley 979 | """""""""" 980 | :Clarification: Transports 7 units 981 | 982 | Azracs 983 | ~~~~~~ 984 | 985 | Swordsman 986 | """"""""" 987 | :Correction: Damage = 3 988 | 989 | Elephant 990 | """""""" 991 | :Update, Version 1.2+: Attack = 3, Damage = 3 992 | 993 | Lizardmen 994 | ~~~~~~~~~ 995 | 996 | Green Wyvern 997 | """""""""""" 998 | :Update, Version 1.2+: Cost = 98 999 | 1000 | Basilisk 1001 | """""""" 1002 | :Update, Version 1.2+: Cost = 202 1003 | 1004 | Dark Elves 1005 | ~~~~~~~~~~ 1006 | 1007 | Executioner 1008 | """"""""""" 1009 | :Correction: Defense = 5 1010 | 1011 | Goblins 1012 | ~~~~~~~ 1013 | 1014 | Big Beetle 1015 | """""""""" 1016 | :Update, Version 1.2+: Night Vision ability added 1017 | 1018 | Undead 1019 | ~~~~~~ 1020 | 1021 | Swordsman 1022 | """"""""" 1023 | :Correction: Death Immunity ability added 1024 | 1025 | Skull Thrower 1026 | """"""""""""" 1027 | :Correction: Movement = 20, Death Immunity ability added 1028 | 1029 | Demon 1030 | """"" 1031 | :Correction: Attack = 6, Poison Strike ability removed, Fire Strike ability 1032 | added Reaper 1033 | :Update, Version 1.2+: Defense = 5, Damage = 6 1034 | 1035 | -------------------------------------------------------------------------------- /Wolfenstein 3D/file-formats.rst: -------------------------------------------------------------------------------- 1 | .. default-role:: code 2 | 3 | ################################### 4 | Wolfenstein 3D code design document 5 | ################################### 6 | 7 | Format documentation of asset files in Wolenstein 3D. 8 | 9 | .. contents:: Table of Contents 10 | :depth: 3 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | Files overview 15 | ############## 16 | 17 | The assets of Wolfensein 3D are stored in multiple files, unlike more modern 18 | games such as Doom. These files are containers that contain different assets 19 | glued together, and every file usually contains a "header" of sorts that helps 20 | in locating the actual asset we seek. 21 | 22 | The files are named the same in all distributions of the game, but their file 23 | extension varies. For simplicity the file extensions will be omitted in this 24 | document when not relevant The following table offers an overview: 25 | 26 | ========= ================================ 27 | Extension Version 28 | ========= ================================ 29 | ``WL1`` Shareware 30 | ``WL3`` Early three-episode full version 31 | ``WL6`` Six-episode full version 32 | ``WJ1`` Japanese shareware? 33 | ``WJ6`` Japanese full version? 34 | ``SOD`` Spear of Destiny? 35 | ``SDM`` ??? 36 | ``SD1`` SoD M2: Return to Danger? 37 | ``SD2`` SoD M3: Ultimate challenge 38 | ``SD3`` ??? 39 | ========= ================================ 40 | 41 | The files can be grouped roughly in three categories: *graphics*, *audio* and 42 | *maps*. The game assets for WS3D are stored in various files with the same 43 | extension, which is depending on the version of the game. The assets are 44 | distributed as follows: 45 | 46 | Graphics 47 | VGADICT, VGAHEAD, VGAGRAPH 48 | Audio 49 | AUDIOHED, AUDIOT 50 | Maps 51 | MAPHEAD, GAMEMAPS 52 | 53 | The header files contain information about the structure of the actual asset 54 | files 55 | 56 | 57 | 58 | Conventions and nomenclature 59 | ############################ 60 | 61 | Decimal integer numbers are given as regular numbers, binary numbers are 62 | prefixed with `0b`, octal numbers with `0o` *o* and hexadecimal numbers are 63 | prefixed with `0x`. Example: 64 | 65 | .. math:: 66 | 13 = 0b1011 = 0o15 = 0xD 67 | 68 | All continuous numbers are written in the standard big-endian notation used in 69 | the English language. This means the left-most digit is the most significant 70 | one and a number like `0b1011` is computed as 71 | 72 | .. math:: 73 | (1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^0). 74 | 75 | Multibyte numbers are given in little-endian notation and the bytes are 76 | seperated by whitespace charakters, thus the multibyte number `0x1A 0x3C` 77 | corresponds to the hexadecimal number `0x3C1A` or decimal `15386`. If the 78 | endianness needs to be explicitly stated it will be noted as `(BE)` for 79 | big-endian and as `(LE)` for little-endian. 80 | 81 | Notes are written as ``:NOTE:``, tasks are written as ``:TODO:`` and bugs in the 82 | original implementation are written as ``:BUG:``. This allows using the editor's 83 | search function to quickly jump to these points. 84 | 85 | 86 | Pseudocode 87 | ========== 88 | 89 | Pseudocode is based on how C works, so if an integer is added to or subtracted 90 | from a pointer it means the pointer is advanced by the amount of bytes its 91 | value takes up. For instance, if `p` is a pointer to a word and a word is two 92 | bytes in size, then `p + 2` is a pointer that points four bytes (two words) 93 | further away from `p`. Variables in pseudocode are considered immutable, every 94 | arithmetic operation returns a copy. In the above example the pointer `p` would 95 | not advance, instead `p + 2` would be a new pointer. To mutate a variable use a 96 | verb such as *increment* or *advance*. 97 | 98 | Pointers and arrays are used more or less interchangably in the pseudocode as 99 | well. Usually when a pointer is described as a "sequence" of something it can 100 | be an array as well. Similarly, the square bracked notation `pointer[i]` means 101 | "the value of `pointer + i`". Whether the actual implementation uses pointers, 102 | arrays, vectors, linked lists of whatever is irrelevant. 103 | 104 | 105 | Data types 106 | ========== 107 | 108 | The data types in this document are similar to the types used in the original 109 | source. A *byte* is eight bits in size, a *word* is a sequence of two bytes. All 110 | multibyte-numbers are stored in little-endian format in the asset files. A 111 | *character* or *char* is synonymous to a byte and encodes an ASCII character. 112 | 113 | Sometimes data types will be used interchangably, like *byte*, *unint8* of 114 | *char*, depending on what fits the context better. When reading or writing data 115 | it makes more sense to talk about bytes and words, whereas *uint8* or *uint16* 116 | are more suited when the numerical value is relevant. 117 | 118 | 119 | 2D or 3D 120 | ======== 121 | Despite its name Wolfenstein 3D is not a true 3D game; the game's data and 122 | simulation all happen in a flat 2D space on a strict grid, while the rendering 123 | appears to take place in a 3D world to the player. In this document the game 124 | world (called "world space") will be treated as if it was actually a three- 125 | dimensional space, since that is what the player is experiencing. On the other 126 | hand, simulation space, where all the game's actual mechanics are implemented, 127 | will be treated like a two-dimensional plane, since that is the way the game 128 | works. 129 | 130 | 131 | 132 | Compression Algorithms 133 | ###################### 134 | 135 | The following desctiptions describe the algorithms in general, regardless of how 136 | the game uses them. 137 | 138 | 139 | RLEW compression 140 | ================ 141 | 142 | A variant of RLE (Run Length Encoding) that uses words instead of bytes as the 143 | underlying unit. Repeating words are stored as a word triplet `(tag, count, 144 | word)` where `tag` is a constant word used to identify the triplet, `count` is 145 | how many times to copy the word and `word` is the word to copy. Aside from 146 | these triplets there are also uncompressed words that are copied verbatim. Here 147 | is the pseudocode: 148 | 149 | -------------------------------------------------------------------------------- 150 | 151 | :Prerequisites: 152 | - `source` : pointer to the start of the compressed input stream 153 | - `destination` : pointer to the start of the decompressed output stream 154 | - `tag` : a word used to identify a triplet 155 | - `length` : integer length of the decompressed data 156 | - Must allocate enough memory to hold the decompressed sequence 157 | 158 | :Side effects: 159 | The pre-allocated memory will be filled with decompressed data 160 | 161 | :Code: 162 | 1) Make new pointers: `read` = `start`, `write` = `desination`. These 163 | Pointers will be moved forward while the original pointers remain fixed 164 | 2) While `length` > :math:`0` 165 | 166 | 1) Read `word` pointed at by `read` 167 | 2) If `word` is `tag` 168 | 169 | 1) Advance `read` by one word 170 | 2) Make new integer `count` from word pointed at by `read` 171 | 3) Advance `read` by one word 172 | 4) while `count` > :math:`0` 173 | 174 | 1) Copy word under `read` to `write` 175 | 2) Advance `write` by one word 176 | 3) Decrement `count` and `length` by one 177 | 5) Advance `read` by one word 178 | 3) Else 179 | 180 | 1) Copy word under `read` to `write` 181 | 2) Advance `read` and `write` by one word 182 | 3) Decrement `length` by one 183 | 184 | -------------------------------------------------------------------------------- 185 | 186 | What about the word that's identical to `tag`? It will be compressed as `(tag, 187 | 0x01 0x00, tag)`, i.e. copy the word `tag` one time. This is actually a 188 | threefold increase in data compared to the uncompressed version, but in 189 | practice this is a better solution than having special cases. 190 | 191 | 192 | 193 | Carmack compression 194 | =================== 195 | 196 | The underlying idea of this compression method is that certain patterns of 197 | information are going to be repeated several times. Instead of repeating the 198 | pattern each time a reference to previous instances of the pattern is stored; 199 | the already uncompressed data is referenced by the still compressed data. 200 | 201 | The compressed data consists of uncompressed words, one of two types of 202 | pointers (near pointers and far pointers), and exceptions where all four can 203 | appear in the same file depending on which is necessary. Near pointers are byte 204 | triplets and far pointers are byte quadruples. On top of this there are special 205 | exceptions for words that might be confused for pointers. All offsets are given 206 | in *words*, so to get the *byte* offset multiply the word offset by two. 207 | 208 | Before we look at the pseudocode we need to understand the priciples first. 209 | 210 | 211 | Near pointers 212 | ------------- 213 | 214 | Near pointers are a sequence of three bytes `(count, 0xA7, offset)`. The first 215 | byte tells us how many words to copy, it is an usingned 8-bit integer. The 216 | second byte is the tag and always `0xA7`, it is used to identify a near 217 | pointer. The third byte is the unsigned 8-bit integer offset relative from the 218 | last written word to the word to copy. Take the following example 219 | 220 | ========================= ======================================== 221 | decompresssed data before `0C 00 0A 00 CD AB 05 00 ??` 222 | near pointer `02 A7 03` 223 | decompresssed data after `0C 00 0A 00 CD AB 05 00 0A 00 CD AB ??` 224 | ========================= ======================================== 225 | 226 | The `??` is the current position of the destination pointer; it points at 227 | memory that has been allocated but not yet been written to, its content is at 228 | this point undefined. The near pointer tells us to copy two words (four bytes) 229 | from three words ago. The resulting output would then be 230 | 231 | First a copy of the destination pointer (called *copy pointer*) is moved four 232 | words back, pointing at the byte `0A`. The byte pointed at by the copy pointer 233 | is copied to the value pointed at by the destination pointer and both pointers 234 | are incremented. This is repeated four times, at which point the copy pointer 235 | has reached the original position of the destination pointer. 236 | 237 | 238 | Far pointers 239 | ------------ 240 | 241 | The disadvantage of near pointers is that the offset is an 8-bit integer, so it 242 | can only reach :math:`255` words back. Far pointers `(count 0xA8 low_offset 243 | high_offset)` use a 16-bit offset, so they take up one more bytes in memory. 244 | The offset is given relative to the start of the decompressed sequence, i.e. 245 | the first destination pointer. Aside from the offset they work the same as near 246 | pointers, their tag is `0xA8`. 247 | 248 | 249 | Exception 250 | --------- 251 | 252 | Words with a high byte (second byte) of `0xA7` or `0xA8` can be confused for 253 | pointers. In compressed form the low byte is replaced by the byte `0x00` and 254 | the low bytes value is appened after the high byte. A count of :math:`0` would 255 | make no sense for a pointer, so the algorithm can tell when an exception has 256 | occured. Since the low byte comes after the high byte the word is actually 257 | stored in big-endian notation and needs to be swapped around when written to 258 | the destination. 259 | 260 | 261 | Extraction 262 | ---------- 263 | 264 | To decompress the data we need to know the length of the decompressed data 265 | because there is no indication when the end of the compressed sequence is 266 | reached; the compressed data is often stored adjacent to other compressed data 267 | in the same file. On top of that there is also uncompressed data between near- 268 | and far pointers which must be copied verbatim. 269 | 270 | Keep count of the bytes or words already written. When using words instead of 271 | bytes to keep track make sure you divide the byte count by two. At first the 272 | count is :math:`0` and it is incremented every time we write a word or byte. 273 | Once the count reaches the size of the decompressed data the extraction is 274 | done. After each write increment the count and advance the pointers 275 | appropriately. This means the destination pointer is advanced by one byte for 276 | every byte written and the source pointer is advanced by three bytes for near 277 | pointers and exceptions, four for far pointers, and two for regular words. 278 | 279 | During each iteration step read a word. If the word's high byte (second byte) 280 | is neither the near- nor the far flag copy the word to the destination. If it's 281 | the near flag and the count is not `0x00` step `offset` words back through the 282 | decompressed data and copy `count` words from there to the decompressed data. 283 | If it's a far pointer and the count is not `0x00` copy `count` words `offset` 284 | words from the start of the decompressed data. If the count is zero advance the 285 | pointer by one byte and copy the reversed word. 286 | 287 | 288 | Pseudocode 289 | ---------- 290 | 291 | This pseudocode operates on words. 292 | 293 | -------------------------------------------------------------------------------- 294 | 295 | :Constants: 296 | - `zero = 0x00` 297 | - `near = 0xA7` 298 | - `far = 0xA8` 299 | 300 | :Prerequisites: 301 | - `source` : pointer to the start of the compressed input stream 302 | - `destination` : pointer to the start of the decompressed output stream 303 | - `length` : length of the decompressed data sequence in words 304 | - Must allocate enough memory to hold the decompressed sequence 305 | 306 | :Side effects: 307 | The pre-allocated memory will be filled with decompressed data 308 | 309 | :Code: 310 | 1) Make new pointers: `read = start`, `write = desination`. These pointers 311 | will be moved forward while the original pointers remain fixed 312 | 2) While `length > 0` 313 | 314 | 1) Read the word pointed at by `read` 315 | 2) Make new integer `count` the numeric value of its low byte 316 | 3) Make new integer `flag` the numeric value of its high byte 317 | 4) If `flag` is `near` and `count` is not `zero` 318 | 319 | 1) Advance `read` by one byte 320 | 2) Read the word under `read` 321 | 3) Make the new integer `offset` the numeric value of the word's high 322 | byte 323 | 4) Make the new pointer `copy = write - offset` 324 | 5) While `count > 0` 325 | 326 | 1) Copy word under `copy` to `write` 327 | 2) Advance `copy` and `write` by one word each 328 | 3) Decrement `count` and `length` by one each 329 | 5) Else if `flag` is `far` and `count` is not `zero` 330 | 331 | 1) Advance read by one word 332 | 2) Read the word under `read` 333 | 3) Make the new integer `offset` the numeric value of the word 334 | 4) Make the new pointer `copy = destination + offset` 335 | 5) While `count > 0` 336 | 337 | 1) Copy word under `copy` to `write` 338 | 2) Advance `copy` and `write` by one word each 339 | 3) Decrement `count` and `length` by one each 340 | 6) Else if `flag` is `near` or `far` and `count` is `zero` 341 | 342 | 1) Advance `read` by one byte 343 | 2) Copy word under `read` to `write` 344 | 3) Swap bytes of word under `write` 345 | 4) Advance `read` and `write` by one word each 346 | 5) Decrement `length` by one 347 | 7) Else 348 | 349 | 1) Copy word under `read` to `write` 350 | 2) Advance `read` and `write` by one word each 351 | 3) Decrement `length` by one 352 | 353 | -------------------------------------------------------------------------------- 354 | 355 | Near- and far pointers are very similar, the only difference is in how the 356 | offset is computed and that near pointer have to advance by one byte while far 357 | pointers advance by one word. 358 | 359 | 360 | 361 | Huffman compression 362 | =================== 363 | 364 | Id's implementation of the Huffman compression algorithm uses a :math:`255` 365 | node large Huffman tree stored as a flat array where each node consist of two 366 | words, and node number :math:`255` (index :math:`254`) is always the root node. 367 | Here is how the nodes work: a byte called the *node value* is being kept track 368 | of, it is initially :math:`254`, the array position of the root node of the 369 | tree. From there the input of the compressed stream is being read bit-wise, if 370 | the bit is `0` the node value is set to the node's first word, otherwise to the 371 | node's second word. If the node value is less than :math:`256` (i.e. within the 372 | value range of a byte) the node value is written as a byte and the node pointer 373 | is reset back to the root node. Otherwise, if the node value is eaqual to or 374 | greater than :math:`256` the node pointer is set to the node at array index 375 | (node value - :math:`256`). 376 | 377 | 378 | Pseudocode 379 | ---------- 380 | 381 | Since the input cannot be read bit-wise it has to be read one byte at a time 382 | and then the input byte is being examined using a masking byte. This byte 383 | starts out as `0x01` and is bitewise `AND`-ed with the input byte to decide 384 | which path down the tree to take. Afterwards the 1-bit of the masking byte is 385 | left-shifted by one to be able to examine the next input-bit. Once the mask 386 | byte reached `0x80` the masking bit is all the way to the left, so we need to 387 | reset it back to `0x01` and read the next input byte. 388 | 389 | -------------------------------------------------------------------------------- 390 | 391 | :Constants: `root = 254` 392 | 393 | :Prerequisites: 394 | - `source`: pointer to the start of the compressed input stream as bytes 395 | - `destination`: pointer to the start of the decompressed output stream as 396 | bytes 397 | - `length`: length of the decompressed data sequence in words 398 | - `huffman_tree`: array of Huffman-tree nodes for decompression 399 | - Must allocete enough memory to hold the decompressed sequence 400 | 401 | :Data structures: 402 | `struct huffman_node {word word_0, word_1}` : a structure holding two words 403 | 404 | :Side effects: The pre-allocated memory will be filled with decompressed data 405 | 406 | :Code: 407 | 1) Make new pointer `node` of type `huffman_node` and set it to 408 | `huffman_tree[root]` 409 | 2) Make new pointers `read` and `write` and set them to `source` and 410 | `destination` respectively 411 | 3) Make new byte `mask = 0x01` and `input`, set input to value of `read`, 412 | advance `read` 413 | 4) Make new word `node_value` 414 | 5) Repeat indefinitely 415 | 416 | 1) If `(input & mask) == 0x00` 417 | 418 | 1) `node_value = node->word_0` 419 | 2) Else 420 | 421 | 1) `node_value = node->word_1` 422 | 3) If `mask == 0x80`, i.e. the masking bit is all the way to the right 423 | 424 | 1) Set `input` to value pointed at by read, advance read 425 | 2) Set `mask` back to `0x01` 426 | 4) Else 427 | 428 | 1) Bit-shift `mask` by one bit to the left 429 | 5) If `node_value < 256` (hex `0xFF`) 430 | 431 | 1) Write the value of `node_vale` as a byte to `write`, advance 432 | `write` 433 | 2) Reset `node_pointer` back to `huffman_tree[root]` 434 | 3) If the end of the output stream has been reached break out of the loop 435 | 6) Else 436 | 437 | 1) `node_pointer = huffman_tree[node_value - 256]` 438 | 439 | -------------------------------------------------------------------------------- 440 | 441 | 442 | 443 | 444 | Graphics 445 | ######## 446 | 447 | There are two types of graphics in the game: *pics* and *sprites*. Pics are 448 | rectangular pictures of any size without any transparent holes and used outside 449 | the 3D portions of the game. An alternative name is *bitmaps*. Sprites are in- 450 | game object graphics using the colur `0x980088` for transparency and are always 451 | :math:`64 \times 64` pixels large. 452 | 453 | 454 | 455 | Pics 456 | ==== 457 | 458 | To extract pics three files are needed: 459 | 460 | ========== ========================================= 461 | File name Purpose 462 | ========== ========================================= 463 | `VGADICT` Huffman-tree for decopressing the pics 464 | `VGAHEAD` Headers describing where to find the pics 465 | `VGAGRAPH` Compressed pics lumped together 466 | ========== ========================================= 467 | 468 | The pics are all Huffman-compressed, so first the Huffman tree has to be loaded. 469 | 470 | VGADICT 471 | This file is :math:`1024` bytes large, but the last four bytes are just 472 | `0x00` byte padding. Four consequtive bytes each form a Huffman tree node 473 | and the node type itself is made of two words, so the file describes 474 | :math:`255` individual Huffman nodes (:math:`255 /times 4 = 1020`). Only 475 | those :math:`1020` bytes are read and stored verbatim in an array of 476 | Huffman-node type of length :math:`255` (size hard coded). As explained 477 | above a Huffman-node is a struct holding two words. 478 | 479 | VGAHEAD 480 | This file holds the offsets of the pics and is uncompressed. Each offset is 481 | a 32-bit signed number, but it is stored using only three bytes instead of 482 | four. The number of offsets is one more than the number of actual chunks; 483 | this last offset points to the end of the file. It is necessary because the 484 | length of a compressed chunk is not encoded anywhere, it needs to be 485 | computed using the starting offset of the next chunk. 486 | 487 | VGAGRAPH 488 | This is the file containing the Huffman-compressed chunks. The number of 489 | pics is hard-coded into the executable and cannot be learned from this file 490 | as not all chunks are actually pics, some are text or palettes. The first 491 | chunk is the *picture table*, an array of widths and heights for each pic. 492 | Each array element is a pair of two words, the first being the width and the 493 | second being the height. 494 | 495 | 496 | Extracting the pics 497 | ------------------- 498 | 499 | Pics are stored Huffman-compressed, so first we need to read the Huffman-table. 500 | This is straight forward, simply dump the contents of VGADICT into a pre- 501 | allocated array. All sizes are hard coded. Next we need to read the pic headers 502 | from VGAHEAD. 503 | 504 | First we need to know that number of pics used by the game. This can vary 505 | depending on which version of the game is played and the number is hard coded 506 | into the executable. It can also be computed by getting the size of the VGAHEAD 507 | file in bytes and dividing by three since each head is stored as three bytes. 508 | Both approaches are valid and there is a proposal below under "Distributions of 509 | the game and magic numbers" for using hard-coded numbers in a way that's 510 | compatible with multiple versions of the game at runtime. 511 | 512 | Using that number allocate space for an array of that many 32-bit integers and 513 | fill each one with the corresponding offset value. Beware that the offsets are 514 | stored in the file using only three bytes, not four. One exception is the 515 | number `0x00FFFFFF` or its corressponding byte sequence `FF FF FF` which gets 516 | mapped to the offset :math:`-1`. It does not appear in neither the registered 517 | six-episode release nor in the shareware release. I am not sure what the reason 518 | is here, but the original release has the following line in the `CA_FarRead` 519 | function 520 | 521 | .. code:: 522 | 523 | if (length>0xffffl) 524 | Quit ("CA_FarRead doesn't support 64K reads yet!"); 525 | 526 | This seems to be a safety check for technical reasons and since that value does 527 | not appear among the offsets anyway I am not certain if it is worth replicating. 528 | 529 | Now we need to read the picture table, an array of widths and heights for the 530 | individual pics. Open the VGAGRAPH file and jump to the first offset. We can 531 | read the expanded length of the chunk in bytes as a signed 32-bit integer from 532 | the first four bytes. Now compute the compressed length of this first chunk in 533 | bytes by taking the offset to the next chunk, substracting the offset of the 534 | current chunk and subtracting four (the extpanded length). Now allocate enough 535 | bytes to hold that sequence and fill it with the first chunk minus the first 536 | four bytes. Allocate enough memory to hold the decompressed picture table and 537 | Huffman-expand the first chunk into it. 538 | 539 | Now that the preperation work is done we can start extracting the individual 540 | pics. So far we have the Huffman tree, an array of offsets, a pic table 541 | describing the size of each pic and an open VGAGRAPH file. A chunk is 542 | identified using its magic number. Get the offset of the chunk and that of the 543 | next chunk using their magic numbers. If the offset of the chunk is :math:`-1` 544 | abort. We can get the magic number of the next chunk by adding :math:`+1` to 545 | the magic number of the current chunk. If the offset of the next chunk is 546 | :math:`-1` keep adding :math:`+1` to the magic number until the offset is a 547 | proper value. Compute the length of the compressed chunk as the difference in 548 | chunk offsets and fill a buffer of that size and type 32-bit signed integer 549 | with the data of the chunk. 550 | 551 | Now we can expand the data. We need to know the expanded size of the chunk, 552 | which can be read from the compressed chunk: the first four bytes are a signed 553 | 32-bit integer that tells us the size, so read it and advance the pointer by 554 | four bytes. There is an exception if the chumk number is greater or equal to 555 | `STARTTILE8` and less than `STARTEXTERNS`; I don't really understand what 556 | that is supposed to represent, but the size is hard coded in that case and the 557 | pointer is not advanced. Here it the code in question 558 | 559 | .. code:: 560 | 561 | if (chunk >= STARTTILE8 && chunk < STARTEXTERNS) { 562 | // expanded sizes of tile8/16/32 are implicit 563 | #define BLOCK 64 564 | #define MASKBLOCK 128 565 | 566 | if (chunk>2)+(i>>2))+(i&3)*(width>>2)*height]] 605 | 606 | Here `rgb_pixel` is a linear array of output pixels starting in the top-left 607 | corner and growing width-first, height-second. `palette` is an array that maps 608 | a colpur index to an RGB colour value. `vga_pixel` is the array of picture 609 | pixels. The variables `i` and `j` stand for the current width and height 610 | while building the output image. The operators `>>` and `&` are bitwise 611 | right-shift and bitwise `AND` respectively. 612 | 613 | I don't understand how or why pictures need to be "woven" in such a way, I 614 | assume it has to do with the way that the VGA standard works. Trying to order 615 | the pixels linearly instead of weaving them results in :math:`4 \times 4` tiles 616 | of down-scaled versions of the picture; the original picture can still be 617 | recognised. The original code does mention four "layers" when it is about to 618 | send the picture to memory. 619 | 620 | 621 | Sprites 622 | ======= 623 | 624 | Sprites are stored in the file VSWAP, together with textures and sound effects, 625 | there are no other files involved. Each sprite is :math:`64 \times 64` pixels 626 | large. They are drawn column-wise and since there is a lot of empty columns 627 | left and right of the visible picture. Only the columns between and including 628 | the outer-most non- empty columns are given. Each column is described via a 629 | variable-length list of drawing instructions, each instruction being six bytes 630 | in size. 631 | 632 | 633 | VSWAP 634 | ----- 635 | 636 | The first six bytes of this file is the header consisting of three signed 637 | :math:`16`-bit integers. The first integer is the total number of chunks in the 638 | file, regardless of type. The second integer is the starting index of the 639 | sprite chunks relative to the beginning of the file. The third integer is the 640 | starting index of the sound effects. I will only be focusing on the sprites 641 | here. 642 | 643 | Next up is a list of all chunk offsets. They are stored as unsigned 644 | :math:`32`-bit integers and their amount is the number of chunks. It is 645 | followed by a second list, the list of chunk lengths, same amount but stored as 646 | words. To decide whether a chunk is a texture, a sprite or a sound one has to 647 | use the chunk's index and compare it to the number of sprite- and sound chunks 648 | and their starting index. If you want to read a sprite or a sound you have to 649 | add the starting index to the magic number, for example if the sprite index is 650 | :math:`35` and we want to read sprite :math:`8` we have to read chunk 651 | :math:`43`. 652 | 653 | Once we have a sprite's offset and length we can read it. The sprite has its 654 | own header consisting of two words followed by an array of up to :math:`64` 655 | words. The first word is the index of the left-most non-empty column, the 656 | second word is the index of the right-most column. The array is of variable 657 | length and contains the offsets to the head of the drawing instruction list of 658 | each column; the first array element is the offset to the drawing instruction 659 | list of the left-most non-empty column, the last array element is the offset 660 | for the right-most non-empty column, and evey element in between belongs to the 661 | column after the previous one. All these offsets are relative to the beginning 662 | of the sprite, not the VSWAP file. method 663 | 664 | The number of instruction offsets can be computed as follows: `last_column - 665 | first_column + 1`. The index of the beginning of the pixel data within the 666 | sprite can thus be found as follows 667 | 668 | .. code:: 669 | 670 | (last_column - first_column + 1 + 2) * sizeof(word) 671 | 672 | Here is a schematic of a sprite chunk 673 | 674 | .. code:: 675 | 676 | Word = first_column 677 | | 678 | Word = last_column 679 | | 680 | Word = offset[0] -> |W|W|W| ... |W|W|W| 681 | : 682 | Word = offset[n] -> |W|W|W| ... |W|W|W| 683 | | 684 | Byte = data 685 | : 686 | Byte = data 687 | 688 | A `W` means `word`, a `B` means `byte`, a `- ` means "is" and a `->` means 689 | "points to" or "is an offset to", offsets are relative to the beginnig of the 690 | chunk. The data stands to any remaing data that's in the sprite, regardless of 691 | what it represents. It is given in bytes, because that's how the pixels will be 692 | read, but the column instructions are three *words*, so take care to read three 693 | words or six bytes, not three bytes. method 694 | 695 | To fill the image with pixels we fill the entire image with transparency (byte 696 | `0xFF`). Next we iterate over the non-empty columns. Here the variable `x` will 697 | refer to the index of the current column, it gives us the horizontal position 698 | of the pixel. The vertical position is derived from the drawing instructions: 699 | the first word divided by two is the lower starting point of the pixel 700 | sequence, the third word is the upper end point of the sequence (columns are 701 | drawn from bottom to top). If the first word is `0x0000` it means the end of 702 | the column has been reached and we can advance `x` to the next one. The middle 703 | word is used to reference which pixels to use, but oddly enough it is not 704 | necessary. method 705 | 706 | All that's missing now is how which pixels to draw onto the sprite. Sprites use 707 | a sort of RLE-compression: in the compressed sprite data each byte after the 708 | instruction offsets is a pixel sequence and the n-th sequence belongs to the 709 | n-th instruction. The extents of the instruction tell us how many pixels from 710 | that sequence to draw. After an instruction has been executed move on to the 711 | next pixel. Here is the pseudocode 712 | 713 | -------------------------------------------------------------------------------- 714 | 715 | :Constants: `transparency = 0xFF` 716 | 717 | :Prerequsites: 718 | - `chunk`: pointer to the compressed chunk as a byte sequence 719 | - `first_colum`: index of the first column (within range :math:`[0, 63)`, less 720 | than last_column) 721 | - `last_colum`: index of the last column (within range :math:`(0, 63]`, 722 | greater than first_column) 723 | - `offsets`: offsets of the column drawing instructions 724 | - `i`: `(last_column - first_column + 1 + 2) * sizeof(word)` 725 | - Must allocate enough space to hold decompressed sprite (:math:`64 \times 64` 726 | bytes) 727 | 728 | :Code: 729 | 1) Fill entire sprite with the colour for transparency 730 | 2) Make pointer to word `column_offset_reader` and set it to the first column 731 | instruction offset 732 | 3) For (word `column = first_column`, while `column <= last_column`, 733 | iterate `++column`) 734 | 735 | 1) Make pointer to word `drawing_instruction` and set to `chunk` + 736 | value of `column_offset_reader` (as word) 737 | 2) Make integer `idx = 0` 738 | 3) While `drawing_instruction[idx] != 0x0000` 739 | 740 | 1) For (word `row = drawing_instruction[idx+2] / 2`, 741 | while `row < drawing_instruction[idx] / 2`, iterate `++row`) 742 | 743 | 1) `result[column + (63 - row) * 64]` = `chunk[i]` 744 | 2) `++i` 745 | 2) `idx += 3` 746 | 4) Advance `column_offset_reader` by one word 747 | 748 | -------------------------------------------------------------------------------- 749 | 750 | Now about the second word of the instruction; rather than using the above 751 | method to get the pixel sequence it is possible to use that word. Use the 752 | numeric value of the word plus the current row as the offset from the beginning 753 | of the compressed chunk. As far as I can tell both ways yield the same result, 754 | so I don't know which one to prefer. If in doubt go with this one though, just 755 | in case that there is a weird exception somewhere out there. Here is the 756 | modified pseudocode from above 757 | 758 | -------------------------------------------------------------------------------- 759 | 760 | :Code: 761 | 1) ... 762 | 2) ... 763 | 3) ... 764 | 765 | 1) ... 766 | 2) ... 767 | 3) ... 768 | 769 | 1) ... 770 | 771 | 1) `result[column + (63 - row) * 64] = 772 | chunk[drawing_instruction[idx+1] + row]` 773 | 2) ... 774 | 4) ... 775 | 776 | -------------------------------------------------------------------------------- 777 | 778 | We don't need the variable `i` anymore, and so we don't increment it either. 779 | 780 | 781 | Interpreting sprites 782 | -------------------- 783 | 784 | Sprites use the same palette as bitmap pictures, but the order in which pixels 785 | are stored is different. If you have been following the above instructions the 786 | sprite will be flipped horizontally, i.e. upside-down. This means the first row 787 | in the raw byte data is the last row in the RGB data, the second row is the 788 | second-to-last and so on. Columns are not affected. method 789 | 790 | 791 | 792 | Textures 793 | ======== 794 | 795 | Textures are simple since they are not compressed. Just like sprites they are 796 | always :math:`64 \times 64` pixels large, but they have no holes. They are also 797 | stored in the VSWAP file, but their type has no offset, the magic number of a 798 | texture is the number of its chunk. To read the texture simply read 799 | :math:`4096` bytes from the chunk verbatim. That fixed number can be replaced 800 | by the chunk length as discussed above for sprites. method 801 | 802 | Textures use the same palette as bitmap pictures and sprites as well, but the 803 | order of their pixels is different. The entire image is transposed, meaning that 804 | the row and column of each pixel need to be swapped, like a transposed matrix. 805 | Or in other words, Wolfenstein 3D drew the textures column-first, row-second. 806 | method 807 | 808 | 809 | 810 | Audio 811 | ##### 812 | 813 | Audio is divided into two categories: sound effect and music tracks and they 814 | share the same files. There is a head file called *AUDIOHED* that contains the 815 | offsets to the the individual chunks as signed 32-bit integers and the chunks 816 | are stored uncompressed in the *AUDIOT* file. method 817 | 818 | 819 | 820 | AUDIOHED 821 | ======== 822 | 823 | There are three types of sound effects: PC speaker, AdLib sound and digitised 824 | sound. Every sound effect exists in every format, although it may be defined 825 | just as empty data, and they are stored in the same order, so the magic number 826 | of a sound effect needs to be mapped to the appropriate chunk. Given the number 827 | of sound effects, which is hard-coded, we can compute the starting offsets of a 828 | format by multiplying a number with the total number of sound effects. 829 | 830 | ========== ========= 831 | Type Offset 832 | ========== ========= 833 | PC-speaker :math:`0` 834 | AdLib :math:`1` 835 | Digitised :math:`2` 836 | Music :math:`3` 837 | ========== ========= 838 | 839 | To get the AdLib version of sound `n` we can thus compute its index as `1 * 840 | number_of_sounds + n`. We can also see that the music chunks follow the sound 841 | effect chunks, and their amount is also hard-coded. We can thus compute the 842 | total number of chunk offsets as follows 843 | 844 | .. code:: 845 | 846 | number_of_offsets = start_music + number_of_tracks + 1 847 | 848 | Where does that extra `1` come from? That's the offset to an imaginary chunk 849 | one past the last chunk. It does not exist, but it is necessary for computing 850 | the length of the last chunk. Computing the length of a chunk is done using the 851 | offset of the next chunk; for the i-th chunk that would be 852 | 853 | .. code:: 854 | 855 | size[i] = offset[i+1] - offset[i] 856 | 857 | It is possible that the size of some chunks is `0`, in this case the chunk can 858 | be seen as non-existent and should be skipped. In fact, all the digitised sound 859 | effects are like this, they are actually stored in the *VSWAP* file instead, 860 | right after the sprite chunks. method 861 | 862 | 863 | 864 | AUDIOT 865 | ====== 866 | 867 | This file is a container for various other files, stored as uncompressed chunks 868 | all lumped together. To find a particular chunk use its offset and size gotten 869 | from the *AUDIOHED* file. What to do with that chunk varies on a type-by-type 870 | basis. There are also tags of the form `!ID!` (`0x21 0x49 0x44 0x21`) the the 871 | end of each file format group, but they are skipped by the offsets anyway. 872 | method 873 | 874 | The AdLib sound effects and the music are stored in a format that has been 875 | specifically designed for AdLib sound cards, so unlike the other data it cannot 876 | be simply converted to wave data. One would have to emulate the AdLib hardware, 877 | at least the necessary parts, or use a library. method 878 | 879 | 880 | Sound effects 881 | ------------- 882 | 883 | As explained above there are three different types of sound effects and they 884 | are stored ordered by format first and magic number second. Digitised sound is 885 | an exception though: MUSE, the program used by Id, offered that format but 886 | never supported it. The data structures are all there, but they are never used 887 | and the chunks in the AUDIOT file all the length :math:`0`. They are stored in 888 | another file instead. 889 | 890 | 891 | PC speaker 892 | ---------- 893 | 894 | PC speaker sound effects are a form of *inverse frequency sound format* where 895 | the data bytes represent the inverse of the frequency to play. Here is how the 896 | file is composed: the first four bytes are an unsigned 32-bit integer giving 897 | the length of the sound data, it should be the size of the chunk minus 898 | :math:`7`. It is followed by two bytes of unsigned 16-bit integer giving the 899 | priority of the sound effect. Since in the original engine only one sound could 900 | play at a time a sound will interrupt any sound of lower or equal priority. 901 | Next up is the sequence of data bytes of the length encoded in the first four 902 | bytes. Finally one single byte is used to terminate the file, it is usually 903 | (always?) :math:`0x00`. The file has therefore :math:`7` bytes of non-sound 904 | data (length, priority and terminator). There is no file name encoded, so the 905 | file can only be accessed using the magic number of the sound effect. 906 | 907 | Each byte (unsigned 8-bit integer) of the audio data sequence represents a 908 | certain sound frequency measured in *Hz*. The frequency can be computed this 909 | way: 910 | 911 | .. code:: 912 | 913 | frequency = 1193181 / (value * 60) // for value != 0 914 | = 0 // for value == 0 915 | 916 | The number `1193181` has the hexadecimal value `0x1234DD`. The refresh rate of 917 | the speaker is :math:`140` Hz, so each instruction lasts :math:`\frac{1}{140}` 918 | seconds. Also keep in mind that multiplying a byte value by :math:`60` can 919 | exceed the range of an :math:`8`-bit integer, so the computation has to be done 920 | at least using :math:`16` bits. 921 | 922 | ============ ========== ============================================== 923 | Data type Name Description 924 | ============ ========== ============================================== 925 | Uint32 length Length of sound data, chunk length - :math:`7` 926 | Uint16 priority Higher priority wins 927 | Byte[length] data Actual audio data 928 | Uint8 terminator Unused by the game 929 | ============ ========== ============================================== 930 | 931 | 932 | Interpreting the data 933 | ~~~~~~~~~~~~~~~~~~~~~ 934 | 935 | Aside from the raw audio data there is no playback information stored in the 936 | file, everything is hard-coded. Since the PC speaker was not able to play 937 | different tones many developers used a trick called *pulse-width modulation* to 938 | create the illusion. The frequency perceived by the listener is created by 939 | precisely controlling short bursts of audio pulses. Explaining the mathematical 940 | properties would be beyond the scope of this document, so I'll refer instead to 941 | its [Wikipedia article](http://en.wikipedia.org/wiki/Pulse-width_modulation). 942 | 943 | Each byte tells us how long the the phase needs so be. First we read a byte and 944 | muliply its numeric value by :math:`60` (hard-coded number). This lets us 945 | compute the length of the phase 946 | 947 | .. code:: 948 | 949 | tone = input_byte * 60 950 | phase_length = sample_rate * (tone / 1193181) * 1/2 951 | 952 | The *sample rate* depends on how precisely we want to sample the data. Higher 953 | numbers are more precise, but take up more space. We also need to make sure the 954 | sample rate matches the sample rate of our playback, i.e. it is the number of 955 | samples played per second. A value of :math:`40,000` is adequate. 956 | 957 | The formula works as follows: looking at the second formula we compute the 958 | inverse of the frequency we want to simulate. This means a higher frequency 959 | will have a shorter duration than a lower one. This inverse frequency is 960 | multiplied by the sample rate; frequencies are measured in Hz, which is just 961 | another way of writing :math:`\frac{1}{s}`, i.e. one per second of something, 962 | so an inverse frequency is a duration, measured in seconds. The sample rate is 963 | measured in *samples/second* and by multiplying it with the duration we get the 964 | number of samples to generate. Finally we divide by two because we need to flip 965 | back-and forth between high and low volume at the half-point mark. 966 | 967 | Now it's time to write the sample bytes. How many samples should be written per 968 | byte depends on the selected sample rate as well as the original playback rate 969 | of :math:`140` Hz. 970 | 971 | .. code:: 972 | 973 | samples_per_byte = sample_rate / 140 974 | 975 | For each byte written we also keep track of the "ticks": each written byte 976 | increments the counter, and if the ticks have reached the phase length we flip 977 | the sign and reset the counter. A tone of :math:`0` interrupts everything, it 978 | writes the neutral sound (:math:`128`) and keeps the tick counter at :math:`0`. 979 | The byte written is :math:`128` plus the volume level of the simulated speaker. 980 | This level can be chose arbitrarily, as long as it's less or equal to 981 | :math:`127.` 982 | 983 | Here is the pseudocode: 984 | 985 | -------------------------------------------------------------------------------- 986 | 987 | :Constants: 988 | - `base_timer = 1193181` 989 | - `pcs_rate = 140` (playback rate of PC speaker) 990 | - `volume = 20` (arbitrarily chosen, must be :math:`≤ 127`) 991 | 992 | :Prerequisites: 993 | - `source`: pointer to the start of the input stream as bytes. 994 | - `destination`: pointer to the start of the decompressed output stream as 995 | bytes 996 | - `pcs_length`: length of the decompressed data sequence in words 997 | - `sample_rate`: how many samples to play back per second 998 | 999 | :Side effects: The destination buffer will be allocated and filled with data 1000 | 1001 | :Code: 1002 | 1) Make new variable `samples_per_byte = sample_rate / pcs_rate` 1003 | 2) Make new variable `wav_length = pcs_length * samples_per_byte * 1004 | sizeof(byte)` 1005 | 3) Allocate memory to `destination` of length `pcs_length * samples_of_bytes 1006 | *sizeof(byte)` 1007 | 4) Make new pointers `read` and `write` and set them to `source` and 1008 | `destination` respectively 1009 | 5) Make new signed integer variable `sign = -1` 1010 | 6) Make new unsigned integer variable `phase_tick = 0` 1011 | 7) While `pcs_length > 0` 1012 | 1013 | 1) Make new variable `tone = (value of read) * 60`, advance `read` by 1014 | one byte 1015 | 2) Make new variable `phase_length = sample_rate * (tone / base_timer) * 1016 | 1/2` 1017 | 3) For (`int i = 0`, while `i < samples_per_byte`, iterate `++i`) 1018 | 1019 | 1) If `tone != 0` 1020 | 1021 | 1) Write `(128 + sign * volume)` to `write`, advance `write` 1022 | 2) If `phase_tick >= phase_length` 1023 | 1024 | 1) `sign *= -1` 1025 | 2) `phase_tick = 0` 1026 | 3) `++phase_tick` 1027 | 2) Else 1028 | 1029 | 1) `phase_tick = 0` 1030 | 2) Write 128 to `write`, advance `write` 1031 | 4) `--pcs_length` 1032 | 1033 | -------------------------------------------------------------------------------- 1034 | 1035 | Bytes are in this document equivalent to unsigned 8-bit integers, so it might 1036 | look conflicting that we use a signed integer and use it for multiplication. 1037 | However, since the neutral sound is :math:`128`, the middle of the 8-bit value 1038 | range, it doesn't matter in C. For other languages this might not necessarily 1039 | hold true though, so make sure it is well-defined. 1040 | 1041 | 1042 | AdLib 1043 | ~~~~~ 1044 | 1045 | AdLib sounds are written to specifically talk to the AdLib sound card. It 1046 | starts with a header of six bytes: the first four bytes are an unsigned 32-bit 1047 | integer for the *length* of the sound data in bytes, the remaining two bytes 1048 | are the *priority*, similar to the priority for PC speaker sound. 1049 | 1050 | Then comes the relevant part: :math:`16` bytes of instrument settings followed 1051 | by a byte for the octave number and then the data bytes with the length from 1052 | above. 1053 | 1054 | Finally we have a footer consisting of a terminator byte, not used by the game, 1055 | and a null-terminated ASCII string for the file name, not used either. 1056 | 1057 | ============ =========== ======================== 1058 | Data type Name Description 1059 | ============ =========== ======================== 1060 | Uint32 length Length of the sound data 1061 | Uint16 priority Higher priority wins 1062 | Byte[16] instrument Instrument settings 1063 | Byte octave Octave to play notes at 1064 | Byte[length] data Actual audio data 1065 | Uint8 terminator Unused by the game 1066 | Char[] file name Null-terminated string 1067 | ============ =========== ======================== 1068 | 1069 | The instrument settings are as follows: 1070 | 1071 | ========= ======= ============ ======================================== 1072 | Data type Name OPL register Description 1073 | ========= ======= ============ ======================================== 1074 | Uint8 mChar `0x20` Modulator characteristics 1075 | Uint8 cChar `0x23` Carrier characteristics 1076 | Uint8 mScale `0x40` Modulator scale 1077 | Uint8 cScale `0x43` Carrier scale 1078 | Uint8 mAttack `0x60` Modulator attack/decay rate 1079 | Uint8 cAttack `0x63` Carrier attack/decay rate 1080 | Uint8 mSus `0x80` Modulator sustain 1081 | Uint8 cSus `0x83` Carrier sustain 1082 | Uint8 mWave `0xE0` Modulator waveform 1083 | Uint8 cWave `0xE3` Carrier waveform 1084 | Uint8 nConn `0xC0` Feedback/connection (usually ignored and 1085 | set to :math:`0`) 1086 | Uint8 voice none unused by game 1087 | Uint8 mode none unused by game 1088 | Uint8[3] padding none pad instrument definition up to :math:`16` 1089 | bytes 1090 | ========= ======= ============ ========================================== 1091 | 1092 | Sound effects are played on channel :math:`0` because the other channels of the 1093 | sound card are reserved for music; the replay rate is :math:`140` Hz. The 1094 | octave value is written to AdLib register `0xB0` and it must be computed to 1095 | following way to prevent it from interfering with other bits stored in the 1096 | register 1097 | 1098 | .. code:: 1099 | 1100 | block = (octave & 7) << 2 // 7=00000111b 1101 | regB0 = block | other_fields 1102 | 1103 | The audio data consists oft he raw bytes to send to register `0xA0` and the 1104 | byte `0x00` means silence. Silence can be achieved by setting the fifth bit 1105 | (hexadecimal `0x20`) to `0x00` in register `0xB0`. Here is the pseudocode for 1106 | playback: 1107 | 1108 | -------------------------------------------------------------------------------- 1109 | 1110 | :Constants: 1111 | - `block = (octave & 7) << 2` 1112 | - `note_on = 0x20` 1113 | 1114 | :Prerequisites: Byte sequence of audio data to read 1115 | 1116 | :Code: 1117 | 1) Make boolean variable `note` and set to false 1118 | 2) Make byte variable `next_byte` 1119 | 3) While there is data to read 1120 | 1121 | 1) Read `next_byte` 1122 | 2) If (`next_byte == 0x00)` 1123 | 1124 | 1) Set register `0xB0` to `block` 1125 | 2) Set `note` to false 1126 | 3) Else 1127 | 1128 | 1) Set register `0xA0` to `next_byte` 1129 | 2) If (`note == false`) 1130 | 1131 | 1) Set register `0xB0` to (`block | note_on`) 1132 | 2) Set `note` to true 1133 | 4) Wait until next tick (playmback rate :math:`140` Hz) 1134 | 1135 | -------------------------------------------------------------------------------- 1136 | 1137 | The original code also checked if the next byte was equal to the previous one, 1138 | and if so it kept playing the same note instead of sending the same data to the 1139 | sound card again. 1140 | 1141 | 1142 | Digitised 1143 | ~~~~~~~~~ 1144 | 1145 | Digitised sound effects, such as voices or gun shots are stored in the VSWAP 1146 | file. That file has been discussed in the *sprites* section, so refer there for 1147 | information on how to read the file. The data chunks are raw PCM data, played 1148 | back at a sample rate of :math:`7000` Hz, mono sound and eight bytes per 1149 | sample. 1150 | 1151 | Where it gets complicated is that some audio files are split over multiple 1152 | successive audio chunks; one example is the very first effect ("Achtung!), 1153 | which is split over the first and second chunk. That is also why there are more 1154 | sound effect chunks than there are sound effects (:math:`120` instead of 1155 | :math:`46`). We must read the last chunk of the VSWAP file, it contains the 1156 | audio list consisting of pairs of words; the first word is the index of the 1157 | biginning of the first audio chunk, the second word is the length of the 1158 | complete audio chunk. This means that the global list of lengths and offsets 1159 | detailed in the *sprites* section is only needed for the offsets. 1160 | 1161 | The index of a sound effect chunk can be learned by adding the effect's index 1162 | from the audio list and the sound start index. This gives us the global file 1163 | index of the first chunk of the sound effect. Using this global index we can 1164 | find the offset of the chunk in the lgobal list. The length of the total audio 1165 | sequence is the length from the audio list. 1166 | 1167 | The number of digitised sound effects is the length of the audio list divided 1168 | by four. The length of the list is the length of the VSWAP file minus the 1169 | offset of the list, i.e. the list is the very last chunk of the file. 1170 | 1171 | 1172 | Music tracks 1173 | ------------ 1174 | 1175 | The music format is *WLF*, which is essentially type-1 *IMF* whith a playback 1176 | rate of :math:`700` Hz instead of :math:`560` Hz. Here is how a *WLF* file is 1177 | composed: 1178 | 1179 | ============ ========== ====================================== 1180 | Type Name Description 1181 | ============ ========== ====================================== 1182 | Uint16 Length Length of the sound data 1183 | Byte[length] Sound data The sound data to play 1184 | Byte[] Metadata Arbitrary metadata, unused by the game 1185 | ============ ========== ====================================== 1186 | 1187 | The sound data consists of byte quartets of the following form: 1188 | 1189 | ==== ============== 1190 | Type Description 1191 | ==== ============== 1192 | Byte AdLib register 1193 | Byte AdLib data 1194 | Word Delay 1195 | ==== ============== 1196 | 1197 | There is also an optional footer that contains metadata that will not be used 1198 | for playback but can be used by an audio editor: 1199 | 1200 | ======== ======= ================================== 1201 | Type Name Description 1202 | ======== ======= ================================== 1203 | Unint16 ??? Unknown 1204 | Char[16] Title Title of the song 1205 | Char[64] Remarks Comments, usually source file name 1206 | Char[6] cProg Unknown, maybe from the compiler 1207 | ======== ======= ================================== 1208 | 1209 | 1210 | 1211 | Levels & Maps 1212 | ============= 1213 | 1214 | Levels are laid out on a :math:`64 \times 64` tile-based square map. This size 1215 | is not hard-coded into the game, so one should not make assumptions about the 1216 | level's size, instead the size should be read from the map file. Although there 1217 | are no official levels of any other size an engine or interpreter should be 1218 | able to support custom-made maps of different size. Each level in the game 1219 | actually consists for three maps overlaying each other: 1220 | 1221 | Architecture 1222 | The first map contains information about the level's architecture, i.e. 1223 | walls, doors and floors. 1224 | 1225 | Objects 1226 | The second map contains the level's objects, i.e. enemies, decorations and 1227 | pick-ups. 1228 | 1229 | Other 1230 | The third map contains other data and is not used in this game, it's a 1231 | leftover from earlier Id titles. 1232 | 1233 | These three individual maps together form the level the player will be playing. 1234 | Usually when speaking about maps one means the entire level, but here we will 1235 | maintain this distinction to avoid confusion or ambiguity. 1236 | 1237 | Each of the tiles in a level describes a three-dimensional cube in the game 1238 | world with :math:`64` units in length to both sides and :math:`64` units in 1239 | height (i.e. a cube in 3D world space). 1240 | 1241 | 1242 | MAPHEAD 1243 | ------- 1244 | 1245 | The file starts with the signature 16-bit integer `0xABCD` (represented as 1246 | `0xCD 0xAB` bytes in the file). This signature appears always to be the same, 1247 | but we should not make any assumptions; it is used as the signature for the 1248 | RLEW compression algorithm. The file is described by the structure 1249 | `mapfiletype` in the original source code. 1250 | 1251 | Next are exactly :math:`100` 32-bit signed integer values containing the header 1252 | offsets of the actual levels, that amount is hardcoded into the source. Not all 1253 | of these 32-bit numbers have meaningful values, only the first n do, where n is 1254 | the total amount of levels in the game, i.e. :math:`10` in the shareware 1255 | version and :math:`30` or :math:`60` in the full version. The remaining numbers 1256 | are all padding with `0x00000000` as their value. This means the level offsets 1257 | are stored in a `nul`-terminated 4-byte array with a fixed length of 1258 | :math:`100.` 1259 | 1260 | The last remaining byte always appears to be be `0x00` and it's called the 1261 | `tileinfo` in the original source code and is declared as an array of 1262 | unspecified size of type `byte`. The type `byte` is a typedef for `unsigned 1263 | char` and equal to an 8-bit integer on the target architecture of Wolfenstein 1264 | 3D's original code. It appears to be a leftover from the map format of previous 1265 | Id Software games that did use it. 1266 | 1267 | Note that there is no information in this file as to how many levels there are 1268 | in the game. This information would have to be calculated from the file's size 1269 | itself. To compute that number one would have to step through the list of 1270 | header offsets until reaching the first offset that's `0x00000000` (start of 1271 | the padding). The number of steps is equal to the number of levels. 1272 | 1273 | ============= ========== ================================================ 1274 | Name Type Description 1275 | ============= ========== ================================================ 1276 | Signature Word Used for RLEW decompression, usually `0xCD 0xAB` 1277 | Header offset Int32[100] Offsets into the gamemaps file 1278 | Tile info Byte Unused, usually `0x00` 1279 | ============= ========== ================================================ 1280 | 1281 | 1282 | GAMEMAPS 1283 | -------- 1284 | 1285 | This file contains the actual information about the levels and their individual 1286 | maps. A level is made from a *level header*, which describes where to find the 1287 | level's maps, their compressed sizes, the size of the level and finally the 1288 | name of the level. 1289 | 1290 | The header can be found using the offset from the *MAPHEAD* file as an absolute 1291 | value, i.e. relative to the start of the file. From there on the header is 1292 | stored as an uncompressed sequence of raw information. 1293 | 1294 | The first three values are 32-bit signed integer values each. The first one is 1295 | holding the offset to the level's architecture map, the next value is the offset 1296 | to the level's object map and the third value is the offset to the level's logic 1297 | map. All values are absolute offsets from the beginning of the file, not 1298 | relative offsets from the header or relative to each other. 1299 | 1300 | The next three values are unsigned 16-bit integer values describing the 1301 | Carmack-compressed length in bytes of each map; this is important because the 1302 | maps are lumped together adjacent to each other with no separator. Their order 1303 | is again first architecture, then objects and then logic. 1304 | 1305 | Next are two unsigned 16-bit integers describing the width and height of the 1306 | level, in that order. The size appears to always be :math:`64 \times 64`, but 1307 | since it's not hardcoded it should not be assumed. 1308 | 1309 | Finally :math:`16` characters, 8-bit ASCII each, form the level's name. In the 1310 | original implementation the characters are stored in an array of type `char` 1311 | with unspecified size. This is the standard way of storing ASCII strings in C, 1312 | but the string needs to be terminated with `\0` (the null character). In the 1313 | file any remaining bytes are filled with `\0`, but in the code there is nothing 1314 | to ensure that the string is indeed properly terminated, leaving a possibility 1315 | for an error to happen. 1316 | 1317 | ============== ========= =========================================== 1318 | Name Type Description 1319 | ============== ========= =========================================== 1320 | Map offset Int32[3] Offset of the three maps, absolute from the 1321 | beginning of the file 1322 | Carmack length Uint16[3] Length of the Carmack-compressed map 1323 | Width Uint16 Width of the level 1324 | Height Uint16 Height of the level 1325 | Level name Char[16] Name of the level 1326 | ============== ========= =========================================== 1327 | 1328 | The first word of a map is the most north-western tile, and each column is one 1329 | more tile to the east, each row one tile to the south. 1330 | 1331 | 1332 | Extracting the maps 1333 | ------------------- 1334 | 1335 | Maps are compressed using the RLEW compression and then compressed on top of 1336 | that using Carmack compression. To decompress them one has to first 1337 | Carmack-decompress the data and then RLEW-decompress it. For Carmack 1338 | compression one can find the decompressed length encoded into the compressed 1339 | map as the fist word, it is given in bytes. This means the pointer to the 1340 | compressed sequence must be advanced by one before starting the decompression. 1341 | For some reason the pointer to the Carmack-decompressed but still 1342 | RLEW-compressed sequence must be advanced by one word as well; could be a 1343 | leftover from a previous map format. The size of the uncompressed RLEW data is 1344 | hardcoded as `64*64*2` bytes or :math:`4096` words. Since the size is also 1345 | stored in the map format it might be a better idea to use that value instead 1346 | and allow levels of different size for mods. The RLEW tag can be found in the 1347 | MAPHEAD file as described above. 1348 | 1349 | 1350 | 1351 | Appendix 1352 | ######## 1353 | 1354 | 1355 | Known bugs and limitations 1356 | ========================== 1357 | 1358 | 1. A map needs at least one enemy, one piece of treasure and one secret door, 1359 | or else the game will crash. This is the result of the game trying to 1360 | calculate the percentage the player has picked up and ending up dividing by 1361 | zero. 1362 | 1363 | 1364 | Distributions of the game and magic numbers 1365 | =========================================== 1366 | 1367 | Different versions of the game assign different key numbers to the graphics. 1368 | Each graphic can be identified using an integer "key" magic number and that 1369 | number depended on what the graphics artists produced. This means the 1370 | programmers would have had to keep a list of key numbers and always change their 1371 | code when the graphics changed. Instead the software used by the artists 1372 | produced alongside the data files also a header file that mapped each number to 1373 | a macro, so the developers could simply use the macro and the generated header 1374 | would map the macro to the correct number. 1375 | 1376 | The problem with this is that each build was only suitable for a particular 1377 | distribution of the game, like shareware, registered, Japanese or Spear of 1378 | Destiny. The simple solution is to use `#ifdef` directives and set the version 1379 | at compile time, which is an acceptable solution when building for a particular 1380 | release, but ill-suited for a source port that needs to be as compatible as 1381 | possible. I propose the following solution that moves the version detection 1382 | from compile-time to run-time. 1383 | 1384 | There will be one global header file that has a universal mapping that assigns a 1385 | number to any image that might exist in any distribution. It is not necessary 1386 | for it to be compatible to any existing distribution. The programmers will use 1387 | these global macros then. For each distribution there will be a mapping that 1388 | maps the universal macro to the distribution's corresponding key number. At 1389 | run-time when the program starts determine the distribution and assign a global 1390 | mapping variable to be the mapping for that distribution. The mapping could for 1391 | example be done using an array where the universal macro is the index and the 1392 | distribution's key the value. Trying to access an image that does not exist in 1393 | that particular distribution could be mapped to an invalid number such as -1. 1394 | 1395 | 1396 | References 1397 | ========== 1398 | 1399 | The following sources were used for reference and to guide me in the right 1400 | direction: 1401 | 1402 | - `Wolfenstein 3D source code 1403 | `_ 1404 | - `Chocolate Wolfenstein 3D source code 1405 | `_ 1406 | - `Wolfensein 3D on Modding Wiki 1407 | `_ 1408 | - `Some guy's abandoned attempt to understand the game data 1409 | `_ 1410 | 1411 | --------------------------------------------------------------------------------