Airfix DogFighter Programmer's Manual


<< Page 2  Tutorial   Page 4 >>

3.1.1: Coordinates.

I think it would be wise at this point to give some explanation about coordinates. For both objects you will see definitions for two sets of coordinates, three in each set. Why? The first set defines the 3D location of the object in the house along the X-, Z- and Y- axes (in that order!) In other words, the first value defines the position East/West, the second gives the Height and the third gives the North/South coordinate. These will be more fully explained in a later chapter.

The second set might look a bit more mysterious, especially since only the middle value is non-zero. They stand for PYB, or Pitch / Yaw / Bank. Think of an aircraft: Pitch means nose up or down, Yaw is Rotate and Bank is Tilt Left/Right. Think of our PSP (the Yellow Arrow in the Dining Room). In the preceding screenprint it is lying flat underneath the Dining Room Table. If the Pitch would have a positive value instead of zero, the “nose” would tilt more or less upward, depending on the value. Likewise, if the Bank-value would be unequal to zero, one of the tips would be at a higher position than the other. Finally, the middle one (Yaw) is more commonly known (and will make more sense) as Rotation. In the coordinate-definitions of both objects they are the only ones unequal to zero, because they define the position on the compass the object has. If you have already played with the House Editor, you know that you can spin each object round to point in any direction. In doing so you will define the middle value of the second set of coordinates.
ÿr> More about that later, let’s first finish the rest of the block…

As we shall see later, this list is standard for any unit that you place in your level.

Except one…

You might remember that we saw three variable declarations in the .afs-file. We have seen that model0 is the tank and model1 is the Fw190, but what about model2? You might remember we also dropped a PSP, or Player Start Position, under the dining room table. We find this back in the .afs-file as the definition of the Start Position. It doesn’t mention model2, but it has inherited all its coordinates. Remember I told you try not to rotate it when placing it in the room? Depending on how accurate you were in that, the value for the Rotation (middle one of the second set of 3d-coordinates) will not be far off from 0.000000…


3.2: the .level-file

As mentioned earlier, the .level-file is the one that is constructed while we are assembling our map in the House Editor. We were able to open the .afs-file with Windows Notepad, as it is a plain-text scriptfile. No such luck with the level-file, as it contains binary data. If you try to read it in Notepad anyway (go on, you know you want to…) it will make absolutely no sense, and saving the file after opening it in Notepad will completely ruin it! So you have been warned….

The only way to do it properly is by opening the levelfile with a Hex-editor:

Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000    46 48 4F 55 8A 03 00 00 48 4F 55 53 21 00 00 00    FHOUŠ...HOUS!...
00000010    47 61 6D 65 5C 57 6F 72 6C 64 73 5C 44 6F 67 66    Game\Worlds\Dogf
00000020    69 67 68 74 73 5C 64 66 5F 31 2E 77 6F 72 6C 64    ights\df_1.world
00000030    00 47 43 43 53 04 00 00 00 CD D2 CF 00 4D 4F 44    .GCCS....ÍÒÏ.MOD
00000040    4C 60 00 00 00 F8 9B 5D 42 12 B4 9D 3D 98 26 6F    L`...ø›]B.´.=˜&o
00000050    40 00 00 00 00 8F C2 F5 3C 00 00 00 80 64 69 6E    @.....Âõ<...€din
00000060    69 6E 67 5F 72 6F 6F 6D 00 47 61 6D 65 5C 4F 62    ing_room.Game\Ob
00000070    6A 65 63 74 73 5C 55 6E 69 74 73 5C 48 65 59 65    jects\Units\HeYe
00000080    6C 6C 6F 77 2E 6F 62 6A 65 63 74 00 6D 6F 64 65    llow.object.mode
00000090    6C 32 00 00 00 00 00 00 01 00 00 00 00 01 00 00    l2..............
000000A0    00 32 00 00 00 4D 4F 44 4C 63 00 00 00 0B 39 17    .2...MODLc....9.
000000B0    42 49 2E 7F 40 86 BB 43 40 00 00 00 00 0C 5F 01    BI..@†»C@....._.
000000C0    BD 00 00 00 80 64 69 6E 69 6E 67 5F 72 6F 6F 6D    ½...€dining_room
000000D0    00 47 61 6D 65 5C 4F 62 6A 65 63 74 73 5C 41 69    .Game\Objects\Ai
000000E0    72 63 72 61 66 74 73 5C 41 63 46 77 31 39 30 2E    rcrafts\AcFw190.
000000F0    6F 62 6A 65 63 74 00 6D 6F 64 65 6C 31 00 00 00    object.model1...
00000100    00 00 00 01 00 00 00 00 01 00 00 00 32 00 00 00    ............2...
00000110    4D 4F 44 4C 63 00 00 00 8A 2D 58 42 0D 2D 50 40    MODLc...Š-XB.-P@
00000120    CD F9 5E 40 00 00 00 00 D8 0F C9 3F 00 00 00 80    Íù^@....Ø.É?...€
00000130    64 69 6E 69 6E 67 5F 72 6F 6F 6D 00 47 61 6D 65    dining_room.Game
00000140    5C 4F 62 6A 65 63 74 73 5C 55 6E 69 74 73 5C 47    \Objects\Units\G
00000150    75 43 68 75 72 63 68 69 6C 6C 2E 6F 62 6A 65 63    uChurchill.objec
00000160    74 00 6D 6F 64 65 6C 30 00 00 00 00 00 00 01 00    t.model0........
00000170    00 00 00 01 00 00 00 32 00 00 00 4F 42 4A 45 50    .......2...OBJEP
00000180    00 00 00 B8 85 37 42 A1 74 BD 40 D0 49 56 41 00    ...¸…7B¡t½@ÐIVA.
00000190    00 00 00 00 00 00 00 00 00 00 80 64 69 6E 69 6E    ..........€dinin
000001A0    67 5F 72 6F 6F 6D 00 47 61 6D 65 5C 4F 62 6A 65    g_room.Game\Obje
000001B0    63 74 73 5C 53 74 61 74 69 63 5C 70 61 69 6E 74    cts\Static\paint
000001C0    69 6E 67 5F 66 6F 78 68 75 6E 74 2E 6F 62 6A 65    ing_foxhunt.obje
000001D0    63 74 00 4F 42 4A 45 50 00 00 00 D2 F8 5D 42 66    ct.OBJEP...Òø]Bf
000001E0    89 C3 3F 9C 66 5A 40 00 00 00 00 07 00 00 30 00    ‰Ã?œfZ@.......0.
000001F0    00 00 80 64 69 6E 69 6E 67 5F 72 6F 6F 6D 00 47    ..€dining_room.G
00000200    61 6D 65 5C 4F 62 6A 65 63 74 73 5C 53 74 61 74    ame\Objects\Stat
00000210    69 63 5C 74 61 62 6C 65 5F 64 69 6E 69 6E 67 72    ic\table_diningr
00000220    6F 6F 6D 2E 6F 62 6A 65 63 74 00 4F 42 4A 45 4D    oom.object.OBJEM
00000230    00 00 00 E2 5F 5F 42 60 E5 78 40 34 22 5E 40 00    ...â__B`åx@4"^@.
00000240    00 00 00 92 99 C9 BF 00 00 00 80 64 69 6E 69 6E    ...’™É¿...€dinin
00000250    67 5F 72 6F 6F 6D 00 47 61 6D 65 5C 4F 62 6A 65    g_room.Game\Obje
00000260    63 74 73 5C 44 79 6E 61 6D 69 63 5C 49 61 46 6C    cts\Dynamic\IaFl
00000270    6F 77 65 72 56 61 73 65 2E 6F 62 6A 65 63 74 00    owerVase.object.
00000280    49 41 4F 42 21 00 00 00 49 61 4C 69 67 68 74 73    IAOB!...IaLights
00000290    77 69 74 63 68 00 73 77 69 74 63 68 5F 6B 69 74    witch.switch_kit
000002A0    63 68 65 6E 00 01 00 00 00 49 41 4F 42 42 00 00    chen.....IAOBB..
000002B0    00 49 61 44 6F 6F 72 00 64 6F 6F 72 5F 64 69 6E    .IaDoor.door_din
000002C0    69 6E 67 72 6F 6F 6D 5F 6C 69 76 69 6E 67 72 6F    ingroom_livingro
000002D0    6F 6D 00 01 00 00 00 00 00 00 00 00 00 00 00 00    om..............
000002E0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
000002F0    00 00 00 49 41 4F 42 3F 00 00 00 49 61 44 6F 6F    ...IAOB?...IaDoo
00000300    72 00 64 6F 6F 72 5F 6B 69 74 63 68 65 6E 5F 64    r.door_kitchen_d
00000310    69 6E 69 6E 67 72 6F 6F 6D 00 00 00 00 00 00 00    iningroom.......
00000320    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
00000330    00 00 00 00 00 00 00 00 00 00 49 41 4F 42 24 00    ..........IAOB$.
00000340    00 00 49 61 4C 69 67 68 74 73 77 69 74 63 68 00    ..IaLightswitch.
00000350    73 77 69 74 63 68 5F 64 69 6E 69 6E 67 72 6F 6F    switch_diningroo
00000360    6D 00 01 00 00 00 49 41 4F 42 24 00 00 00 49 61    m.....IAOB$...Ia
00000370    4C 69 67 68 74 73 77 69 74 63 68 00 73 77 69 74    Lightswitch.swit
00000380    63 68 5F 6C 69 76 69 6E 67 72 6F 6F 6D 00 01 00    ch_livingroom...
00000390    00 00 00-XX-XX-XX-XX-XX-XX-XX-XX-XX-XX             ..



For those who are not familiar with Hex-editors: In the middle you see 16 columns of pairs of characters. Each pair is the (hexadecimal) value of a byte. As Hexadecimal means based on 16, it is small wonder that there are 16 columns. The column on the left, with 8 positions, is the RowCounter. You will notice that each next row is incremented by 10 but this is hexadecimal 10, meaning 16 in decimal terms!
If you look closer you will see that the 10th row has the value 0000A0…

On the right the ASCII-characters of the values of the bytes are displayed. A dot means that this position contains a non-printable ASCII-character, which does not necessarily mean zero!!!!!

If you have a closer look at the right-hand field, you will spot that the file is made up of a number of blocks, each starting with a 4-character string in Capitals. These are the Block-headers. Present in this .level-file are the following: FHOU, HOUS, GCCS, MODL, OBJE and IAOB. In any .level-file you will only find FHOU, HOUS and GCCS once, and always as the first, second and third Block. The others will usually appear a number of times, depending on how many Objects and Models you stuff into the level you are building…


3.2.1: General Structure of .level-files.

This pretty much is the standard structure of a .level file:


3.2.2: the HOUS-block.

We will leave the FHOU- and CCS blocks for what they are at the moment, and first have a look at the HOUS-block. You will remember that the first thing we did in building our level was selecting the environment: the Livingroom, Diningroom, Kitchen. If you look at the first three lines you will see that the following string is present: HOUS!...Game\Worlds\Dogfights\df_1.world. As mentioned earlier, the four positions after HOUS represent the length of this block in Hexadecimal. If we substitute the values in the string then we get:

HOUS 21 00 00 00 Game\Worlds\Dogfights\df_1.world 00,

in which the hexadecimal values are printed in bold. If we count the positions in this block, we find a total of 41. So what’s the difference? Well, the length-descriptor gives the length of the string After the descriptor, which means only the underlined, blue-coloured part of the string. Don’t forget that the bold pairs count for only one position each. That would still make it a total of 33, so what’s the difference? When we count the length of the string we automatically do that in decimal values. The four positions between HOUS and the underlined string are Hexadecimal however, and hex(21) is equivalent to 2x16 + 1x1 = 32 + 1 = 33!!!

But why is 21 the first hex value, followed by three times 00?

3.2.3: Reverse Hex Notation (RHN).

This seems to be a standard format in ADF-files, not only in .level-files but in others as well.
The way it is programmed is that the 4 positions are in reverse order. It is a bit like writing 2500 as 0052…
We would expect the Most Significant Bit on the left-hand side and the Least Significant Bit on the right, but in the ADF-files it is just the other way around. In the rest of this document, I will refer to this as RHN.


3.2.3: the MODL-block.

Let’s have a look at the third MODL-block and substitute the nonsense-chars for their Hex-equivalents straight away: (Hex in bold)

MODL 63 00 00 00
8A 2D 58 42   0D 2D 50 40   CD F9 5E 40
00 00 00 00   D8 0F C9 3F   00 00 00 80

dining_room 00
Game\Objects\Units\GuChurchill.object 00
model0 00
00 00 00 00
00
01 00
00 00
00
01 00 00 00
32 00 00 00

Why have I, seemingly at random, grouped the data this way? Let’s take it line for line…


MODL 63 00 00 00 Just like in the HOUS-block, the MODL-block starts with the 4-character Block-header (MODL) followed by the block length descriptor in RHN. This means that the rest of the block is hex(63) characters long, which in decimal is 6x16 + 3x1 = 99 positions.
8A 2D 58 42   0D 2D 50 40   CD F9 5E 40
00 00 00 00   D8 0F C9 3F   00 00 00 80
The next two lines contain 3 groups of 4 positions each. The first of these two contains the values for the X-, Z- and Y coordinates that we saw earlier in the .asf-file, the only difference being that here they are given in hexadecimal values (and yes, in RHN).
The second of these two lines, of course, contains the values for Pitch, Rotation and Bank that we discussed earlier with the .asf-file, also in RHN.
Notice that the value for bank isn’t 00 00 00 00 , but 00 00 00 80 ! This seems to be a standard default value for any object you drop into the level under construction...
Notice also, that the Hexadecimal values in the level-file bear absolutely NO resemblance to the Decimal ones as mentioned in the .asf-file....


Game\Objects\Units\GuChurchill.object 00 Next up is the string that refers to the definition file for the actual model, in this case the (Ground Unit-) Churchill tank. Like the string that refers to the .world-file, this string is closed by a 00 End Byte.
model0 00
Next line gives the Object Label, the name that the Model will be referred by in the House Editor and in the .asf-file. The House Editor will give them names automatically, starting with model0 and incrementing by 1 each time you add a model to the map.
00 00 00 00 These positions set the value for the Team the model belongs to. As you see, the default value that the House Editor enters is 0. Why it needs four hex positions I don't know.
00 This Byte is a bit of an odd one, as on this line the Squad is set, but in a rather different way.
This will be explained more fully a bit later on, suffice for now to say that this single byte is an End Byte, just like the one after the Descriptor String for the .world-file and the Churchill tank reference file name.
ÿtd?
01 00 These two bytes set the AIActivate value for the model. See the .afs-file earlier in this chapter.
00 00 Haven't been able to figure out what these bytes do?
00 This is another End Byte, this time for the SetPickUpType (see below)
01 00 00 00 This is the setting for the AISetStayRoom-parameter, in RHN
32 00 00 00 This is the setting for the AISetAggression parameter, also in RHN.
By the way, Hexadecimal 32 = 50 in Decimal…


A word about the SetPickupType-parameter.

Anyone who has ever flown a Mission in ADF (and I assume that's everyone who reads this Document!) knows that when you destroy a breakable or a model, a Pickup appears. Most of the time these are completely random, but a Breakable or a Model can be set a specific Pickup-item. If you want to see the names of the range available, have a look in the Game\Objects\Units-folder. All names of Pickups start with pu, e.g. puBomb is the name of the Pickup Bomb Pack. So how do we set the Fw190 to cough up a Repair Kit when it dies? The name we are looking for is puRepairs.

In the Hex-Editor, we simply insert the string "puRepairs" in front of the SetPickupType End Byte, as will be shown after a discussion about the SetSquad-Parameter.


A word about the SetSquad-parameter.

In the Blocks described so far, most numerical settings are done in Hexadecimal values.
Not so the SetSquad-parameter. In the MODL-block above there is only the 00 of the End Byte.

First, what does the SetSquad-parameter do?
As we have seen in the discussion about the .asf-file, there are three possible sides: Neutral (0), Allied (1) or Axis (3). A Squad is just a subset of one of these forces that comes in handy as a single unit for programming purposes. Anyone who has played the Allied level "Attic Raid" (level 4) knows that when you kill off all three German bombers that fly into the attic you will get the message "Bombers are eliminated". That is because they are programmed to belong to the same Squad, and when all three are killed, no matter in what order, the Squad ceases to exist. So, in our simple Sample1 the Squad-property is not very important, but it will become later on so we will set it to, let's say, 21.

As mentioned, the way the setting is done is a bit different from the other settings. Just like the SetPickupType value, the Squad-value is entered as a string, but with a numerical value. What that means is that you either insert the string "21" in the right-hand side of the Hex-Editor (as ASCII-characters) or in the middle as the Hexadecimal values 32 31 (= ASCII-char "2" followed by ASCII "1"). And while we're at it, why not change the Object Label for the Focke-Wulf from "model1" to "Fw_190"? This won't cause much trouble, as it has the same string-length....



<< Page 2  Tutorial   Page 4 >>