Hocus Pocus Map Format
Format type | Map/level |
---|---|
Map type | 2D tile-based |
Layer count | 4 |
Tile size (pixels) | 16×16 |
Viewport (pixels) | 320×160 |
Games |
Hocus Pocus maps consist of 13 individual files which will be referred to using the extensions .000 to .012 for convenience (as neither filenames nor extensions are stored in HOCUS.DAT). Each map uses four layers: a background layer, two foreground layers and an "event" layer containing enemies, treasures and such. The background and foreground layers are 14400 bytes long, corresponding to a level sized 240x60 tiles. Maps are stored left-to-right, top-to-bottom. The event layer is 28800 bytes long, stored in the same way but with 2 bytes per tile.
File Formats
*.000 (8 bytes)
0 UINT16LE iNull 2 UINT16LE iPlayerX 4 UINT16LE iPlayerY 6 UINT16LE iShootDelay The lower value, the more frequently enemies shoot projectiles (45 = standard value, 0 crashes game)
*.001 (724 bytes)
This stores animation setings for the tileset. The file contains this 4-byte header:
0 UINT8 iBackgroundTile 1 UINT8 iSwitchDownTile 2 UINT8 iSwitchUpTile 3 UINT8 iShootableTile
The header is followed by 240 entries of the following structure:
TAnimData (3 bytes): 0 UINT8 iFirstIndex 1 UINT8 iLastIndex 2 UINT8 iAnimType 0 = no animation, 1 = permanent animation, 2 = animation starts at random
*.002 (5040 bytes)
This file stores 10 entries of the following structure:
TMessageData (504 bytes): 0 UINT16LE iPosX 2 UINT16LE iPosY 4 CHAR[50] cLine0 54 CHAR[50] cLine1 104 CHAR[50] cLine2 154 CHAR[50] cLine3 204 CHAR[50] cLine4 254 CHAR[50] cLine5 304 CHAR[50] cLine6 354 CHAR[50] cLine7 404 CHAR[50] cLine8 454 CHAR[50] cLine9
*.003 (40 bytes)
This file contains data for the teleporting potions. The file stores 10 entries of the following structure:
TTeleportCoordinates (4 bytes): 0 UINT16LE iStartOff index into linear map layer data 2 UINT16LE iEndOff
*.004 (506 bytes)
This file stores 23 entries of the following structure:
TSwitchCoordinates (22 bytes): 0 UINT16LE iSwitchType 0 = remove tiles from map layer, 1 = fill with tiles from additional map layer 2 UINT16LE iSwitchOff0 offset into background layer; $FFFF if unused 4 UINT16LE iSwitchOff1 6 UINT16LE iSwitchOff2 8 UINT16LE iSwitchOff3 10 BYTE bDesiredTile0 this data must be in the background layer at the offset given above for the switch to be activated 11 BYTE bDesiredTile1 12 BYTE bDesiredTile2 13 BYTE bDesiredTile3 14 UINT16LE iUpperLeftX 16 UINT16LE iUpperLeftY 18 UINT16LE iLowerRightX 20 UINT16LE iLowerRightY
*.005 (300 bytes)
This file stores 25 entries of the following structure:
TToggleCoordinates (12 bytes): 0 UINT16LE iRequiredKey always 0 in the original files, but the game does check this value and behave accordingly 2 UINT16LE iRequiredTile 4 UINT16LE iUpperLeftX 6 UINT16LE iUpperLeftY 8 UINT16LE iLowerRightX 10 UINT16LE iLowerRightY
*.006 (300 bytes)
This file stores 25 entries of the following structure:
TToggleCoordinates (12 bytes): 0 UINT16LE iRequiredKey 0 = no key required, 1 = silver key, 2 = gold key 2 UINT16LE iRequiredTile tile number in backgrund layer 4 UINT16LE iUpperLeftX 6 UINT16LE iUpperLeftY 8 UINT16LE iLowerRightX 10 UINT16LE iLowerRightY
*.007 (240 bytes)
This contains 10 entries of the following structure:
0 UINT16LE iSpriteSet $FFFF = unused entry. Used iSpriteSet values are: 0x04-0x15, 0x17-0x1C, 0x1E-0x27. 2 UINT16LE iHealth if this value plus the current difficulty setting is 20 or higher, enables boss health bar and kill-on-touch. 4 UINT16LE iProjectileHSpeed 6 UINT16LE iProjectileVSpeed 8 UINT16LE iProjectileXOffset Valid for vertical projectiles 10 UINT16LE iTargetPlayer If 1, vertical projectiles will move horizontally towards the player. 12 UINT16LE iUnknown2 14 UINT16LE iShootProjectiles If 1, enemy will fire projectiles. 16 UINT16LE iUnknown3 18 UINT16LE iWobblyProjectiles If 1, projectiles will have a wobbly motion. 20 UINT16LE iUnknown4 Always 0 22 UINT16LE iBehavior
Valid iBehavior values are:
- 0: Walk around, stop when shooting
- 1: Walk around, dash towards player, don't stop when shooting
- 2: Fly, facing one direction
- 3: Fly, facing towards player
- 4: Stand still, animated, firing rapidly (1st episode boss)
- 5: Stand still, animated, firing normally (flower)
- 6: 3, but faster (ghost)
- 7: Bugged
- 8: Dragon (3rd episode boss)
- 99: Trolodon (4th episode boss)
*.008 (8000 bytes)
This file stored data required for spawning enemies. It consists of 250 entries of the following format:
TEnemyEntry (32 bytes): 0 UINT16LE[8] iEnemyType enemy type, $FFFF = unused entry 16 UINT16LE[8] iOffsets index into info layer (info layer is an array of 16 bit values!) or $FFFF for unused slots
*.009 (14400 bytes)
Background Layer (array of 240*60 BYTE values)
$FF means blank space (backdrop is visible), other values are tileset indices
*.010 (14400 bytes)
Map Layer (array of 240*60 BYTE values)
$FF means blank space (backdrop or background layer are visible), other values are tileset indices
*.011 (14400 bytes)
Additional Map Layer (array of 240*60 BYTE values)
$FF means blank space (backdrop or background layer are visible), other values are tileset indices
This layer is almost identical to the main map layer but it is never used directly to draw the maps in the game. It contains all the blocks that will be pasted into the main map layer when a switch (type 1) or an "insert wall" trigger is activated in the game. This layer is NOT used when a switch or a trigger makes walls disappear. In those cases, the area in the main map layer is simply filled with non-tile values ($FF).
*.012 (28800 bytes)
Info/Event Layer (array of 240*60 UINT16LE values)
A value of 30000 ($7530) indicates an empty cell, other values have the following meaning:
0000 red gem (100) 0001 grey gem (250) 0002 goblet (500) 0003 crown (1000) 0004 green potion (healing) 0005 magic crystal 0006 spikes (hazard) 0007 zapper (increase firepower) 0008 -- UNUSED -- (invisibility) 0009 golden potion (jumping power) 000A white potion (rapid fire) 000B -- UNUSED -- 000C silver key 000D gold key 000E lava (hazard) 000F wizard ("hint" messages) 0010 grey potion (3 fireballs) 0011-0016 -- UNUSED -- 0017-001D teleport tags 001E-0020 -- UNUSED -- (teleport tags) 0021-0031 switches 0032-0037 -- UNUSED -- (switches) 0038-003A trigger: insert wall 003B-0050 -- UNUSED -- (trigger: insert wall) 0051-0058 trigger: remove wall 0059-0069 -- UNUSED -- (trigger: remove wall) 006A-006E enemies 006F-0073 -- UNUSED -- (enemies?) 0074-008C trigger: enemies 008D-016D -- UNUSED -- (trigger: enemies)
Tile mapping
The background and foreground layers each store one byte per tile. This is a direct index into the tileset, with the value 0xFF being used as 'no tile' (to see through to the layer below, or in the case of the background layer, to the backdrop image.)
Levels 1 and 2 use the first tileset image in the DAT file, Levels 3 and 4 use the second and levels 5 and 6 use the third tileset image. The last three levels of each episode use the same tileset, which will be the fourth tileset file for Episode 1. The same pattern is repeated for episodes 2 to 4 of the registered version, using tileset images 5 to 16. The same scheme is used for the backdrop images, which are the 4 PCX files (or 16 for the registered version) located directly before the 4 (or 16) PCX files containing the tileset images.
The mapping can be calculated using the following formula (assuming Episode ranges from 0 to 3 and Level ranges from 0 to 8):
TilesetNumber = FirstTilesetNumber + 4*Episode + MIN(Level/2, 3) BackdropNumber = FirstBackdropNumber + 4*Episode + MIN(Level/2, 3)
Note: The game does not calculate the numbers linke this. It has lookup tables in the EXE that define which tileset and backdrop images to use for each level.
The tilesets are in PCX format, as a 320×200 image made up of 16×16 images. Tile 0 is at (0,0) and tile 1 is at (16,0) for example.
Level time limit
Level time limit hardcoded into "HOCUS.EXE" executable file as an array of UINT16LE. Absolute offset to the value of each level time limit can be calculated by formula (taken directly from the disassembled game code):
ArrayOffs + (EpisodeNumber*18) + (LevelNumber*2)
Note that EpisodeNumber and LevelNumber must be zero-based values (starts from 0, not from 1).
Known ArrayOffs values:
0001FAAA: shareware 1.0 0001FDA0: shareware 1.1 00020794: registered 1.0 00020A9A: registered 1.1
Note that ArrayOffs can be found by sequences of bytes 96 00 2C 01 90 01 which are represent time limit (150, 300 and 400) for the first three levels of first episode.
Elevator Tiles
There are two elevator tiles (left and right) which move up or down when the player presses up or down arrow while standing upon one of these tiles (an elevator tile always links with the respective adjacent tile, even if that tile is not an elevator tile).
The tile numbers are stored as an array of 80 SINT16LE values in the executable (at offset 0x21C26 for v1.1 registered). The first two values are the left and right elevator tiles for Episode 1 Level 1. Note that this array actually stores information for 10 levels per episode even though the final game only uses 9 levels per episode.
If the left elevator tile is -1 then the level has no elevators. In that case, the right tile is also set to -1, but the game only checks the left tile to see if the level has any elevators.
Other stuff stored in HOCUS.EXE
! Maybe this should be moved elsewhere. I'm just putting it here to share the knowledge --K1n9 Duk3 (talk) 06:58, 12 April 2016 (UTC)
As you can see from the FAT offset, all these values are for v1.1 registered.
0x1F1A4 - FAT (offset, size) 0x20680 - sound entries (16) (vocFile, pcFile, priority) 0x20A22 - pics for story (10) (picfile, x, y) 0x20A5E - pics for end1 (2) 0x20A6A - pics for end2 (2) 0x20A76 - pics for end3 (4) 0x20A8E - pics for end4 (2) 0x20A9A - par times (9 levels per episode) 0x21714 - item infos 0x21ADA - tileset numbers 0x21B2A - level numbers 0x21B7A - backdrop numbers "[BKG]" "[SLD]" "[FNC]" 0x21BDE - music numbers (9 levels per episode) 0x21C26 - elevator tiles (10 levels per episode) 0x21CC6 - x coords for boss 4 (4 stages) 0x21CCE - y coords for boss 4 (4 stages) 0x21CD6 - tile offsets for boss 4 (= x + 240*y) 0x21CDE - directions for boss 4 0x21CE6 - health thresholds for boss 4 0x21CEE - y increments for super jump (25) 0x21D20 - y increments for normal jump (19) 0x21D46 - health increments for hurting player (all <= 0) ----------------------------------- typedef struct { char name[36]; Sint16 score; Uint8 heal; Uint8 firepower; Uint8 type; Uint8 _padding; } TItemInfo;
Credits
This file format was reverse engineered by Malvineous, K1n9 Duk3, MainMemory and some clarifications were added by Hisymak. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)