Ok I had questions, but I have tricks to share with the community too.
It is possible to edit the units abilities without a rebuild of the game, but it could need a sacrifice.
The following guide work with the version
1.03, and was not tested with another one. But if it cause the game crash, you must adapt what is saying in this post to your version.
You need an hexadecimal editor, and open the executable file of the game with it.
Then search the followings bytes : "0f bf c6 68 50 45 50 4f". (With my version, I find it at the offset 0xD43A1)
Go to this location, and you are now in the code of the engineer ability that magically repair buildings.
If you have not the source code, so you can only modify the original version of the game, and in this version, this ability don't work at all.
So you can sacrify this magic repairing to get free room.
In order to do this, you must find the first "66 83 fe 03" before your current position in the file (with my version, offset is 0xD4379), it is the starting of the useless engineer ability code.
Replace this "66 83 fe 03" with "eb 6f 90 90". (It make a jump of 0x6f bytes, it is the distance in bytes between here and the next "66 83 fe 03", which mark the next ability code. You should adapt this value to your situation if necessary).
Now if you save the file and execute the game, the Engineer have no special ability anymore.
Let's continue the hack.
By doing this, you won 111 free bytes to add code.
First, what ability do you want, and for which unit ?
For example, you want to add the elven boat and give it the ability of become invisible.
Let's search for the code of the invisibility. There are already two units that can cast this spell : The Ssrathi builder and the Dark guard.
So you must search for their unit ID in ascii, near from the current free bytes. They are "ALBX" and "AKGX". (I found them before the just-broken engineer code, at offset 0xD428B there is "AKGX" and at 0xD4292 there is "ALBX").
Be carful, some bytes after there is again theese two units ID, and if you want to do a replacing test, you must replace both locations in order to get a working ability.
For example, replace the both "AKGX" dword by an other ID, and an other unit will have the ability instead of the Dark Guard.
But this is not what you want, you want to teach the ability to a new unit without replace an existing configuration, thanks to the engineer you have a free space to write a new code chunk.
Now the job is a little harder.
You must make a map of two parts in the file : the free bytes from engineer and the code of invisibility.
You must write theese offsets somewhere on a paper or on your favorite text editor :
1. The "=AKGX" (or "3d 41 4b 47 58") offset from invisibility code : For me it's 0xD428A ;
2. The "=ALBX" (or "3d 41 4c 42 58") offset from invisibility code : For me it's 0xD4291 ;
3. The first "0f bf c6" that follows this "=ALBX" from invisibility code : For me it's 0x4298 ;
4. The first "c7 44 85" that follows this "0f bf c6" from invisibility code : For me it's 0xD42A2 ;
5. The "90 90" you wrote in the begining of the engineer code : For me it's 0xD437B.
Okay, now let's ASM hack !
The offsets you just wrote, I will call them N°1, N°2, N°3, N°4 and N°5.
Go to the N°1, and start to overwrite bytes with that :
"3d 41 4b 47 58" -> "e9 xx xx xx xx"
Where "xx xx xx xx" = (N°5) - (N°1) - 5
For example, I have (N°5) = 0xD437B and (N°1) = 0xD428A :
"xx xx xx xx"
= (N°5) - (N°1) - 5
= 0xD437B - 0xD428A - 5
= EC
It is little endian coded, that means when you have a number as "AA BB CC DD", you must write it "DD CC BB AA".
My EC value must be completed with zeros, it give "00 00 00 EC", but because it must be little endian, I will mark "EC 00 00 00"
So, the modification for me is :
"3d 41 4b 47 58" -> "e9 ec 00 00 00" (This operation transform the "if ID = AKGX" comparison to a jump toward the offset N°5)
Now, go to the offset N°5.
And start to overwrite this :
"90 90 0f 8d zz" -> "3d 41 4b 47 58" (This modification restaure the "if ID = AKGX" to extend the condition)
Where zz can be any value depending on your version.
Continue with :
"zz zz zz 3d 41 41" -> "0f 84 xx xx xx xx"
Where "xx xx xx xx" = (N°3) - (N°5) - 0xB
(For me, "xx xx xx xx" = "12 ff ff ff")
Continue with :
"42 58 75 zz 8b" -> "3d 41 53 57 4d" (It is the "elseif ID = ASWM" condition part, concerning the added Unit ID)
And :
"0d zz zz zz zz 8d" -> "0f 85 xx xx xx xx"
Where "xx xx xx xx" = (N°2) - (N°5) - 0x16
(For me, "xx xx xx xx" = "00 ff ff ff")
And the four last instructions :
"14 zz zz" -> "0f bf c6"
"zz zz" -> "6a 23" (Here, the 0x23 is the mana cost, you can change it if you want !)
"66 83 zz zz zz" -> "68 41 53 57 4d" (And here, the unit ID again. Do not change it without update the comparison located before)
And the final return to the invisibility code is :
"zz zz zz zz 75" -> "e9 xx xx xx xx"
Where "xx xx xx xx" = (N°4) - (N°5) - 0x25
(For me "xx xx xx xx" = "02 ff ff ff")
It's done !
Now if you made the modification correctly, you can play with a unit whose ID is "ASWM", this unit have the invisibility, and "AKGX" and "ALBX" kept their ability too.
By doing this, you used 37 bytes in the 111 free bytes brougth by the engineer, so you can apply this method three times, and more if you find an other place where you can insert code.
If you don't know ASM, you may want to undersand the code, you should look for a tutorial about ASM on the net, there is a lot of.
You can adapt this guide for any other ability and unit, but some cases are specific and require you to understand well what the code is doing.
Here is the final bypassed code in the guide (I used the "//" string to mark a comment) :
- Code:
-
// Invisibility function, modified to jump in the engineer zone
0xd428a : JMP LABEL_ENGINEER_BYPASS // Was the "AKGX" comparison, is now a jump to the engineer zone
0xd428f : JE UNIT_IS_DARK_GUARD // Old conditionnal jump, not used anymore
// Following code is non modified
[NOT_ELVEN_SHIP]
0xd4291 : CMP eAX, "ALBX" // If NOT Unit_ID = "ALBX"
0xd4296 : JNE NOT_SSRATHI_BUILDER // Then Quit InvisibilityCode
[UNIT_IS_DARK_GUARD]
0xd4298 : MOVSX AX, SI
0xd429b : PUSH 35 // Mana cost is set to 35
0xd429d : PUSH "AKGX" // Well, the Ssrathi is treated as a Dark Guard, because it needs a research !
[CALL_ABILITY_SUBROUTINE]
0xd42a2 : MOV [eAX*4 + eBP], 0x004cfbc0
...
[NOT_SSRATHI_BUILDER]
// Starting code of an other ability
0xd42fa : 0x66 0x83 0xfe 0x03
...
// Engineer free space modified to extending the code
0xd4379 : JMP ENGINEER_END // Make the code skip all the followings instructions
[LABEL_ENGINEER_BYPASS]
0xd437b : CMP eAX, "AKGX" // If Unit_ID = "AKGX"
0xd4380 : JE UNIT_IS_DARK_GUARD // Then Goto DarkGuard invisibility code
0xd4386 : CMP eAX, "ASWM" // If NOT Unit_ID = "ASWM"
0xd438b : JNE NOT_ELVEN_SHIP // Then Return to invisibility code, when testing if Unit_ID is "ALBX"
0xd4391 : MOVSX AX, SI
0xd4394 : PUSH 35 // Set mana cost to 35 for the boat
0xd4394 : PUSH "ASWM" // Set the ability button active for the boat
0xd439b : JMP CALL_ABILITY_SUBROUTINE // Jump to the rext of the invisibility code
...
[ENGINEER_END]
// Starting code of an other ability
0xd43ea : 0x66 0x83 0xfe 0x03
Erf, I'm typing this guide since some hours now, I hope it can be easily understandable and adaptable.
Enjoy it.