Jump to content

EXE editing & programming issues


MrFlibble

Recommended Posts

And as for "repair hold".... I wonder if this can't be achieved by some sort of scripting in an EMC file or something (if I'm not mistaken that's how the "always return to repaired units to previous position on the map" and the "turret increased range" thingies were solved).

BUILD.EMC has nothing to do with the sidebar command interface, and cannot be edited so that a button will be added to the Repair Facility that will allow to pause unit repair process. The sidebar commands are partially controlled via the regular parameters accessible via Nyerguds' editor, others seem to be hardcoded elsewhere.

Link to comment
Share on other sites

  • 1 month later...

Probably a bit mask. Something that checks if the house is Harkonnen and the building ID the WOR, then takes the existing prerequisites bit mask it should check, and then does "AND [value], FBFFh" on it, to remove the Barracks bit from it.

(FBFFh = 1111 1011 | 1111 1111, so it allows all bits to go through except for the 0400h bit)

[edit]

Found it ;D

It was even already documented in Segra's database:


seg010:1C28 01E                 cmp     si, 7                               ; if WOR Factory
seg010:1C2B 01E                 jnz     short notWOR                        ; Jump if Not Zero (ZF=0)
seg010:1C2D 01E                 les     bx, [bp+buildingGamePtr]            ; Load Full Pointer to ES:xx
seg010:1C30
seg010:1C30     loc_1C060:                                                  ; if harkonnen
seg010:1C30 01E                 cmp     es:[bx+_buildingGame.houseID], 0
seg010:1C35
seg010:1C35     loc_1C065:                                                  ; Jump if Not Zero (ZF=0)
seg010:1C35 01E                 jnz     short notWOR
seg010:1C37 01E                 cmp     missionNumberPrevious, 1            ; if missionnumberprevious >= 1
seg010:1C3C 01E                 jl      short notWOR                        ; Jump if Less (SF!=OF)
seg010:1C3E
seg010:1C3E     loc_1C06E:                                                  ; Logical AND
seg010:1C3E 01E                 and     [bp+buildingPreReq1], 0FBFFh
seg010:1C43
seg010:1C43     loc_1C073:                                                  ; Logical AND
seg010:1C43 01E                 and     [bp+buildingPreReq2], 0FFFFh
seg010:1C47 01E                 mov     di, 2
seg010:1C4A
seg010:1C4A     notWOR:

Prerequisites are 4 bytes, but it's split up in 2 because 16-bit programs can't handle 4-byte values.

The last command here, AND [value], FFFFh is totally useless, btw. Just the result of that "splitting up a long value" :P

btw, the exception can be disabled simply by changing the checked house ID to something above 6 ;)

In a hex editor, you can search for "81 66 E8 FF FB" (the actual disabling command), and then go back about 10 bytes until you find "26 80 7F 08 00", the house check. That 00 at the end is the house it executes this exception for.

The disabling command seems to be a unique sequence in all versions, including even the demo, so it's easy to find.

Link to comment
Share on other sites

Cool, thanks :) BTW, is the exception code nything like the one in C&C?

btw, the exception can be disabled simply by changing the checked house ID to something above 6 ;)

In a hex editor, you can search for "81 66 E8 FF FB" (the actual disabling command), and then go back about 10 bytes until you find "26 80 7F 08 00", the house check. That 00 at the end is the house it executes this exception for.

Oh, I actually was more interetsted in expanding it to other sides (maybe something like "Check if House is NOT X" will work?), or at least switching it to different side :)

Link to comment
Share on other sites

Cool, thanks :) BTW, is the exception code anything like the one in C&C?

Wasn't the fact I knew pretty much exactly how it would look enough indication of that? ;)

C&C has almost exactly the same code in reverse, to make the Nod buildings be equivalent as prerequisites to their GDI counterparts. This is done so the GDI buildings set as prerequisites serve as general indication of a vehicle factory, an infantry factory, a superweapon, a heavy defense structure (obelisk/AGT), so that if you want something to have "the superweapon building" as prerequisite, you just give it GDI's adv comm center, and it'll work with the Nod Temple too.

The prerequisites system works by first making a bit mask with 1's for the buildings you have, to compare with the prerequisites bit mask of the construction option you're trying to give to the player.

The equivalence code works by checking for the Nod counterparts of the aforementioned buildings, and every time it sees you got one of the Nod equivalents, it adds the GDI bit to it, meaning it pretends you got both. That way, a general "does the player have a Barracks building?" check can work :)

This is not done the other way around though. If you specify that something needs the Hand of Nod to be built, it will not work if you got the GDI Barracks.

Oh, I actually was more interested in expanding it to other sides (maybe something like "Check if House is NOT X" will work?), or at least switching it to different side :)

well, the problem with expanding it is that you usually needs more space in the exe to actually put in something useful. In this case, you can free up some space with the useless "AND [value], FFFF" command, but that's still not enough for some decent coding.

Enabling the exception if the house is NOT Harkonnen is rather simple, it's just adapting the condition of the jump it does after the check.

Right now it says "jnz" ("Jump if Not Equal", byte 75h) right behind the house check. Change that to "Jump if Equal" ("jz", byte 74h) and the exception is enabled for all houses except for the Harkonnen (or whatever house you'd change the check to). For 3 playable houses, this means you can perfectly enable it for 1 (normal), 2 (inverted), 3 (remove the house check and jump by replacing it with 90h bytes) or 0 (force the jump past it by changing it to EBh, a normal "jmp") houses, meaning this one is fully customizable.

Link to comment
Share on other sites

(..)

In this case, you can free up some space with the useless "AND [value], FFFF" command, but that's still not enough for some decent coding.

(..)

You can change the useless AND into a forward jump to some unused block (as long as this piece of code is not in an overlay). Then you have much more room :) There are a nice amount of places the code can never come, so in theory you have room to extend ;)

Link to comment
Share on other sites

Well there are no unused blocks, I don't know how to make new ones in the exe, and the 16-bit code doesn't allow far jumps. And I have no idea how a jump to a different section even work. It just isn't used in 32-bit code.

Also, I've found that you need to be VERY careful with removing "unreachable" code or "unused" functions... sometimes it uses pretty dirty tricks to use them after all, or you're just missing some reference information in the database.

I'm sticking to C&C95 :P

Link to comment
Share on other sites

Wasn't the fact I knew pretty much exactly how it would look enough indication of that? ;)

I'd say it was rather an indication of your expert knowledge in this field ;) Thanks for the info :)

BTW, I wonder if a general comparison of the code of Dune II and Command & Conquer would be of any historical interest, revealing how the game engine evolved...

Link to comment
Share on other sites

Well there are no unused blocks, I don't know how to make new ones in the exe, and the 16-bit code doesn't allow far jumps. And I have no idea how a jump to a different section even work. It just isn't used in 32-bit code.

Also, I've found that you need to be VERY careful with removing "unreachable" code or "unused" functions... sometimes it uses pretty dirty tricks to use them after all, or you're just missing some reference information in the database.

I'm sticking to C&C95 :P

I have found a few blocks (via OpenDUNE C-ifications) which are impossible to ever be called .. stuff like: if (emu_ax < 0) { } (unsigned compare). It just never happens :) Even with all its dirty tricks, it is never called :)

But okay .. using OpenDUNE is easier anyway, as it allows all and any modifications ;)

Link to comment
Share on other sites

BTW, I wonder if a general comparison of the code of Dune II and Command & Conquer would be of any historical interest, revealing how the game engine evolved...

Well the prerequisites system is still the same, that I can tell at least ;D

Link to comment
Share on other sites

I have found a few blocks (via OpenDUNE C-ifications) which are impossible to ever be called .. stuff like: if (emu_ax < 0) { } (unsigned compare). It just never happens :) Even with all its dirty tricks, it is never called :)

Does this mean that extra code can be added instead of those and it will work? :) There's also some extra space freed by Segra's "vanishing Houses bug" fix.

Link to comment
Share on other sites

Well in a 32-bit program that would help... you can just jump from one tiny open spot to the next. In that case you'd be able to use 22 of these 27 bytes for actual code. (2 gone by making that actual code jump over the free part, 5 for the jump away after executing the added code). But as I said, I have no idea how long jumps work in 16-bit. As far as I can see, they kinda don't. You somehow have to set which section it should jump to, and then do a jump in there or something.

Link to comment
Share on other sites

Well in a 32-bit program that would help... you can just jump from one tiny open spot to the next. In that case you'd be able to use 22 of these 27 bytes for actual code. (2 gone by making that actual code jump over the free part, 5 for the jump away after executing the added code). But as I said, I have no idea how long jumps work in 16-bit. As far as I can see, they kinda don't. You somehow have to set which section it should jump to, and then do a jump in there or something.

16bit far jumps work the same as 32bit far jumps. You just have to make sure to repair the 'cs' value afterwards (but that is also true for 32bit). So using a far call is most likely easier, as then you can just do a return, which restores everything. You can only not jump to or from code in higher overlays, as they are dynamicly swapped in and out. The rest is staticly loaded, and can be used freely. Via OpenDUNE it should be easy to locate which are what. All files starting with cs__B are dynamic, all others static.

Another random thought, if you really want to extend Dune2 itself: remove the sound, and load a patched file via the sound driver. Sound drivers are loaded in 0xAB000, so that is a set address. Just a random thought :)

Link to comment
Share on other sites

yeah, I totally didn't get any of that. In 32 bit, all I do it "jmp wherever_I_want" and it does it. Not a clue what that cs value is you're talking about. I know very little about the whole theory behind assembler... I just know how to adapt it correctly, in 32 bit. And I haven't seen any cs in that.

Do you mean you can use a 2-byte value as far jump parameter in 16-bit? The tool I use to convert asm code to bytecode only does 32-bit far jumps... would be annoying :P

Link to comment
Share on other sites

yeah, I totally didn't get any of that. In 32 bit, all I do it "jmp wherever_I_want" and it does it. Not a clue what that cs value is you're talking about. I know very little about the whole theory behind assembler... I just know how to adapt it correctly, in 32 bit. And I haven't seen any cs in that.

Do you mean you can use a 2-byte value as far jump parameter in 16-bit? The tool I use to convert asm code to bytecode only does 32-bit far jumps... would be annoying :P

Of course you need a 4 byte value .. 16bit machines have 20bit memory available ;) I suggest you read up on that a bit .. 'cs' = Code Segement. For that too, Google or something is your friend :)

Maybe some day when I am bored, I will write a small proof-of-concept on the sound driver idea.

Link to comment
Share on other sites

well as far as I know, code segments don't matter at all in 32 bit. I can jump between them or link to them without any problems. They're all part of one long addressing range.

And I said "2-byte value as far jump parameter", not as jump command. I know the full command can be longer than 2 bits.

Link to comment
Share on other sites

(..)

And I said "2-byte value as far jump parameter", not as jump command. I know the full command can be longer than 2 bits.

The memory address space on a 16bit machine is 20bits. You can't address this with 2 bytes. And as there is a far jump command, it has to be at least 3 bytes (but it is 4 bytes). This is called a CS:IP pair, CodeSegement + InstructionPointer. You should really look this up (using a search engine or what ever), as it is too much to explain here.

Mind you, I talk about the parameter here too. The command is of no relevance to this talk.

Link to comment
Share on other sites

Hm, I've noticed there are five code segnments in DUNE2.EXE that refer to the WOR: the first one, according to Segra, enables unit production within the structure, the second is the modifier for the Harkonnen WOR tech level and prerequisites that Nyerguds posted, the third is responsible for changin the WOR upgrade level from 6 to 4 for the Harkonnens, and there are two more, the purpose of which I currently do not know.

Link to comment
Share on other sites

  • 2 weeks later...
  • 4 weeks later...

I've found some more interesting functions in Dune II (EU version):

Here's the one that decides what color the score screen progress bars should be:

A1 38 3A        ; get House ID
0B C0          ; if Harkonnen
74 0C          ; red score bar
3D 01 00        ; if Atreides
74 13          ; blue score bar
3D 02 00        ; OR
74 1A          ; green score bar
EB 0C          ; else, use the Atreides blue bar
; Harkonnen red score bar
C7 46 FC 95 00  ; palette index for the darkest coulour in the remap scheme
C7 46 FA 00 00  ; some reference to a function that creates the "glowing" effect
EB 18
; Atreides blue score bar
C7 46 FC A5 00
C7 46 FA 02 00
EB 0C
; Ordos green score bar
C7 46 FC B5 00
C7 46 FA 01 00
EB 00

I could not identify the function that creates the glowing effect, but if the "base colour" referred to by the palette index (prior to calling that function) is changed, the colour of the score bar changes as a result of mixing the colours (e.g. I got a dark green colour by mixing the Sardaukar purple with something else). If the glowing effect index is changed to something else (e.g. C7 46 FA 03 00), the score bar no longer "glows", but retains the colour specified by the palette index above.

The colour of the "enemy" score bar (which is always purple) is handled somewhere else, and I have been unable to find it yet.

And here's the chunk that chooses House heralds for the map selection screen:

A1 38 3A        ; get House ID 
0B C0          ; if Harkonnen
74 0C          ; use Harkonnen herald
3D 01 00        ; if Atreides
74 10          ; use Atreides herald
3D 02 00        ; if Ordos
74 10          ; use Ordos herald
EB 09          ; else, use the Atreides herald

I've been unable to find the code that picks the heralds for the production screen as yet. It is probably more tricky, since the unplayable sides do not use any herald at all, but instead the space where the heralds should be is filled with a "copy-pasted" upper part of the top herald image.

I also identified the code for the glowing selection boxes for the production screen:

A1 38 3A        ; get House ID  
0B C0          ; if Harkonnen
74 0C          ; red selection box
3D 01 00        ; if Atreides
74 2F          ; blue selection box
3D 02 00        ; if Ordos
74 1C          ; green selection box
EB 2A          ; else, white selection box

The function itself that draws the selection boxes is pretty complicated, and I've been unable to figure out how to change the colours.

Link to comment
Share on other sites

I could not identify the function that creates the glowing effect, but if the "base colour" referred to by the palette index (prior to calling that function) is changed, the colour of the score bar changes as a result of mixing the colours (e.g. I got a dark green colour by mixing the Sardaukar purple with something else). If the glowing effect index is changed to something else (e.g. C7 46 FA 03 00), the score bar no longer "glows", but retains the colour specified by the palette index above.

Just checking: you are aware this is an old game, running in palettized 320x200 mode? The "glow" color may just be using one single color index, with some timer rotating the R, G, or B (or a combination) values of that index up and down. Perhaps it works like this: the RGB color of the index you found is copied to a buffer, and that gets read to draw a rectangle in the 'glow' color index (rather than directly in the color index of the lookup), and after that it's just that one index that gets updated.

If you are able to make color indexed screenshots of various score screens, you might find that the differently coloured bars are, in fact, using the same index. It's what I would do, leaving the other 255 colors (a preciously low number) unchanged, to draw the rest of the screen with.

Link to comment
Share on other sites

The "glow" color may just be using one single color index, with some timer rotating the R, G, or B (or a combination) values of that index up and down.

That's what I suspect is the case, but the thing is that changing the actual palette index alone does not help, since there apparently are different hardcoded patterns that facilitate the playable Houses' score bars "glowing", and cannot be used with different colours.

Link to comment
Share on other sites

I wouldn't be surprised if the game has a "find nearest colour" function which takes an RGB value and then looks through the entire palette to find the nearest match to it. I mean, C&C has only 256 colours too, and it does stuff like on-the-fly object resizes (with transparency, even) for the minimap.

Link to comment
Share on other sites

  • 4 months later...

As you know, the Fremen in the Sega version, unlike the PC version, have special icons different from regular troopers (also found among the PC version files), more hit points and weapon damage. However, as it turns out, Fremen troopers in the Sega version are not separate units, but modified Trooper(s) units. Ti_ from the Russian team focused on research and modding of Sega Mega Drive Dune: The Battle for Arrakis port has posted the relevant code related to the palace-summoned Fremen.

ROM:00022EA2                 lea     (fremens_quanit).l,a1
ROM:00022EA8                move.b  (a1,d3.w),d6
ROM:00022EAC                ext.w  d6
ROM:00022EAE                moveq  #0,d5
ROM:00022EB0                lea    (fremens_utype).l,a4
ROM:00022EB6                bra.w  loc_22FFC
ROM:00022EBA ; ---------------------------------------------------------------------------
ROM:00022EBA
ROM:00022EBA loc_22EBA:                              ; CODE XREF: SUPERWEAPON+336j
ROM:00022EBA                addq.w  #1,(word_FFC148).l
ROM:00022EC0                jsr    (randomisation).l ; angle position randomisations
ROM:00022EC6                move.w  d0,(sp)
ROM:00022EC8                move.w  #1,-(sp)        ; accurate positions
ROM:00022ECC                move.w  #$1E,-(sp)      ; range between fremens
ROM:00022ED0                move.l  d4,-(sp)
ROM:00022ED2                jsr    sub_1168C
ROM:00022ED8                addq.l  #8,sp
ROM:00022EDA                move.l  d0,-(sp)
ROM:00022EDC                moveq  #3,d0          ; fremen house
ROM:00022EDE                move.w  d0,-(sp)
ROM:00022EE0                move.w  d0,-(sp)
ROM:00022EE2                move.w  #0,-(sp)
ROM:00022EE6                jsr    (random_for_xz).l ; fremen signle trooper
ROM:00022EEC                addq.l  #4,sp
ROM:00022EEE                add.w  d0,d0
ROM:00022EF0                move.w  (a4,d0.w),-(sp)
ROM:00022EF4                move.w  #$FFFF,-(sp)
ROM:00022EF8                jsr    UNIT_CREATING
ROM:00022EFE                lea    $A(sp),sp
ROM:00022F02                movea.l a0,a2
ROM:00022F04                subq.w  #1,(word_FFC148).l
ROM:00022F0A                move.l  a2,d0
ROM:00022F0C                beq.w  loc_22FFA
ROM:00022F10                lea    $12(a2),a1
ROM:00022F14                move.w  (a1),d0
ROM:00022F16                add.w  d0,d0
ROM:00022F18                move.w  d0,(a1)

Code to change icons:

ROM:00029922                 cmpi.b  #3,8(a3)        ; fremen house?
ROM:00029928                bne.s  unit_icons      ; no
ROM:0002992A                cmpi.b  #$19,2(a3)      ; worm
ROM:00029930                beq.s  unit_icons      ; yes
ROM:00029932                cmpi.b  #3,2(a3)        ; unit is 3 troopers
ROM:00029938                bne.s  loc_2993E      ; no
ROM:0002993A                moveq  #$5E,d3        ; 3 fremens icon
ROM:0002993C                bra.s  loc_29940
ROM:0002993E ; ---------------------------------------------------------------------------
ROM:0002993E
ROM:0002993E loc_2993E:                              ; CODE XREF: sub_294C2+476j
ROM:0002993E                moveq  #$68,d3        ; single fremen icon
ROM:00029940
ROM:00029940 loc_29940:                              ; CODE XREF: sub_294C2+47Aj
ROM:00029940                move.w  d3,(sp)
ROM:00029942                bra.s  loc_2995A

And here's the code for Fremen troopers' attack damage increase:

ROM:000449BA                 move.w  $54(a0),d7      ; read unit damage
.....

..ROM:000449FE loc_449FE:                              ; CODE XREF: ROM:000449F6j
ROM:000449FE                cmpi.b  #3,8(a3)        ; fremen house id?
ROM:00044A04                bne.s  loc_44A08      ; no
ROM:00044A06                lsl.w  #2,d7          ; damage 4x

ROM:000449E2 loc_449E2:                              ; CODE XREF: ROM:000449D2j
ROM:000449E2                                        ; ROM:000449DEj
ROM:000449E2                cmpi.b  #3,2(a3)        ; troopers
ROM:000449E8                beq.s  loc_449F2      ; yes
ROM:000449EA                cmpi.b  #5,2(a3)        ; trooper
ROM:000449F0                bne.s  loc_44A08      ; no

Since there is evidence that the game code had undergone minimal changes during the Sega version development, I wonder if analogous code could be found in the PC version?

Link to comment
Share on other sites

  • 2 weeks later...

Ti_ changed the code in the Sega version so that the worms leave spice blooms when driven off the map:

*d3=coord.
*a2= adress;  regs saved d3-d5, a2-a3


org $47160

jsr $43504(pc)
jmp ($1ED0).w

nop




addq.l  #4,sp
cmpi.b #$19,2(a2) ; unit is worm?
bne.s no_worm

lea ($FFFFC068).w,a3 ; map scale
lea ($714A8).l,a2 ; map cfg dat
move.w  #511,d5

move.w  (a3),d4
add.w  d4,d4
add.w  (a2,d4.w),d3
ext.l  d3
lsl.l  #2,d3
movea.l ($4AA24).l,a3
adda.l d3,a3
move.w  ($FFFFC228).w,d4
and.w  d5,d4
move.w  (a3),d3
andi.w  #$FE00,d3
add.w  d4,d3
move.w  d3,(a3)
no_worm
movem.l (sp)+,d3-d5/a2-a3
rts

He believes that the worms were supposed to return to the map after some time, and there are leftovers in the code for this which might be possible to reactivate. So basically he hopes to have unlimited spice on the map this way :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...