NKF, on 25 August 2015 - 07:02 AM, said:
Good catch. It's such a trivial error that no one would really notice it, but that is most certainly a bug. Must chronicle on wiki!
I've seen that you updated it indeed
. But I don't think your assumption is correct - of course, I don't know which source you are using
. I've derived it directly from the code of the game itself, after disassembling it in IDA 5.0. The two relevant sections in the .exe that place the two small wings:
For the small left wing: 80 3D 3B 63 01 00 FF 75 11 B8 01 00 00 00 E8 15 BE FE FF 04 11 A2 3B 63 01 00 (address range 43A58h - 43A71h)
For the small right wing: 80 3D 3E 63 01 00 FF 75 11 B8 01 00 00 00 E8 69 BD FE FF 04 13 A2 4A 63 01 00 (address range 43B04h - 43B1Dh)
Disecting it and disassembling the pieces:
For the small left wing:
80 3D 3B 63 01 00 FF = cmp byte ptr ds:1633Bh, 0FFh. It compares the byte located at address 1633Bh against the value 'FF'
75 11 = jnz short loc_510DA. In other words, if the value is unequal to 'FF', skip this section and jump to the address at loc_510DA; this means placement of a small wing section failed.
B8 01 00 00 00 = mov eax, 1. If the value was equal to 'FF', the placement will occur. First step is to set the value of the EAX register to 1. As I indicated in my Plane map construction post a bit above, this is the range the game uses for the next call, the random number generator.
E8 15 BE FE FF = call Randomizer. The name 'Randomizer' is one that I assigned to the subroutine being called. It will take the value from the previous instruction to generate a random number in the range from 0 to the number specified. In this case, the result will be either 0 or 1.
04 11 = al, 11h. The randomizer returned the result into the 'AL' register (part of the EAX register) and this instruction subsequently raises it by 11h. The value 11h is the offset for the small left wing section.
A2 3B 63 01 00 = mov ds:1633Bh, al. The resulting value in the 'AL' byte register is copied directly into the address at 1633Bh. This is the same address as was being checked against.
Note that both the validation check as well as the actual writing of the map block number happen based on a direct address, not on a dimension / position calculation.
For the small right wing, we have the dissection in a similar fashion:
80 3D 3E 63 01 00 FF = cmp byte ptr ds:1633Eh, 0FFh. See above, except the check address is 1633Eh instead.
75 11 = jnz short loc_51186. Same as above, except the effective jump location is different. The value '11' is relative to the location from where the jump is made.
B8 01 00 00 00 = mov eax, 1.
E8 69 BD FE FF = call Randomizer
04 13 = add al, 13h. The value 13h is the offset for the small right wing among the map blocks for this map type.
A2 4A 63 01 00 = mov ds:1634Ah, al. The map block number is written to address 1634Ah. This value differs from the one against which the check was made.
As I said above, the whole map generation has code that writes bytes to an address range ranging from 1632Ch to 16387h, 92 bytes in total. This is a memory range, not an address offset within the GeoScope.exe of course. When the game is run, the actual address range is shifted to 1F032Ch and higher, but the code explicitely refers to the previous range as you can see from the dissection.
The order of these bytes corresponds exactly to the byte order of the GeoData.dat file as detailed on the UfoPedia page
. Bytes 0Ch through 2Fh detail the map block numbers, according to that page. Adding the offset to the address of the start byte, the start address of the map block numbers is 16338h, ending at 1635Bh. For a 5x5 map, only the first 25 of those 36 bytes are used. Placing them in a diagram as if it's the minimap of the mission yields:
Row 0: 16338h 16339h 1633Ah 1633Bh
Row1: 1633Dh 1633Eh
1633Fh 16340h 16341h
Row2: 16342h 16343h 16344h 16345h 16346h
Row3: 16347h 16348h 16349h 1634Ah
Row4: 1634Ch 1634Dh 1634Eh 1634Fh 16350h
I've highlighted the three blocks relevant for the placement of the small wings. The one in the top row is for the small left wing. The one in the first row is the position being checked against for the small right wing, while the one in the third row is where the wing is actually getting placed.
With some nudging on my side (slight modification to the GeoData.dat file before it was being passed to the Tactical.exe file), I've managed to force a reproduction of the bugs' result. The image can be seen below:
The wing tiles where the X-Com craft is being placed, are simply replaced by those of the X-Com craft in question. The other tiles are left untouched. As you can see, the bug is mostly cosmetical, it just looks weird.
For the record, what you stated with your relative location calculations is indeed used for the plane's middle sections, as well as the cockpit. It's just not being used for the small wings: those use direct address pointers.