Notes:Magic Carpet (DOS)
This page contains notes for the game Magic Carpet (DOS).
Contents
Level.Dat Data Structures
Included with the files of the original CD release of Magic Carpet is a file called GAM00088.DAT. This is an invaluable and interesting file for reverse engineering as it's some kind of internal format used to save the details of an unfinished map. Specifically, this seems to be the raw contents of the map LEV00088.DAT, based on the corresponding .inf file for that cut level (which made it into the game as level 65).
What's so useful is that the map includes headers for the data, therefore naming each attribute. Just as importantly, it also lists the map generator parameters. Magic Carpet is interesting, as while it includes the "MAPHACK" tool to generate height map levels out of user pictures, the game does NOT store height maps in the final levels. In fact they are all procedurally generated on runtime from a set of parameters stored in the level file. Note all levels are of a fixed size (38KB), and pad out any unused space with zero byte entries.
Map Header and Generation Parameters
These begin from the very first byte of each level file up to position 2e. Names are mostly from GAM00088.DAT file, which only begins from the Seed attribute. Note most of the later attributes only seem to work with one byte, higher values seem to crash the game (like rivers).
Variable | Offset (hex) | Length (hex) | Notes |
---|---|---|---|
Level Mana Total | 0x0 | 0x4 | The level's total mana. Note this works in conjunction with the target percentage set at the end of the file. |
Seed | 0x4 | 0x2 | Determines the fundamental map landscape shape |
Blank | 0x6 | 0x2 | |
Off[set] | 0x8 | 0x2 | Offsets the generated landscape horizontally within the map frame |
Blank | 0xA | 0x2 | |
Raise | 0xC | 0x4 | Raises height of landscape peaks |
Gnarl | 0x10 | 0x2 | Gnarls landscape to create tree root style appearance. Rarely used |
Blank | 0x12 | 0x2 | |
River | 0x14 | 0x2 | Generates more rivers on the map. Values above 255 seem to crash the game |
Blank | 0x16 | 0x2 | |
Sourc | 0x18 | 0x2 | Seems to raise sea level/lower base level of terrain. While this seems to use two bytes, going beyond the first byte seems to crash the game |
Blank | 0x1A | 0x2 | |
SnLin | 0x1C | 0x2 | Always C8/200. Not sure what it does |
Blank | 0x1E | 0x2 | |
SnFlt | 0x20 | 0x2 | Generally low number below 50. Unknown what this does |
Blank | 0x22 | 0x2 | |
BhLin | 0x24 | 0x2 | Beach Line? Generally number below 30. This determines how desertified the level is - how much of the terrain is "beach". 255 is pretty much entirely sand. |
Blank | 0x26 | 0x2 | |
BhFlt | 0x28 | 0x2 | Values generally below 20. Presumably beach related, but not apparent what this actually does |
Blank | 0x2A | 0x2 | |
RkSte | 0x2C | 0x2 | Unknown. Values generally below 40 |
There is then a lots of zeroed data until position 442. This seems to be fixed across all levels as the start of Thing data.
Thing Definitions
These always begin at position 442 in a level file. These include everything the player can see and interact with in the game, from enemies to collectables to switches. Each entry is 18 bytes long, and there are 1999 entries.
To do: Fill this out, Michael Howard's work here already collects 99% of it |
Variable | Offset (hex) | Length hex) | Notes |
---|---|---|---|
Class | 0x0 | 0x2 | What type of thing it is - enemy, scenery, etc |
Model | 0x1 | 0x2 | Sub type. Which enemy type, what kind of scenery, etc |
Xpos | 0x3 | 0x2 | X coordinate of Thing |
Ypos | 0x4 | 0x2 | Y coordinate of Thing |
DisId | 0x6 | 0x2 | Distinct ID? Used by switches, needs more research |
SwiSz | 0x8 | 0x2 | Switch Size - the size of the area in which the player must enter to trigger the switch |
SwiId | 0xA | 0x2 | The switch number that this item is triggered by. Also used as a modifier for other values, for example what kind of spell |
Paren | 0xC | 0x2 | Joins together linked items, like segments of path and walls. Also used by teleports to store the X value of the destination. Also used as a modifier to e.g. determine what kind of building to place |
Child | 0xE | 0x2 | Joins together linked items, like segments of path and walls. Also used by teleports to store the Y value of the destination |
Each entry contains the above variables. Each entry is numbered 1 - 1999, but this is implicit from their order and used for things like the Parent and Child values, it's not explicitly recorded in the entry.
Thing Types
These go in the "Class" field. They define the basic Type of a Thing
Value | Type | Notes |
---|---|---|
02 | Scenery | |
03 | Player Spawn | |
05 | Creatures | |
07 | Weather | |
0A | Effects | |
0B | Switches | |
0C | Spells |
Once a Thing type is set, the Thing Subtype (e.g. if a creature, what kind of creature it is) is then set in the "Model" field:
Scenery Thing SubTypes
Value | Thing Subtype | Notes |
---|---|---|
00 | Tree | There are two types of tree used in the game. It doesn't seem possible to choose which is used where, they are set pseudo-randomly (as they use a seed they will always be the same choice when the level is loaded) |
01 | Standing Stone | |
02 | Dolmen | |
03 | Bad Stone | The weird looking stone with the kind of witch creature statue carved into it |
04 | Blue Dome | A leftover from when the game used 2D billboard textures for buildings. Not used in any final game levels |
05 | Blue Dome | Duplicate of above |
Player Spawn Subtypes
These are wizard (player) start positions. If the wizard (other than the player) has a castle level set above zero, they will build their castle here on level start
Value | Thing Subtype | Notes |
---|---|---|
04 | Flyer1 | The player |
05 | Flyer2 | |
06 | Flyer3 | |
07 | Flyer4 | |
08 | Flyer5 | |
09 | Flyer6 | |
0A | Flyer7 | |
0B | Flyer8 |
Creature Thing Subtypes
Creatures with a SwiId value are spawned by triggering the switch with the corresponding SwiId value
Value | Thing Subtype | Notes |
---|---|---|
00 | Dragon | |
01 | Vulture | |
02 | Bee | |
03 | Worm | |
04 | Archer | |
05 | Crab | |
06 | Kraken | |
07 | Troll/Ape | It turns out there is a random chance for either of these enemies to appear using this Creature ID. |
08 | Griffin | |
09 | Skeleton | |
0A | Emu | |
0B | Genie | |
0C | Builder | |
0D | Townie | |
0E | Trader | |
10 | Wyvern |
Weather Thing Subtypes
The weather code seems to be totally removed from the game, and none of the values do anything.
Value | Thing Subtype | Notes |
---|---|---|
0 | Tornado | |
1 | Rain Cloud | |
2 | Thunder Cloud | |
3 | Thermals | |
4 | Wind | This remains in a few multiplayer levels but does nothing |
Effect Thing Subtypes
"Effects" range from all objects that are not creatures or scenery (buildings, Craters, walls, etc) to one-off effects like explosions and traps usually triggered by switches
Value | Thing Subtype | Notes |
---|---|---|
0 | Explosion | |
1 | Big explosion | |
2 | Dust | |
3 | Blood | |
4 | Spark | |
5 | Splash | |
6 | Fire | |
7 | Freeze | |
8 | Mini Volcano | |
9 | Volcano | |
0A | Mini crater | |
0B | Crater | |
0C | Possession | |
0D | White smoke | |
0E | Black smoke | |
0F | Earthquake | |
11 | Meteor | |
15 | Steal Mana | Trap |
17 | Lightning | |
18 | Rain of Fire | |
19 | Unknown | |
1C | Wall | Always have a DisID of 65535 and SwiId of 1. They work by having a minimum of two points (Things) defined in the level and linked via the Parent and Child values (based on their Thing number in the list) to draw the wall to fit between the points. |
1D | Path | Works exactly the same as Walls above |
1F | Canyon | Again, works exactly the same as Walls do |
22 | Teleport | Uses the Parent field to store the X coordinate of its destination, and the Child field for its destination's Y coordinate |
27 | Mana Ball | These start as a single small ball with a value of 512 mana. To get bigger values, more small balls are placed on the same point, and they will auto-merge into a larger size on level start. |
2D | Villager Building | The Parent field value determines building type. 1 = Tent, various other values determine other building types |
31 | Unknown | |
32 | Ridge Node | Again, works exactly the same as Walls do |
34 | Crab Egg |
Switch Thing Subtypes
Switches cause either Effects to trigger, or Creatures/spells to spawn. The SwiId (Switch ID) field is used to give each switch a unique ID, and also to assign Effects and Creature spawns to trigger by giving them the same ID. However, there is more at play, the DisId field is also used to trigger switches in sequence (so they will only trigger after the previously linked switch in that attribute has been fired). Switch areas are always circular, and the SwiSz (Switch Size) field determines the radius of this circle. Things that are to be triggered by a switch need the SwiId and DisId set to that of the switch. If both are not set, the object will start the level already spawned.
Value | Type | Notes |
---|---|---|
0 | Hidden Inside | A hidden switch activated once by the player moving inside its area |
1 | Hidden outside | A hidden switch activated once by the player moving outside its area |
2 | Hidden Inside re | A recurring/repeatable hidden switch activated by the player moving inside its area. |
3 | Hidden outside re | A recurring/repeatable hidden switch activated by the player moving outside its area. |
4 | On victory | This switch type triggers when the player completes the level (i.e. hit mana target). Levels 20 and 22 use this. |
5 | Death Inside | The "Death" switch types don't actually do anything special. They work exactly the same as regular hidden switches. The intention is that these are two be used when the outcome of the switch will be bad for the player (i.e. can make them dead!) so that it is obvious that is what the switch is for in the editor. An example of this is LEV00025 - lots of Death traps that trigger lethal meteor storms. |
6 | Death Outside | |
7 | Death inside re | |
8 | Death Outside re | |
9 | Obvious Inside | A visible switch that triggers by the player moving inside its area. Note, this and all obvious type switches shows a small X at its centre |
0A | Obvious outside | A visible switch that triggers by the player moving outside its area |
0B | Obvious Inside re | A repeatable visible switch that triggers by the player moving inside its area |
0C | Obvious outside re | A repeatable visible switch that triggers by the player moving outside its area |
0D | Dragon | These "creature" switches trigger once all creatures of their respective type on the map have been killed. |
0E | Vulture | |
0F | Bee | |
10 | Worm | |
11 | Archer | |
12 | Crab | |
13 | Kraken | |
14 | Troll | |
15 | Griffon | |
18 | Genie | |
1D | Wyvern | |
1E | Creature all | Triggers once all creatures of all types on the map have been killed |
1F | Exit Level | LEV000049 Uses this switch type, it marks the final level of the game |
Spell Thing SubTypes
Spell jars. Note that these MUST have the SwiId value populated to tell the game which type of spell it is, or the player cannot pick up the item. There seem to be two accepted values: 1 for normal spell jar (red) and 5 for the non-mana-limited (blue) variety. If a spell jar is spawned by a switch, the DisId field is used to mark which one it is, NOT the SwiId field (which still marks what kind of jar it is).
Value | Type | Notes |
---|---|---|
0 | Fireball | |
1 | Heal | |
2 | Speed Up | |
3 | Possession | |
4 | Shield | |
5 | Beyond Sight | |
6 | Earthquake | |
7 | Meteor | |
8 | Volcano | |
9 | Crater | |
0A | Teleport | |
0B | Duel | Called "Rubber band" internally |
0C | Invisible | |
0D | Steal Mana | |
0E | Rebound | |
0F | Lightning | |
10 | Castle | |
11 | Skeleton | |
12 | Thunderbolt | |
13 | Mana Magnet | |
14 | Fire Wall | |
15 | Reverse Speed | |
16 | Global Death | Called "Smart Bomb" internally |
17 | Rapid Fireball | Called "Mini Fireball" internally |
Wizard Stats Block
These are always in the same place in the file, starting at position 90D4. The first 12 bytes are actually the APR stats for the player... Which unless you're some kind of robot, don't have any effect.
Player Spells
Player spells are defined at 90E0. There are 24 bytes, each one simply a boolean value for a spell. There does seem to be some logic involved in which spells are unlocked, however (some seem to need e.g. castle unlocked first).
Spell | Offset (hex) | Length hex) | Notes |
---|---|---|---|
Fireball | 0x0 | 0x1 | All are booleans, 1 = character has this spell |
Shield | 0x1 | 0x1 | |
Accelerate | 0x2 | 0x1 | |
Possession | 0x3 | 0x1 | |
Health | 0x4 | 0x1 | |
Beyond Sight | 0x5 | 0x1 | |
Earthquake | 0x6 | 0x1 | |
Meteor | 0x7 | 0x1 | |
Volcano | 0x8 | 0x1 | |
Crater | 0x9 | 0x1 | |
Teleport | 0xA | 0x1 | |
Duel | 0xB | 0x1 | |
Invisible | 0xC | 0x1 | |
Steal Mana | 0xD | 0x1 | |
Rebound | 0xE | 0x1 | |
Lightning | 0xF | 0x1 | |
Castle | 0x10 | 0x1 | |
Undead Army | 0x11 | 0x1 | |
Lightning Storm | 0x12 | 0x1 | |
Mana Magnet | 0x13 | 0x1 | |
Wall of Fire | 0x14 | 0x1 | |
Reverse Acceleration | 0x15 | 0x1 | |
Global Death | 0x16 | 0x1 | |
Rapid Fireball | 0x17 | 0x1 |
Enemy Wizard Definitions
After the above, there is a block of 100 bytes of what is usually 01 for each wizard. These actually seem to be Boolean values for what appears to be which tactics this particular wizard will use in the level. Most of the time these are all enabled, but on some earlier levels some are set to 00, which seems to be how to dumb down the AI in how it fights the player. It's not known what each specific value does.
Five Bytes after this are the definitions for that wizard's Aggression, Perception, and Reflexes stats, as explained in the Official Strategy Guide. While they can range from 0 - 255 as explained in the guide, the baseline default for all is actually 128.
The fourth byte after the Reflex value is the start of the spell loadout for the wizard, which works exactly as per the player's spells, listed above.
Attribute | Offset (hex) | Length (hex) | Notes |
---|---|---|---|
Aggression | 0x0 | 0x1 | |
Blank | 0x1 | 0x4 | |
Perception | 0x5 | 0x1 | |
Blank | 0x6 | 0x4 | |
Reflexes | 0xA | 0x1 | |
Blank | 0xB | 0x4 | |
Spell Loadout | 0xE | 0x18 |
Some levels have wizards defined beyond the default stats even though they are not present in the level, suggesting they may have been cut (e.g. the first level has a very low level Vodor defined despite it not featuring any enemy wizards).
Misc Level Setup
This is always found after the wizard definitions at 9790. These define the target amount of mana for the player to collect on the level, the number of wizards in the level, and starting castle levels of each wizard (from 0 to 7).
Attribute | Offset (hex) | Length (hex) | Notes |
---|---|---|---|
Mana Target (%) | 0x0 | 0x1 | The percentage of the total mana defined in the first four bytes of the file needed to beat the level |
Blank | 0x1 | 0x1 | |
Number of Wizards in level | 0x2 | 0x1 | Only the player is 1. Therefore 2 would be the player and one enemy wizard (Vodor). Max is 8 |
Blank | 0x3 | 0x1 | |
Player Castle Level | 0x4 | 0x1 | Always set to 0 |
Vodor Castle Level | 0x5 | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Gryshnak Castle Level | 0x6 | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Mahmoud Castle Level | 0x7 | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Syed Castle Level | 0x8 | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Raschid Castle Level | 0x9 | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Alhabbal Castle Level | 0xA | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Scheherazade Castle Level | 0xB | 0x1 | Determines what level this wizard's castle starts at, and therefore their mana state |
Spell Loadouts
Keep in mind that the final game only respects spell loadouts on certain levels. Early on the game ignores what is set in the level to use the inventory the player has built up so far in the game. If a different level is played in one of these slots (most obviously level one), the player will start with no spells at all.