Jump to content

Recommended Posts

Posted

I found another missionNumber exception about "Enemy/[House] Unit Approaching":

seg023:0AD7                   loc_22D07:                                                  ; CODE XREF: sub_22B24+1D4jseg023:0AD7 83 3E A4 38 03                    cmp     missionNumber, 3                    ; Compare Two Operandsseg023:0ADC 73 68                             jnb     short loc_22D76                     ; Jump if Not Below (CF=0)seg023:0ADE B8 08 00                          mov     ax, 8                               ; Const Yardseg023:0AE1 50                                push    ax                                  ; typeIndexFindseg023:0AE2 FF 36 2C 3A                       push    houseHumanID                        ; houseIDseg023:0AE6 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:0AE8 33 D2                             xor     dx, dx                              ; Logical Exclusive ORseg023:0AEA 50                                push    axseg023:0AEB 52                                push    dx                                  ; houseGamePtrseg023:0AEC 9A FD 00 8B 1E                    call    buildingGameFind                    ; Call Procedureseg023:0AF1 83 C4 08                          add     sp, 8                               ; Addseg023:0AF4 89 56 F4                          mov     word ptr [bp+buildingHumanConstYardGamePtr+2], dxseg023:0AF7seg023:0AF7                   loc_22D27:seg023:0AF7 89 46 F2                          mov     word ptr [bp+buildingHumanConstYardGamePtr], axseg023:0AFA 8B 46 F2                          mov     ax, word ptr [bp+buildingHumanConstYardGamePtr]seg023:0AFD 0B 46 F4                          or      ax, word ptr [bp+buildingHumanConstYardGamePtr+2] ; Logical Inclusive ORseg023:0B00 74 38                             jz      short loc_22D6A                     ; Jump if Zero (ZF=1)seg023:0B02 C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0B05 26 FF 77 0C                       push    es:[bx+_unitGame.mapTileY]          ; posY2seg023:0B09 26 FF 77 0A                       push    es:[bx+_unitGame.mapTileX]          ; posX2seg023:0B0D C4 5E F2                          les     bx, [bp+buildingHumanConstYardGamePtr] ; Load Full Pointer to ES:xxseg023:0B10seg023:0B10                   loc_22D40:                                                  ; posYseg023:0B10 26 FF 77 0C                       push    es:[bx+_buildingGame.positionY]seg023:0B14 26 FF 77 0A                       push    es:[bx+_buildingGame.positionX]     ; posXseg023:0B18seg023:0B18                   loc_22D48:                                                  ; Get the angle to point, from this position > that positionseg023:0B18 9A 25 01 48 1D                    call    angleBetweenseg023:0B1D 83 C4 08                          add     sp, 8                               ; Addseg023:0B20 50                                push    axseg023:0B21 9A 7F 00 D0 42                    call    j_AngleAdjust                       ; Call Procedureseg023:0B26 59                                pop     cxseg023:0B27 8B F0                             mov     si, axseg023:0B29 46                                inc     si                                  ; Increment by 1seg023:0B2A 83 E6 07                          and     si, 7                               ; Logical ANDseg023:0B2D 8B C6                             mov     ax, siseg023:0B2F D1 E8                             shr     ax, 1                               ; Shift Logical Rightseg023:0B31 8B F0                             mov     si, axseg023:0B33 8B C6                             mov     ax, siseg023:0B35 05 02 00                          add     ax, 2                               ; Addseg023:0B38 EB 03                             jmp     short loc_22D6D                     ; Jumpseg023:0B3A                   ; ---------------------------------------------------------------------------seg023:0B3Aseg023:0B3A                   loc_22D6A:                                                  ; CODE XREF: sub_22B24+20Cjseg023:0B3A B8 01 00                          mov     ax, 1                               ; Warning: Enemy Unit Approachingseg023:0B3Dseg023:0B3D                   loc_22D6D:                                                  ; CODE XREF: sub_22B24+244jseg023:0B3D 50                                push    axseg023:0B3E 9A 2A 00 86 42                    call    j_soundTableLoad                    ; Call Procedureseg023:0B43 59                                pop     cxseg023:0B44 EB 12                             jmp     short loc_22D88                     ; Jumpseg023:0B46                   ; ---------------------------------------------------------------------------seg023:0B46seg023:0B46                   loc_22D76:                                                  ; CODE XREF: sub_22B24+1E8jseg023:0B46 C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0B49 26 8A 47 08                       mov     al, es:[bx+_unitGame.houseID]seg023:0B4D 98                                cbw                                         ; AL -> AX (with sign)seg023:0B4E 05 06 00                          add     ax, 6                               ; Addseg023:0B51 50                                push    axseg023:0B52 9A 2A 00 86 42                    call    j_soundTableLoad                    ; Call Procedureseg023:0B57 59                                pop     cx

 

If missionNumber is below 3, then check Enemy Unit position respect your CY position and identified this position (N, S, W or E) it plays Mentat alert "Enemy unit approaching from the [identified position]". Of course if you don't have a CY Mentat alert say only "Enemy unit approaching" and stop.

 

Over missionNumber 3 (if is not below 3) it jumps directly on last location (loc_22D76) that loads only HouseID so Mentat alert is "[House] unit approaching" and stop, having bypass the part relative to the positioning (N, S, W or S).

  • Upvote 1
Posted

BTW, the "enemy unit approaching from the <direction>" calculation here is wrong.  It announces unit coming from the south as "from the north".  Since you've identified it, you may as well fix it up.  From seg023:0B29 onwards:

 

Increment by 1, Logical AND 0x7, Shift Logical Right 1

 

should instead be:

 

Increment by 1, Logical AND 0xF, Shift Logical Right 2.

 

 

Edit: hmm, now I can't reproduce it.  Maybe it was an OpenDUNE conversion error.

Posted

I was looking for a way to put Mentat alert so: "[HOUSE] unit approaching from the [N/S/W/E]"

But it seems that if loads pointer to use HouseID, it losts other position references (N/S/W/E) calculated above.

  • Upvote 1
Posted

drnovice, nice find!

As a matter of fact, I only played around with the "Enemy unit approaching" exception in DuneX because it is relevant for the non-ENglish language speech. At some point DuneX used the German language setup (for a variety of reasons that are no longer in effect thanks to segra's and OpenDUNE team's efforts) - of course, all speech that was used was generated from English Harkonnen pack (as you know, German and French use a much smaller set of speech lines). In this mode, I noticed that the game would play the clip "Unit destroyed" when the player lost a unit, and "Enemy unit destroyed" if an enemy unit was destroyed (obviously) - but only when the "Enemy unit approaching" exception was in effect (i.e. in the first two missions). After that, the game would use the "Unit destroyed" clip indiscriminately for both the player's and enemy AI's unit losses, which of course was confusing. So I hacked the EXE to extend the exception from the first two missions to all missions in the campaign. When I switched back to the regular English speech, I decided to just nix the "Enemy unit" stuff at all, and inverted the exception, making it non-functional for all playable missions in the game.

Posted

It's very odd, because to my tests without changes, English languages in Dune2.exe v1.07-EU (the same for DuneX.exe) in previous missions Mentat alerts said "Enemy Unit Destroyed" for AI units (even Fremen units that are "allies"), instead "[HOUSE-Human] Unit Destroyed" for Human units. I'll do further testing without hacking about successive missions for Mentat alerts.

However hacking the .exe about [HOUSE] pronunciation for enemy units destroyed should be preserved "[HOUSE] Unit Destroyed" for proper Human units.

 

Regarding the 'approaching' Mentat alerts I'm thinking to set "Enemy unit approaching from the [position]" for ALL missions because it's more accurate respect only "[HOUSE] unit approaching" and stop. Also because these alerts aren't used for own Human units.

 

 

Soon I'll test "Enemy construction destroyed" Mentat alerts to change in "[HOUSE] construction destroyed", although could remain as it is, because scenario can't manage AI allies about building and teams production.

Posted

I managed "Enemy Structure Destroyed" chunk code:

seg010:12EA C4 5E 06                          les     bx, [bp+buildingGamePtr]            ; Load Full Pointer to ES:xxseg010:12ED 26 8A 47 08                       mov     al, es:[bx+_buildingGame.houseID]seg010:12F1 98                                cbw                                         ; AL -> AX (with sign)seg010:12F2 3B 06 2C 3A                       cmp     ax, houseHumanID                    ; Compare Two Operandsseg010:12F6 75 38                             jnz     short loc_1B760                     ; Jump if Not Zero (ZF=0)seg010:12F8 BF FF FF                          mov     di, 0FFFFhseg010:12FB C4 5E 06                          les     bx, [bp+buildingGamePtr]            ; Load Full Pointer to ES:xxseg010:12FEseg010:12FE                   loc_1B72E:seg010:12FE 26 8A 47 08                       mov     al, es:[bx+_buildingGame.houseID]seg010:1302 98                                cbw                                         ; AL -> AX (with sign)seg010:1303seg010:1303                   loc_1B733:                                                  ; Logical Inclusive ORseg010:1303 0B C0                             or      ax, axseg010:1305 74 0C                             jz      short Hark                          ; Jump if Zero (ZF=1)seg010:1307 3D 01 00                          cmp     ax, 1                               ; Compare Two Operandsseg010:130A 74 0C                             jz      short Atre                          ; Jump if Zero (ZF=1)seg010:130C 3D 02 00                          cmp     ax, 2                               ; Compare Two Operandsseg010:130F 74 0C                             jz      short Ordos                         ; Jump if Zero (ZF=1)seg010:1311 EB 0F                             jmp     short Other                         ; Jumpseg010:1313                   ; ---------------------------------------------------------------------------seg010:1313seg010:1313                   Hark:                                                       ; CODE XREF: structureDamageTake+EFjseg010:1313 BF 16 00                          mov     di, 16hseg010:1316 EB 0F                             jmp     short loc_1B757                     ; Jumpseg010:1318                   ; ---------------------------------------------------------------------------seg010:1318seg010:1318                   Atre:                                                       ; CODE XREF: structureDamageTake+F4jseg010:1318 BF 17 00                          mov     di, 17hseg010:131B EB 0A                             jmp     short loc_1B757                     ; Jumpseg010:131D                   ; ---------------------------------------------------------------------------seg010:131Dseg010:131D                   Ordos:                                                      ; CODE XREF: structureDamageTake+F9jseg010:131D BF 18 00                          mov     di, 18hseg010:1320 EB 05                             jmp     short loc_1B757                     ; Jumpseg010:1322                   ; ---------------------------------------------------------------------------seg010:1322seg010:1322                   Other:                                                      ; CODE XREF: structureDamageTake+FBjseg010:1322 BF FF FF                          mov     di, 0FFFFhseg010:1325 EB 00                             jmp     short 2                           ; Jumpseg010:1327seg010:1327                   loc_1B757:                                                  ; CODE XREF: structureDamageTake+100jseg010:1327                                                                               ; structureDamageTake+105j ...seg010:1327 57                                push    diseg010:1328 9A 2A 00 86 42                    call    j_soundTableLoad                    ; Call Procedureseg010:132D 59                                pop     cxseg010:132E EB 0A                             jmp     short loc_1B76A                     ; Jumpseg010:1330                   ; ---------------------------------------------------------------------------seg010:1330seg010:1330                   loc_1B760:                                                  ; CODE XREF: structureDamageTake+E0jseg010:1330 B8 15 00                          mov     ax, 15h                             ; Hark Struct Destroyedseg010:1333 50                                push    axseg010:1334 9A 2A 00 86 42                    call    j_soundTableLoad                    ; Call Procedureseg010:1339 59                                pop     cx

If Human HouseID is different to Bulding HouseID (jnz) it jumps into loc_1B760 that just play "Enemy Structure Destroyed" (15h) because it's an opponent AI building to be destroyed.

Instead if jnz isn't occurred then check which House declare by ID (00: Harkonnen -> 16h, 01: Atreides -> 17h, 02: Ordos -> 18h, else FFFFh that it's no sound!). Originally it manages only original Houses so if you play as Fremen or Sardaukar you don't heard any Mentat alert about own building destroyed.

 

 

Try to change (Dune 2 v1.07-EU):

0x01031A:                               C4 5E 06 26 8A 470x010320: 08 98 3B 06 38 3A 75 38 BF FF FF C4 5E 06 26 8A0x010330: 47 08 98 0B C0 74 0C 3D 01 00 74 0C 3D 02 00 740x010340: 0C EB 0F BF 16 00 EB 0F BF 17 00 EB 0A BF 18 000x010350: EB 05 BF FF FF EB 00 57 9A 2A 00 8C 32 59 EB 0A0x010360: B8 15 00 50 9A 2A 00 8C 32 59

to: WRONG

 

0x01031A:                               BF FF FF C4 5E 06

0x010320: 26 8A 47 08 98 0B C0 74 19 3D 01 00 74 19 3D 02

0x010330: 00 74 19 3D 03 00 74 19 3D 04 00 74 19 3D 05 00

0x010340: 74 19 BF 16 00 EB 1C BF 17 00 EB 17 BF 18 00 EB

0x010350: 12 BF 19 00 EB 0D BF 20 00 EB 08 BF 21 00 EB 03

0x010360: 90 90 90 57 9A 2A 00 8C 32 59

 

So we can have Mentat alerts, that manage ALL 6 factions, saying "[HOUSE] Structure Destroyed". ;)

 

EDITED: I was wrong about Sardaukar & Mercenary IDs sound references, 'cause are 1A & 1B (not 20 & 21).

I had to change a little the code because  using 0x01035B zone to Mercenary exception it did crash game, so I set them on first 3 bytes (replacing BF FF FF that is null):

0x01031A:                               BF 1B 00 C4 5E 060x010320: 26 8A 47 08 98 0B C0 74 19 3D 01 00 74 19 3D 020x010330: 00 74 19 3D 03 00 74 19 3D 04 00 74 19 3D 05 000x010340: 74 21 BF 16 00 EB 1C BF 17 00 EB 17 BF 18 00 EB0x010350: 12 BF 19 00 EB 0D BF 1A 00 EB 08 90 90 90 90 900x010360: 90 90 90 57 9A 2A 00 8C 32 59

last jz (74 21) goes directly to 0x010363 position.


 

Now I would like understand why Mentat alerts "Sardaukar Unit Destroyed" and "Sardaukar Unit Deployed" are heard "Sardaukar ... Destroyed" and "Sardaukar ... Deployed". In particular it refers to %cUNIT.VOC file, it happens for all ATRE.PAK, HARK.PAK and ORDOS.PAK files (thus regardless the voice).

  • Upvote 1
Posted

Great findings, thanks!

BTW, I never really paid attention while playing, does the game announce the destruction of both the player's and the AI's structures? I'm only sure of the fact that in non-English versions, the game just has a clip for "Enemy structure destroyed".

Now I would like understand why Mentat alerts "Sardaukar Unit Destroyed" and "Sardaukar Unit Deployed" are heard "Sardaukar ... Destroyed" and "Sardaukar ... Deployed". In particular it refers to %cUNIT.VOC file, it happens for all ATRE.PAK, HARK.PAK and ORDOS.PAK files (thus regardless the voice).
This was probably done on purpose, since I guess originally the Sardaukar were supposed to be represented by powerful infantry units (maybe a unique version of Trooper or something).

The Mentat says "Sardaukar destroyed" instead of "Sardaukar unit destroyed" because this is how the relevant phrase is structured. As a matter of fact, there is no single "syntactic model" for the announcements in which only the House names are changed. Rather, each event (such as the construction of a new Atreides unit) is associated with its own sequence of files to be played, and a text string that is displayed if no speech is enabled in the settings.

There's a "speech table" of sorts that lists all the sequences. Here's what it looks like the in segra's database:

dseg:0312 2B 00 FF FF FF FF+soundPlayTableEnglish _soundPlay <2Bh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 33h, 3Ch>; 0dseg:0312 FF FF FF FF 33 00+                                                            ; DATA XREF: soundTableLoad:loc_4D83Erdseg:0312 3C 00                                                                         ; soundTableLoad+93r ...dseg:0320 31 00 1D 00 24 00+stru_43740      _soundPlay <31h, 1Dh, 24h, 37h, 0FFFFh, 34h, 0FFFFh>; 0dseg:032E 31 00 1D 00 24 00+stru_4374E      _soundPlay <31h, 1Dh, 24h, 37h, 39h, 34h, 0FFFFh>; 0 ; Warning: Enemy Unit Approaching Northdseg:033C 31 00 1D 00 24 00+stru_4375C      _soundPlay <31h, 1Dh, 24h, 37h, 3Ah, 34h, 0FFFFh>; 0dseg:034A 31 00 1D 00 24 00+stru_4376A      _soundPlay <31h, 1Dh, 24h, 37h, 3Bh, 34h, 0FFFFh>; 0dseg:0358 31 00 1D 00 24 00+stru_43778      _soundPlay <31h, 1Dh, 24h, 37h, 3Ch, 34h, 0FFFFh>; 0dseg:0366 31 00 1E 00 24 00+stru_43786      _soundPlay <31h, 1Eh, 24h, 37h, 0FFFFh, 35h, 0FFFFh>; 0 ; Warning: Harkdseg:0374 31 00 1F 00 24 00+stru_43794      _soundPlay <31h, 1Fh, 24h, 37h, 0FFFFh, 36h, 0FFFFh>; 0 ; Warning: Atredseg:0382 31 00 20 00 24 00+stru_437A2      _soundPlay <31h, 20h, 24h, 37h, 0FFFFh, 37h, 0FFFFh>; 0dseg:0390 31 00 21 00 24 00+stru_437B0      _soundPlay <31h, 21h, 24h, 37h, 0FFFFh, 38h, 0FFFFh>; 0dseg:039E 31 00 22 00 37 00+stru_437BE      _soundPlay <31h, 22h, 37h, 0FFFFh, 0FFFFh, 39h, 0FFFFh>; 0dseg:03AC 31 00 23 00 24 00+stru_437CC      _soundPlay <31h, 23h, 24h, 37h, 0FFFFh, 3Ah, 0FFFFh>; 0dseg:03BA 31 00 32 00 37 00+stru_437DA      _soundPlay <31h, 32h, 37h, 0FFFFh, 0FFFFh, 3Bh, 0FFFFh>; 0 ; Sabotdseg:03C8 1D 00 24 00 35 00+stru_437E8      _soundPlay <1Dh, 24h, 35h, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0 ; Enemy Unit Destroyeddseg:03D6 1E 00 24 00 35 00+stru_437F6      _soundPlay <1Eh, 24h, 35h, 0FFFFh, 0FFFFh, 3Ch, 0FFFFh>; 0 ; Hark Unit Destroyeddseg:03E4 1F 00 24 00 35 00+stru_43804      _soundPlay <1Fh, 24h, 35h, 0FFFFh, 0FFFFh, 3Dh, 0FFFFh>; 0dseg:03F2 20 00 24 00 35 00+stru_43812      _soundPlay <20h, 24h, 35h, 0FFFFh, 0FFFFh, 3Eh, 0FFFFh>; 0dseg:0400 21 00 24 00 35 00+stru_43820      _soundPlay <21h, 24h, 35h, 0FFFFh, 0FFFFh, 3Fh, 0FFFFh>; 0dseg:040E 22 00 35 00 FF FF+stru_4382E      _soundPlay <22h, 35h, 0FFFFh, 0FFFFh, 0FFFFh, 40h, 0FFFFh>; 0dseg:041C 23 00 24 00 35 00+stru_4383C      _soundPlay <23h, 24h, 35h, 0FFFFh, 0FFFFh, 41h, 0FFFFh>; 0dseg:042A 32 00 35 00 FF FF+stru_4384A      _soundPlay <32h, 35h, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0 ; Sab Destroyeddseg:0438 1D 00 25 00 35 00+stru_43858      _soundPlay <1Dh, 25h, 35h, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:0438 FF FF FF FF 00 00+                                                            ; DATA XREF: miniMapDrawPiece:loc_17652rdseg:0438 FF FF                                                                         ; miniMapDrawPiece:loc_1764Drdseg:0438                                                                               ; Hark Structure Destroyeddseg:0446 1E 00 25 00 35 00+stru_43866      _soundPlay <1Eh, 25h, 35h, 0FFFFh, 0FFFFh, 42h, 0FFFFh>; 0dseg:0454 1F 00 25 00 35 00+stru_43874      _soundPlay <1Fh, 25h, 35h, 0FFFFh, 0FFFFh, 43h, 0FFFFh>; 0dseg:0462 20 00 25 00 35 00+stru_43882      _soundPlay <20h, 25h, 35h, 0FFFFh, 0FFFFh, 44h, 0FFFFh>; 0dseg:0470 21 00 25 00 35 00+stru_43890      _soundPlay <21h, 25h, 35h, 0FFFFh, 0FFFFh, 45h, 0FFFFh>; 0dseg:0470 FF FF FF FF 45 00+                                                            ; DATA XREF: sub_58280:loc_5836Drdseg:0470 FF FF                                                                         ; sub_58280+E8rdseg:047E 22 00 35 00 FF FF+stru_4389E      _soundPlay <22h, 35h, 0FFFFh, 0FFFFh, 0FFFFh, 46h, 0FFFFh>; 0dseg:048C 23 00 25 00 35 00+stru_438AC      _soundPlay <23h, 25h, 35h, 0FFFFh, 0FFFFh, 47h, 0FFFFh>; 0dseg:049A 2C 00 2E 00 FF FF+stru_438BA      _soundPlay <2Ch, 2Eh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:04A8 2C 00 2D 00 FF FF+stru_438C8      _soundPlay <2Ch, 2Dh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:04B6 1E 00 24 00 36 00+stru_438D6      _soundPlay <1Eh, 24h, 36h, 0FFFFh, 0FFFFh, 48h, 0FFFFh>; 0dseg:04C4 1F 00 24 00 36 00+stru_438E4      _soundPlay <1Fh, 24h, 36h, 0FFFFh, 0FFFFh, 49h, 0FFFFh>; 0dseg:04D2 20 00 24 00 36 00+stru_438F2      _soundPlay <20h, 24h, 36h, 0FFFFh, 0FFFFh, 4Ah, 0FFFFh>; 0dseg:04E0 21 00 24 00 36 00+stru_43900      _soundPlay <21h, 24h, 36h, 0FFFFh, 0FFFFh, 4Bh, 0FFFFh>; 0dseg:04EE 22 00 36 00 FF FF+stru_4390E      _soundPlay <22h, 36h, 0FFFFh, 0FFFFh, 0FFFFh, 4Ch, 0FFFFh>; 0dseg:04FC 23 00 24 00 36 00+stru_4391C      _soundPlay <23h, 24h, 36h, 0FFFFh, 0FFFFh, 4Dh, 0FFFFh>; 0dseg:050A 34 00 38 00 FF FF+stru_4392A      _soundPlay <34h, 38h, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0 ; Bloom Locateddseg:0518 31 00 44 00 FF FF+stru_43938      _soundPlay <31h, 44h, 0FFFFh, 0FFFFh, 0FFFFh, 4Eh, 17h>; 0 ; Warning Wormydseg:0526 2F 00 30 00 FF FF+stru_43946      _soundPlay <2Fh, 30h, 0FFFFh, 0FFFFh, 0FFFFh, 50h, 0FFFFh>; 0dseg:0534 31 00 33 00 37 00+stru_43954      _soundPlay <31h, 33h, 37h, 0FFFFh, 0FFFFh, 51h, 0FFFFh>; 0dseg:0542 3D 00 FF FF FF FF+stru_43962      _soundPlay <3Dh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:0550 3E 00 FF FF FF FF+stru_43970      _soundPlay <3Eh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:055E 33 00 3F 00 FF FF+stru_4397E      _soundPlay <33h, 3Fh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:056C 26 00 FF FF FF FF+stru_4398C      _soundPlay <26h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 2Eh>; 0dseg:057A 27 00 FF FF FF FF+stru_4399A      _soundPlay <27h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 2Eh>; 0dseg:0588 28 00 FF FF FF FF+stru_439A8      _soundPlay <28h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 2Eh>; 0dseg:0596 29 00 FF FF FF FF+stru_439B6      _soundPlay <29h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 2Eh>; 0dseg:05A4 2A 00 FF FF FF FF+stru_439C4      _soundPlay <2Ah, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 2Eh>; 0dseg:05B2 40 00 FF FF FF FF+                _soundPlay <40h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 5Ah, 17h>; 0dseg:05C0 1E 00 24 00 3F 00+stru_439E0      _soundPlay <1Eh, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Ah, 0FFFFh>; 0dseg:05CE 1F 00 24 00 3F 00+stru_439EE      _soundPlay <1Fh, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Bh, 0FFFFh>; 0dseg:05DC 20 00 24 00 3F 00+stru_439FC      _soundPlay <20h, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Ch, 0FFFFh>; 0dseg:05EA 21 00 24 00 3F 00+stru_43A0A      _soundPlay <21h, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Dh, 0FFFFh>; 0dseg:05F8 22 00 24 00 3F 00+stru_43A18      _soundPlay <22h, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Eh, 0FFFFh>; 0dseg:0606 23 00 24 00 3F 00+stru_43A26      _soundPlay <23h, 24h, 3Fh, 0FFFFh, 0FFFFh, 9Fh, 0FFFFh>; 0dseg:0614 1E 00 41 00 42 00+stru_43A34      _soundPlay <1Eh, 41h, 42h, 0FFFFh, 0FFFFh, 0A2h, 0FFFFh>; 0dseg:0622 1F 00 41 00 42 00+stru_43A42      _soundPlay <1Fh, 41h, 42h, 0FFFFh, 0FFFFh, 0A3h, 0FFFFh>; 0dseg:0630 20 00 41 00 42 00+stru_43A50      _soundPlay <20h, 41h, 42h, 0FFFFh, 0FFFFh, 0A4h, 0FFFFh>; 0dseg:063E 21 00 41 00 42 00+stru_43A5E      _soundPlay <21h, 41h, 42h, 0FFFFh, 0FFFFh, 0A5h, 0FFFFh>; 0dseg:064C 22 00 41 00 42 00+stru_43A6C      _soundPlay <22h, 41h, 42h, 0FFFFh, 0FFFFh, 0A6h, 0FFFFh>; 0dseg:065A 23 00 41 00 42 00+stru_43A7A      _soundPlay <23h, 41h, 42h, 0FFFFh, 0FFFFh, 0A7h, 0FFFFh>; 0dseg:0668 46 00 47 00 FF FF+stru_43A88      _soundPlay <46h, 47h, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:0676 1E 00 FF FF FF FF+stru_43A96      _soundPlay <1Eh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:0684 1F 00 FF FF FF FF+stru_43AA4      _soundPlay <1Fh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:0692 20 00 FF FF FF FF+stru_43AB2      _soundPlay <20h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:06A0 21 00 FF FF FF FF+stru_43AC0      _soundPlay <21h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:06AE 22 00 FF FF FF FF+stru_43ACE      _soundPlay <22h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:06BC 23 00 FF FF FF FF+stru_43ADC      _soundPlay <23h, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh>; 0dseg:06CA 1E 00 43 00 36 00+stru_43AEA      _soundPlay <1Eh, 43h, 36h, 0FFFFh, 0FFFFh, 93h, 0FFFFh>; 0dseg:06D8 1F 00 43 00 36 00+stru_43AF8      _soundPlay <1Fh, 43h, 36h, 0FFFFh, 0FFFFh, 94h, 0FFFFh>; 0dseg:06E6 20 00 43 00 36 00+stru_43B06      _soundPlay <20h, 43h, 36h, 0FFFFh, 0FFFFh, 95h, 0FFFFh>; 0dseg:06F4 21 00 43 00 36 00+stru_43B14      _soundPlay <21h, 43h, 36h, 0FFFFh, 0FFFFh, 96h, 0FFFFh>; 0dseg:0702 22 00 43 00 36 00+stru_43B22      _soundPlay <22h, 43h, 36h, 0FFFFh, 0FFFFh, 97h, 0FFFFh>; 0dseg:0710 23 00 43 00 36 00+stru_43B30      _soundPlay <23h, 43h, 36h, 0FFFFh, 0FFFFh, 98h, 0FFFFh>; 0dseg:071E FF FF FF FF FF FF+stru_43B3E      _soundPlay <0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 1, 0FFFFh> ; Dunedseg:072C FF FF FF FF FF FF+stru_43B4C      _soundPlay <0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0FFFFh, 0, 0FFFFh> ; Building
This one is BTW for the English version, other languages use a different table with less speech clips.

And this is what it looks like in the EU version (without any comments):

31 00 1D 00 24 00 37 00 FF FF 34 00 FF FF 31 00 1D 00 24 00 37 00 39 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3A 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3B 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3C 00 34 00 FF FF 31 00 1E 00 24 00 37 00 FF FF 35 00 FF FF 31 00 1F 00 24 00 37 00 FF FF 36 00 FF FF 31 00 20 00 24 00 37 00 FF FF 37 00 FF FF 31 00 21 00 24 00 37 00 FF FF 38 00 FF FF 31 00 22 00 37 00 FF FF FF FF 39 00 FF FF 31 00 23 00 24 00 37 00 FF FF 3A 00 FF FF 31 00 32 00 37 00 FF FF FF FF 3B 00 FF FF 1D 00 24 00 35 00 FF FF FF FF 00 00 FF FF 1E 00 24 00 35 00 FF FF FF FF 3C 00 FF FF 1F 00 24 00 35 00 FF FF FF FF 3D 00 FF FF 20 00 24 00 35 00 FF FF FF FF 3E 00 FF FF 21 00 24 00 35 00 FF FF FF FF 3F 00 FF FF 22 00 35 00 FF FF FF FF FF FF 40 00 FF FF 23 00 24 00 35 00 FF FF FF FF 41 00 FF FF 32 00 35 00 FF FF FF FF FF FF 00 00 FF FF 1D 00 25 00 35 00 FF FF FF FF 00 00 FF FF
As you can see, each two bytes represent either a sound clip, or a text string. For example, the 31 00 in the beginning is the "Warning!" speech clip. The first sequences are for "Enemy unit approaching from <direction>":

31 00 1D 00 24 00 37 00 FF FF 34 00 FF FF 31 00 1D 00 24 00 37 00 39 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3A 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3B 00 34 00 FF FF 31 00 1D 00 24 00 37 00 3C 00 34 00 FF FF
The first one lacks any direction, so there's an empty space (FF FF) between the last sound bit (37 00 "approaching" and the ID of the text string (34 00). The text string ID is the same in all cases, as there is only one text string, "Enemy unit approaching". I think the string ID is the same as its hex number in the string table file, counting from 0.

As for the Sardaukar, here's the part of the table:

1D 00 24 00 35 00 FF FF FF FF 00 00 FF FF ; "Enemy unit destroyed"1E 00 24 00 35 00 FF FF FF FF 3C 00 FF FF ; "Harkonnen unit destroyed"1F 00 24 00 35 00 FF FF FF FF 3D 00 FF FF ; "Atreides unit destroyed"20 00 24 00 35 00 FF FF FF FF 3E 00 FF FF ; "Ordos unit destroyed"21 00 24 00 35 00 FF FF FF FF 3F 00 FF FF ; "Fremen unit destroyed"22 00 35 00 FF FF FF FF FF FF 40 00 FF FF ; "Sardaukar destroyed"23 00 24 00 35 00 FF FF FF FF 41 00 FF FF ; "Mercenary unit destroyed"32 00 35 00 FF FF FF FF FF FF 00 00 FF FF ; "Saboteur destroyed"
The Sardaukar line only has two speech clips, ID22 "Sardaukar" and ID35 "destroyed". You can easily edit that to get the "unit" ID24 back there.
Posted

Oh great! Thanks to explain.

Yes, I've read this TableSound, but at the wrong location (from dseg:0836, that I think it's the Intro Voice because of an unique big block of code).

Now I know what sound is played each time. :)

 

I found out also a very interesting thing that could change the gameplay longevity:

seg023:0387 83 3E A6 38 09                    cmp     missionNumberPrevious, 9            ; Compare Two Operandsseg023:038C 75 35                             jnz     short hasAnotherMission             ; Jump if Not Zero (ZF=0)seg023:038Eseg023:038E                   loc_225BE:                                                  ; Call Procedureseg023:038E 9A 31 01 71 39                    call    sub_39841seg023:0393 B8 0F 00                          mov     ax, 0Fhseg023:0396 50                                push    axseg023:0397 FF 36 2C 3C                       push    word_4704Cseg023:039B FF 36 2A 3C                       push    word_4704Aseg023:039F 9A 00 00 A3 33                    call    screenFadeOut                       ; Call Procedureseg023:03A4 83 C4 06                          add     sp, 6                               ; Addseg023:03A7 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:03A9 50                                push    axseg023:03AA 9A 0E 00 DE 32                    call    sub_32DEE                           ; Call Procedureseg023:03AF 59                                pop     cxseg023:03B0 9A 20 00 AE 42                    call    j_gameEndingPlay                    ; Call Procedureseg023:03B5 9A 20 00 03 43                    call    j_gameShutdown                      ; Call Procedureseg023:03BA 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:03BC 50                                push    ax                                  ; statusseg023:03BDseg023:03BD                   loc_225ED:                                                  ; Call Procedureseg023:03BD 9A 77 03 00 10                    call    _exitseg023:03C2                   ; ---------------------------------------------------------------------------seg023:03C2 59                                pop     cxseg023:03C3seg023:03C3                   hasAnotherMission:                                          ; CODE XREF: gameCheckStatus+E3jseg023:03C3 9A 31 01 71 39                    call    sub_39841                           ; Call Procedureseg023:03C8 9A 20 00 B1 42                    call    sub_42B30                           ; Call Procedureseg023:03CDseg023:03CD                   loc_225FD:                                                  ; Call Procedureseg023:03CD 9A 63 01 71 39                    call    sub_39873seg023:03D2 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:03D4seg023:03D4                   loc_22604:seg023:03D4 BA 00 03                          mov     dx, 300hseg023:03D7 50                                push    ax                                  ; intseg023:03D8 52                                push    dx                                  ; fileSizeseg023:03D9seg023:03D9                   loc_22609:                                                  ; intseg023:03D9 FF 36 28 3C                       push    word ptr src+2seg023:03DD FF 36 26 3C                       push    word ptr src                        ; intseg023:03E1 1E                                push    dsseg023:03E2 B8 C9 60                          mov     ax, offset aIbm_pal_2               ; "IBM.PAL"seg023:03E5 50                                push    ax                                  ; fileNameseg023:03E6seg023:03E6                   loc_22616:                                                  ; Call Procedureseg023:03E6 9A 0A 00 41 33                    call    fileLoad_1seg023:03EB 83 C4 0C                          add     sp, 0Ch                             ; Addseg023:03EEseg023:03EE                   loc_2261E:seg023:03EE B8 01 00                          mov     ax, 1seg023:03F1 50                                push    axseg023:03F2 FF 36 A6 38                       push    missionNumberPreviousseg023:03F6 9A 20 00 06 43                    call    j_missionMapScreen                  ; Call Procedureseg023:03FB 59                                pop     cxseg023:03FC 59                                pop     cxseg023:03FD A3 A4 38                          mov     missionNumber, axseg023:0400seg023:0400                   loc_22630:seg023:0400 B8 0F 00                          mov     ax, 0Fhseg023:0403 50                                push    axseg023:0404seg023:0404                   loc_22634:seg023:0404 FF 36 2C 3C                       push    word_4704Cseg023:0408seg023:0408                   loc_22638:seg023:0408 FF 36 2A 3C                       push    word_4704Aseg023:040Cseg023:040C                   loc_2263C:                                                  ; Call Procedureseg023:040C 9A 00 00 A3 33                    call    screenFadeOutseg023:0411 83 C4 06                          add     sp, 6                               ; Add

Maybe changing 09 on cmp check you can play more Scenarios... I'll test soon!

 

EDITED:

And finally I tested it... we can increase the longevity of Dune 2!! Yes we can! :P

 

To try:

1) I changed 09 Mission Number to 1B (hex value of 11 decimal) at 0x017247 (Dune 2 v1.07-EU)

2) I added [GROUP9] & [GROUP10] into REGIONA.INI (tested with Atreides)

3) I created SCENA024.INI & SCENA025.INI for Mission 10 (because after Missions 8, Mission 9 has scenarios numbers increment only to 2 and not 3, the same for Mission after Mission 9, then it returns normal +3 increment)

4) and so on...

 

and it incredibly works! 8)

 

Note: in Mission 10 Mentat briefing are read all SCEN?###.INI written rows, so I must check about TEXTA.ENG if there is additional space to other briefing over Mission 9.

EDITED #2: ok I successfully added new strings for Mission 10 & 11 (4 strings for mission, 1st Briefing, 2nd Win text, 3rd Lose text & 4th Advices) on TEXTA.ENG by SSTEditor.

  • Upvote 1
Posted
EDITED:

And finally I tested it... we can increase the longevity of Dune 2!! Yes we can! :P

 

To try:

1) I changed 09 Mission Number to 1B (hex value of 11 decimal) at 0x017247 (Dune 2 v1.07-EU)

2) I added [GROUP9] & [GROUP10] into REGIONA.INI (tested with Atreides)

3) I created SCENA024.INI & SCENA025.INI for Mission 10 (because after Missions 8, Mission 9 has scenarios numbers increment only to 2 and not 3, the same for Mission after Mission 9, then it returns normal +3 increment)

4) and so on...

 

and it incredibly works! 8)

 

Note: in Mission 10 Mentat briefing are read all SCEN?###.INI written rows, so I must check about TEXTA.ENG if there is additional space to other briefing over Mission 9.

EDITED #2: ok I successfully added new strings for Mission 10 & 11 (4 strings for mission, 1st Briefing, 2nd Win text, 3rd Lose text & 4th Advices) on TEXTA.ENG by SSTEditor.

Actually, I think the possibility of playing beyond mission 9 has already been discussed here somewhere, although I have been unable to track the relevant posts down yet. What I do remember is that some time ago (quite some time ago, actually!) I experimented with this, and managed to play mission 10 right after mission 9. All it required was to disable the ending movie after mission 9, and some additions to the REGION#.INI file.
Posted

How to remove copy protection:

seg023:0414                   loc_22644:                                                  ; Compare Two Operandsseg023:0414 83 3E A6 38 01                    cmp     missionNumberPrevious, 1seg023:0419 74 07                             jz      short copyProtection                ; Jump if Zero (ZF=1)seg023:041Bseg023:041B                   loc_2264B:                                                  ; Compare Two Operandsseg023:041B 83 3E A6 38 07                    cmp     missionNumberPrevious, 7seg023:0420 75 69                             jnz     short ProtectionSkipped             ; Jump if Not Zero (ZF=0)seg023:0422seg023:0422                   copyProtection:                                             ; CODE XREF: gameCheckStatus+170jseg023:0422 B8 D2 3B                          mov     ax, seg seg152seg023:0425 50                                push    axseg023:0426seg023:0426                   loc_22656:seg023:0426 B8 40 04                          mov     ax, 440hseg023:0429seg023:0429                   loc_22659:seg023:0429 50                                push    axseg023:042Aseg023:042A                   loc_2265A:seg023:042A B8 07 00                          mov     ax, 7seg023:042D 50                                push    axseg023:042Eseg023:042E                   loc_2265E:seg023:042E B8 01 00                          mov     ax, 1seg023:0431 50                                push    axseg023:0432 9A 34 00 BB 42                    call    sub_42BE4                           ; Call Procedureseg023:0437 83 C4 08                          add     sp, 8                               ; Addseg023:043Aseg023:043A                   loc_2266A:                                                  ; Logical Exclusive ORseg023:043A 33 C0                             xor     ax, axseg023:043Cseg023:043C                   loc_2266C:seg023:043C 50                                push    axseg023:043Dseg023:043D                   loc_2266D:seg023:043D B8 02 00                          mov     ax, 2seg023:0440seg023:0440                   loc_22670:seg023:0440 50                                push    axseg023:0441seg023:0441                   loc_22671:seg023:0441 B8 C8 00                          mov     ax, 0C8h ; '+'seg023:0444 50                                push    axseg023:0445seg023:0445                   loc_22675:seg023:0445 B8 28 00                          mov     ax, 28h ; '('seg023:0448 50                                push    axseg023:0449 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:044B 50                                push    axseg023:044C 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:044E 50                                push    axseg023:044F 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:0451 50                                push    axseg023:0452seg023:0452                   loc_22682:                                                  ; Logical Exclusive ORseg023:0452 33 C0                             xor     ax, axseg023:0454seg023:0454                   loc_22684:seg023:0454 50                                push    axseg023:0455 9A 07 00 D5 32                    call    inGameMenuDraw_0                    ; Call Procedureseg023:045A 83 C4 10                          add     sp, 10h                             ; Addseg023:045Dseg023:045D                   loc_2268D:                                                  ; Call Procedureseg023:045D 9A 39 00 DD 42                    call    j_ProtectionScreenseg023:0462seg023:0462                   loc_22692:                                                  ; Logical Inclusive ORseg023:0462 0B C0                             or      ax, axseg023:0464 75 0E                             jnz     short ProtectionPassed              ; Jump if Not Zero (ZF=0)seg023:0466 9A 20 00 03 43                    call    j_gameShutdown                      ; Call Procedureseg023:046B 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:046D 50                                push    ax                                  ; statusseg023:046E 9A 77 03 00 10                    call    _exit                               ; Call Procedureseg023:0473                   ; ---------------------------------------------------------------------------seg023:0473 59                                pop     cxseg023:0474seg023:0474                   glb_226A4:                                                  ; CODE XREF: gameCheckStatus+1BBjseg023:0474                   ProtectionPassed:seg023:0474 B8 D2 3B                          mov     ax, seg seg152seg023:0477 50                                push    axseg023:0478seg023:0478                   loc_226A8:seg023:0478 B8 40 04                          mov     ax, 440hseg023:047B 50                                push    axseg023:047Cseg023:047C                   loc_226AC:seg023:047C B8 07 00                          mov     ax, 7seg023:047F 50                                push    axseg023:0480seg023:0480                   loc_226B0:                                                  ; Logical Exclusive ORseg023:0480 33 C0                             xor     ax, axseg023:0482seg023:0482                   loc_226B2:seg023:0482 50                                push    axseg023:0483seg023:0483                   loc_226B3:                                                  ; Call Procedureseg023:0483 9A 34 00 BB 42                    call    sub_42BE4seg023:0488seg023:0488                   loc_226B8:                                                  ; Addseg023:0488 83 C4 08                          add     sp, 8seg023:048Bseg023:048B                   ProtectionSkipped:                                          ; CODE XREF: gameCheckStatus+177jseg023:048B EB 3D                             jmp     short loc_226FA                     ; int

Set directly an unconditional jump (jmp) on ProtectionSkipped location and noped first 2 compare (cmp) on top

 

EDITED: Only now I saw that segra already posted it. Sorry!

Posted
Set directly an unconditional jump (jmp) on ProtectionSkipped location and noped first 2 compare (cmp) on top

My preferred method is to simply change the mission numbers after which the copy protection routine is called to non-existent missions like 10 and 11 (0A and 0B in hexadecimal respectively).
Posted
Actually, I think the possibility of playing beyond mission 9 has already been discussed here somewhere, although I have been unable to track the relevant posts down yet. What I do remember is that some time ago (quite some time ago, actually!) I experimented with this, and managed to play mission 10 right after mission 9. All it required was to disable the ending movie after mission 9, and some additions to the REGION#.INI file.

I think that it could be a good point about mods the possibility to change the "9 missions schema" on the campaigns.

Posted

Dune 2 original:

dseg:2B91 54 4F 54 41 4C 20+aTotalRegions   db 'TOTAL REGIONS',0                        ; DATA XREF: sub_5F1A7+1Fodseg:2B9F 00                                align 2dseg:2BA0 10 00             word_45FC0      dw 10h                                      ; DATA XREF: selectTeam:loc_60A08rdseg:2BA2 38 00             word_45FC2      dw 38h                                      ; DATA XREF: selectTeam+8Brdseg:2BA4 1F 00             word_45FC4      dw 1Fh                                      ; DATA XREF: selectTeam+A5rdseg:2BA6 70 00             word_45FC6      dw 70hdseg:2BA8 38 00             word_45FC8      dw 38hdseg:2BAA 19 00             word_45FCA      dw 19hdseg:2BAC D0 00             word_45FCC      dw 0D0hdseg:2BAE 38 00             word_45FCE      dw 38hdseg:2BB0 24 00                             dw 24hdseg:2BB2 DF 2B 42 43       houseLogoPtrs   dd aFhark_wsa_1                             ; DATA XREF: selectTeam:loc_60D16r


DuneX:

dseg:2B91 54 4F 54 41 4C 20+aTotalRegions   db 'TOTAL REGIONS',0                        ; DATA XREF: sub_5F1A7+1Fodseg:2B9F 00                                align 2dseg:2BA0 10 00             word_45FC0      dw 10h                                      ; DATA XREF: selectTeam:loc_60A08rdseg:2BA2 38 00             word_45FC2      dw 38h                                      ; DATA XREF: selectTeam+8Brdseg:2BA4 34 00             word_45FC4      dw 34h                                      ; DATA XREF: selectTeam+A5rdseg:2BA6 70 00             word_45FC6      dw 70hdseg:2BA8 38 00             word_45FC8      dw 38hdseg:2BAA 22 00             word_45FCA      dw 22hdseg:2BAC D0 00             word_45FCC      dw 0D0hdseg:2BAE 38 00             word_45FCE      dw 38hdseg:2BB0 20 00                             dw 20hdseg:2BB2 DF 2B 42 43       houseLogoPtrs   dd aFhark_wsa_1                             ; DATA XREF: selectTeam:loc_60D16r

I can't undestand what are these dword values.

Posted

Now I can't be sure but I think those are codes for keyboard keys that you press to select a House on the Select your House screen. Those were quite hard to track down and I figured them out almost by chance.

In DuneX, you press M, F or S to select your sides, hence the different codes. These codes somehow reflect the position of keys on a standard keyboard. The original codes are as follows:

1Fh = A
24h = H
19h = O

Now if you count the number of keys on the keyboard in the row between A and H, there are four keys (S, D, F and G). Unsurprisingly, there are also four values between 1Fh and 24h. When I realized that, it was easy to calculate that F should be 22h, and S 20h. IIRC this method also counts keys like Return and Shift, but eventually I figured out what the code for M should be too.

Posted

Alright...thanks! Last week I started analysis about all difference between two EXE, just to know what to modify and where to make it with hex editing. MrFlibble if you want, I can posted an attached with all documentation about it. Anyway making other tests about AI alliance, I sadly noticed that my changes (posted some time ago) work only on units but AI allied no longer takes care of enemy structures. :(
 
Let's recap:

I just read you already had that code, and its not what your after.. so i assume these pieces may have some effect

theres a few bits specific to atreides / fremen

src/unit.c

if (houseID == HOUSE_ATREIDES && unit->o.type != UNIT_SANDWORM) {
houseIDBit |= (1 << HOUSE_FREMEN);
}


if (unit->o.houseID == g_playerHouseID || (unit->o.houseID == HOUSE_FREMEN && g_playerHouseID == HOUSE_ATREIDES)) {
unit->o.seenByHouses = 0xFF;
} else {
unit->o.seenByHouses |= houseIDBit;
}

not sure of the disassembly location atm, but it shouldnt be too hard to find


I think that respective asm about this is:

seg023:0912                   loc_22B42:seg023:0912 89 46 F8                          mov     word ptr [bp+houseGamePtr], axseg023:0915 B8 01 00                          mov     ax, 1seg023:0918 8A 4E 0A                          mov     cl, byte ptr [bp+houseIndex]seg023:091B D3 E0                             shl     ax, cl                              ; Shift Logical Leftseg023:091D 89 46 F6                          mov     [bp+houseRevealed], axseg023:0920 83 7E 0A 01                       cmp     [bp+houseIndex], 1                  ; Compare Two Operandsseg023:0924 75 0E                             jnz     short notAtreOrWorm                 ; Jump if Not Zero (ZF=0)seg023:0926 C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0929 26 80 7F 02 19                    cmp     es:[bx+_unitGame.typeIndex], 19h    ; sandwormseg023:092E 74 04                             jz      short notAtreOrWorm                 ; Jump if Zero (ZF=1)seg023:0930seg023:0930                   loc_22B60:                                                  ; Logical Inclusive ORseg023:0930 83 4E F6 08                       or      [bp+houseRevealed], 8seg023:0934seg023:0934                   notAtreOrWorm:                                              ; CODE XREF: sub_22B24+30jseg023:0934                                                                               ; sub_22B24+3Ajseg023:0934 C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0937 26 8A 47 09                       mov     al, es:[bx+_unitGame.houseRevealed]seg023:093B B4 00                             mov     ah, 0seg023:093D 85 46 F6                          test    [bp+houseRevealed], ax              ; Logical Compareseg023:0940seg023:0940                   loc_22B70:                                                  ; Jump if Zero (ZF=1)seg023:0940 74 18                             jz      short loc_22B8Aseg023:0942 C4 5E F8                          les     bx, [bp+houseGamePtr]               ; Load Full Pointer to ES:xxseg023:0945 26 F7 47 04 08 00                 test    es:[bx+_houseGame.IndexLastFound], 8 ; Logical Compareseg023:094B 74 0D                             jz      short loc_22B8A                     ; Jump if Zero (ZF=1)seg023:094D C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0950seg023:0950                   loc_22B80:seg023:0950 8A 46 F6                          mov     al, byte ptr [bp+houseRevealed]seg023:0953 26 08 47 09                       or      es:[bx+_unitGame.houseRevealed], al ; Logical Inclusive ORseg023:0957 E9 94 02                          jmp     Done                                ; Jumpseg023:095A                   ; ---------------------------------------------------------------------------seg023:095Aseg023:095A                   loc_22B8A:                                                  ; CODE XREF: sub_22B24:loc_22B70jseg023:095A                                                                               ; sub_22B24+57j[...]seg023:0BBB                   checkHouseID:                                               ; CODE XREF: sub_22B24+2A9jseg023:0BBB                                                                               ; sub_22B24+2B3jseg023:0BBB C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0BBE 26 8A 47 08                       mov     al, es:[bx+_unitGame.houseID]seg023:0BC2 98                                cbw                                         ; AL -> AX (with sign)seg023:0BC3 3B 06 2C 3A                       cmp     ax, houseHumanID                    ; Compare Two Operandsseg023:0BC7 74 11                             jz      short AtreFre                       ; Jump if Zero (ZF=1)seg023:0BC9seg023:0BC9                   loc_22DF9:                                                  ; Load Full Pointer to ES:xxseg023:0BC9 C4 5E 06                          les     bx, [bp+unitGamePtr]seg023:0BCC 26 80 7F 08 03                    cmp     es:[bx+_unitGame.houseID], 3        ; Fremenseg023:0BD1 75 11                             jnz     short loc_22E14                     ; Jump if Not Zero (ZF=0)seg023:0BD3 83 3E 2C 3A 01                    cmp     houseHumanID, 1                     ; Atreseg023:0BD8 75 0A                             jnz     short loc_22E14                     ; Jump if Not Zero (ZF=0)seg023:0BDAseg023:0BDA                   AtreFre:                                                    ; CODE XREF: sub_22B24+2D3jseg023:0BDA C4 5E 06                          les     bx, [bp+unitGamePtr]                ; unit = fremen and human = atreseg023:0BDD 26 C6 47 09 FF                    mov     es:[bx+_unitGame.houseRevealed], 0FFhseg023:0BE2 EB 0A                             jmp     short Done                          ; Jumpseg023:0BE4                   ; ---------------------------------------------------------------------------seg023:0BE4seg023:0BE4                   loc_22E14:                                                  ; CODE XREF: sub_22B24+2DDjseg023:0BE4                                                                               ; sub_22B24+2E4jseg023:0BE4 C4 5E 06                          les     bx, [bp+unitGamePtr]                ; Load Full Pointer to ES:xxseg023:0BE7 8A 46 F6                          mov     al, byte ptr [bp+houseRevealed]seg023:0BEA 26 08 47 09                       or      es:[bx+_unitGame.houseRevealed], al ; Logical Inclusive ORseg023:0BEEseg023:0BEE                   Done:                                                       ; CODE XREF: sub_22B24+Fjseg023:0BEE                                                                               ; sub_22B24+63j ...seg023:0BEE 5E                                pop     siseg023:0BEF 8B E5                             mov     sp, bpseg023:0BF1 5D                                pop     bp

Maybe here (the first piece of chunk code) is the key to make hostile AI allied respect other AI not allied.

Posted
Alright...thanks! Last week I started analysis about all difference between two EXE, just to know what to modify and where to make it with hex editing. MrFlibble if you want, I can posted an attached with all documentation about it.
That would actually be very nice if you did that, it would also help new people to quickly find useful information, rather than plough through all the posts in the modding threads. I'd really appreciate it if you summarized the information that is scattered throughout the forums here in a single document.

As for the AT/FR alliance stuff, unfortunately I have no idea. I'm sure you'll figure it out eventually, seeing as how you found out so much about this feature already :)

Posted

I found something very similar to the problem that I described:

 

https://github.com/OpenDUNE/OpenDUNE/issues/100

https://github.com/rofl0r/OpenDUNE/commit/75a5c94bf690e9adb029b9e5acb8be98d039c4ba

When a structure is scouted by houseID, Map_UnveilTile marks the structure's seenByHouses field for AI targetting purposes. When the scouting house is Atreides, Fremen should also gain that knowledge. However, there was an error in commit d085bb3 regarding this special case:

s->o.seenByHouses |= 1 << houseID;
if (s->o.houseID == HOUSE_ATREIDES) s->o.seenByHouses |= 1 << HOUSE_FREMEN;

should instead be:

s->o.seenByHouses |= 1 << houseID;
if (houseID == HOUSE_ATREIDES) s->o.seenByHouses |= 1 << HOUSE_FREMEN;

 

 

It should match this chunk of code:

ovr194:1305 FF 76 08                          push    [bp+HouseID]                        ; HouseIDovr194:1308ovr194:1308                   loc_57818:                                                  ; mapPositionovr194:1308 56                                push    siovr194:1309 0E                                push    csovr194:130A E8 E1 FD                          call    near ptr unitGameGetPtrByMapPos     ; Call Procedureovr194:130D 59                                pop     cxovr194:130E 52                                push    dxovr194:130F 50                                push    ax                                  ; unitGamePtrovr194:1310 9A F4 08 23 22                    call    sub_22B24                           ; Call Procedureovr194:1315ovr194:1315                   loc_57825:                                                  ; Addovr194:1315 83 C4 06                          add     sp, 6ovr194:1318 56                                push    si                                  ; mapPositionovr194:1319 0E                                push    csovr194:131A E8 16 FE                          call    near ptr buildingGameGetPtrByMapPos ; Call Procedureovr194:131D 59                                pop     cxovr194:131E 89 56 FA                          mov     word ptr [bp+buildingGamePtr+2], dxovr194:1321 89 46 F8                          mov     word ptr [bp+buildingGamePtr], axovr194:1324 8B 46 F8                          mov     ax, word ptr [bp+buildingGamePtr]ovr194:1327 0B 46 FA                          or      ax, word ptr [bp+buildingGamePtr+2] ; Logical Inclusive ORovr194:132A 74 1C                             jz      short loc_57858                     ; Jump if Zero (ZF=1)ovr194:132C C4 5E F8                          les     bx, [bp+buildingGamePtr]            ; Load Full Pointer to ES:xxovr194:132F B0 01                             mov     al, 1ovr194:1331 8A 4E 08                          mov     cl, byte ptr [bp+HouseID]ovr194:1334 D2 E0                             shl     al, cl                              ; 1 << houseIDovr194:1336 26 08 47 09                       or      es:[bx+_buildingGame.housesRevealed], al ; Logical Inclusive ORovr194:133A 83 7E 08 01                       cmp     [bp+HouseID], 1                     ; Atrediesovr194:133E 75 08                             jnz     short loc_57858                     ; Jump if Not Zero (ZF=0)ovr194:1340 C4 5E F8                          les     bx, [bp+buildingGamePtr]            ; Load Full Pointer to ES:xxovr194:1343 26 80 4F 09 08                    or      es:[bx+_buildingGame.housesRevealed], 8 ; Logical Inclusive ORovr194:1348ovr194:1348                   loc_57858:                                                  ; CODE XREF: mapGamePieceReveal+C1jovr194:1348                                                                               ; mapGamePieceReveal+D5j

I'll try to change ovr194:133A as advised.

 

EDITED: Yes! Indeed the key of all is:

or      es:[bx+_buildingGame.housesRevealed], 8

In other words, it puts a 1 in bit position regarding Fremen, that is XXXX 1XXX But If you already play Fremen, you must put the 1 in bit position regarding Atreides: XXXX XX1X.

So I think that houseRevealed values is 0000 1010 on starting when you play Atreides with Fremen allied, but it should be the same if you play Fremen with Atreides allied.

 

However I don't know why the operation is completely unilateral, so you must swap ALL Atreides/Fremen ID, including those about isFriendly function, otherwise don't work!

 

P.S. More details in attached documentation upcoming. ;)

Posted

drnovice, something related.  If you can find the isFriendly function, it should look something like this:

 

bool House_AreAllied(uint8 houseID1, uint8 houseID2){        if (houseID1 == HOUSE_INVALID || houseID2 == HOUSE_INVALID) return false;        if (houseID1 == houseID2) return true;        if (houseID1 == HOUSE_FREMEN || houseID2 == HOUSE_FREMEN) {                return (houseID1 == HOUSE_ATREIDES || houseID2 == HOUSE_ATREIDES);        }        return (houseID1 != g_playerHouseID && houseID2 != g_playerHouseID);}

 

Can you spot the bug?

Posted

Yes, the "bug" (if we can call it so) is that this function was designed only to have Atreides human, so it doesn't care to take exception to check the behavior between Atreides AI respect other AI if you should play Fremen.
It's a bit complicate but absolutely logical.
 
Let's analyse the function on 5 cases, assuming that we're playing Atreides (bold is Human, italic is human Ally):
1) if HouseID1 is Fremen and HouseID2 is Atreides -> return true => OK
2) if HouseID1 is Atreides and HouseID2 is Fremen -> return true => OK
3) if HouseID1 is Fremen and HouseID2 is Harkonnen -> return false => OK
4) if HouseID1 is Harkonnen and HouseID2 is Atreides -> return false => OK
5) if HouseID1 is Harkonnen and HouseID2 is Ordos -> return true => OK
 
Recap (bold is Human, italic is human Ally):
1) F <=> A  true
2) A <=> F  true
3) F <=> H  false
4) H <=> A  false
5) H <=> O  true
 
Indeed it's alright, no wrong behaviours.
 
 
Now let's analyse the function on the 5 cases, assuming that we're playing Fremen (bold is Human, italic is human Ally):
1) if HouseID1 is Fremen and HouseID2 is Atreides -> return true => OK
2) if HouseID1 is Atreides and HouseID2 is Fremen -> return true => OK
3) if HouseID1 is Fremen and HouseID2 is Harkonnen -> return false => OK
4) if HouseID1 is Harkonnen and HouseID2 is Atreides -> return true => to FIX
5) if HouseID1 is Harkonnen and HouseID2 is Ordos -> return true => OK
 
Recap (bold is Human, italic is human Ally):
1) F <=> A  true
2) A <=> F  true
3) F <=> H  false
4) H <=> A  true -> to FIX
5) H <=> O  true
 
Here shown why Atreides AI apparently don't work: because Atreides in case 4) see and they are seen by all other Houses as friendly and never as enemy.
Why all this? Because of the missing exception described above.
 
So to fix this part (it's not enough to make bilateral alliance, soon I'll show what else to change over this) just add:
 
bool House_AreAllied(uint8 houseID1, uint8 houseID2)
{
        if (houseID1 == HOUSE_INVALID || houseID2 == HOUSE_INVALID) return false;

        if (houseID1 == houseID2) return true;

        if (houseID1 == HOUSE_FREMEN || houseID2 == HOUSE_FREMEN) {
                return (houseID1 == HOUSE_ATREIDES || houseID2 == HOUSE_ATREIDES);
        }


        if (houseID1 == HOUSE_ATREIDES || houseID2 == HOUSE_ATREIDES) {
                return (houseID1 == HOUSE_FREMEN || houseID2 == HOUSE_FREMEN);
        }


        return (houseID1 != g_playerHouseID && houseID2 != g_playerHouseID);
}

Posted

An extract regarding what I'll publish.
This is asm reference about c++ function described in previous post:

seg023:0F5B                   ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦seg023:0F5Bseg023:0F5B                   ; Attributes: bp-based frameseg023:0F5Bseg023:0F5B                   ; int __cdecl far isFriendly?(int objectHouseID,int HumanHouseID)seg023:0F5B                   isFriendly?     proc far                                    ; CODE XREF: sub_15008+12CPseg023:0F5B                                                                               ; scriptFunctionBuildingGetTarget+65P ...seg023:0F5Bseg023:0F5B                   objectHouseID   = word ptr  6seg023:0F5B                   HumanHouseID    = word ptr  8seg023:0F5Bseg023:0F5B 55                                push    bpseg023:0F5C 8B EC                             mov     bp, spseg023:0F5Eseg023:0F5E                   loc_2318E:seg023:0F5E 8B 56 06                          mov     dx, [bp+objectHouseID]seg023:0F61seg023:0F61                   loc_23191:seg023:0F61 8B 5E 08                          mov     bx, [bp+HumanHouseID]seg023:0F64 83 FA FF                          cmp     dx, 0FFFFh                          ; Compare Two Operandsseg023:0F67seg023:0F67                   loc_23197:                                                  ; Jump if Zero (ZF=1)seg023:0F67 74 05                             jz      short retFalseseg023:0F69seg023:0F69                   loc_23199:                                                  ; Compare Two Operandsseg023:0F69 83 FB FF                          cmp     bx, 0FFFFhseg023:0F6C 75 04                             jnz     short loc_231A2                     ; no human house?seg023:0F6Eseg023:0F6E                   retFalse:                                                   ; CODE XREF: isFriendly?:loc_23197jseg023:0F6E                                                                               ; isFriendly?:notAtreidesj ...seg023:0F6E 33 C0                             xor     ax, ax                              ; Logical Exclusive ORseg023:0F70seg023:0F70                   loc_231A0:                                                  ; CODE XREF: isFriendly?:loc_231D1jseg023:0F70 EB 31                             jmp     short loc_231D3                     ; Jumpseg023:0F72                   ; ---------------------------------------------------------------------------seg023:0F72seg023:0F72                   loc_231A2:                                                  ; CODE XREF: isFriendly?+11jseg023:0F72 3B D3                             cmp     dx, bx                              ; Compare Two Operandsseg023:0F74seg023:0F74                   loc_231A4:                                                  ; Jump if Not Zero (ZF=0)seg023:0F74 75 02                             jnz     short loc_231A8seg023:0F76 EB 26                             jmp     short retTrue                       ; Jumpseg023:0F78                   ; ---------------------------------------------------------------------------seg023:0F78seg023:0F78                   loc_231A8:                                                  ; CODE XREF: isFriendly?:loc_231A4jseg023:0F78 83 FA 03                          cmp     dx, 3                               ; DX = objectseg023:0F7B 74 05                             jz      short isFremen                      ; Jump if Zero (ZF=1)seg023:0F7D 83 FB 03                          cmp     bx, 3                               ; BX = humanseg023:0F80seg023:0F80                   loc_231B0:                                                  ; Jump if Not Zero (ZF=0)seg023:0F80 75 0E                             jnz     short notFremenseg023:0F82seg023:0F82                   isFremen:                                                   ; CODE XREF: isFriendly?+20jseg023:0F82 83 FA 01                          cmp     dx, 1                               ; Compare Two Operandsseg023:0F85seg023:0F85                   loc_231B5:                                                  ; Jump if Zero (ZF=1)seg023:0F85 74 05                             jz      short isAtreidesseg023:0F87seg023:0F87                   loc_231B7:                                                  ; Compare Two Operandsseg023:0F87 83 FB 01                          cmp     bx, 1seg023:0F8Aseg023:0F8A                   loc_231BA:                                                  ; if object is Fremen, and Human is Atreides, Ret Trueseg023:0F8A 75 02                             jnz     short notAtreidesseg023:0F8Cseg023:0F8C                   isAtreides:                                                 ; CODE XREF: isFriendly?:loc_231B5jseg023:0F8C EB 10                             jmp     short retTrue                       ; Jumpseg023:0F8E                   ; ---------------------------------------------------------------------------seg023:0F8Eseg023:0F8E                   notAtreides:                                                ; CODE XREF: isFriendly?:loc_231BAjseg023:0F8E EB DE                             jmp     short retFalse                      ; Jumpseg023:0F90                   ; ---------------------------------------------------------------------------seg023:0F90seg023:0F90                   notFremen:                                                  ; CODE XREF: isFriendly?:loc_231B0jseg023:0F90 3B 16 2C 3A                       cmp     dx, houseHumanID                    ; Compare Two Operandsseg023:0F94seg023:0F94                   loc_231C4:                                                  ; Jump if Zero (ZF=1)seg023:0F94 74 06                             jz      short objectIsHumanseg023:0F96seg023:0F96                   loc_231C6:                                                  ; Compare Two Operandsseg023:0F96 3B 1E 2C 3A                       cmp     bx, houseHumanIDseg023:0F9Aseg023:0F9A                   loc_231CA:                                                  ; if object is not human, and house is not human, ret trueseg023:0F9A 75 02                             jnz     short retTrueseg023:0F9Cseg023:0F9C                   objectIsHuman:                                              ; CODE XREF: isFriendly?:loc_231C4jseg023:0F9C EB D0                             jmp     short retFalse                      ; Jumpseg023:0F9E                   ; ---------------------------------------------------------------------------seg023:0F9Eseg023:0F9E                   retTrue:                                                    ; CODE XREF: isFriendly?+1Bjseg023:0F9E                                                                               ; isFriendly?:isAtreidesj ...seg023:0F9E B8 01 00                          mov     ax, 1seg023:0FA1seg023:0FA1                   loc_231D1:                                                  ; Jumpseg023:0FA1 EB CD                             jmp     short loc_231A0seg023:0FA3                   ; ---------------------------------------------------------------------------seg023:0FA3seg023:0FA3                   loc_231D3:                                                  ; CODE XREF: isFriendly?:loc_231A0jseg023:0FA3 5D                                pop     bpseg023:0FA4seg023:0FA4                   locret_231D4:                                               ; Return Far from Procedureseg023:0FA4 CB                                retfseg023:0FA4                   isFriendly?     endp

Note that HumaHouseID pointer/parameter creates misunderstandings because of the HouseID can be even NOT human, simply it's a 2nd HouseID slot parameter... indeed we have seen above the cases that function can be called, even to check 2 HouseID that it doesn't regard Human.

I choose to remove "HOUSE_INVALID" checks because I think that parameters are always valued when function House_AreAllied (isFriendly? on asm) is called....

 

 

UPDATE: ON NEXT THREAD PAGE.

Posted

[1 of 4] is asm reference about c++ chunk of code:
src/unit.c

hp = House_Get_ByIndex(g_playerHouseID);    ui = &g_table_unitInfo[unit->o.type];    h = House_Get_ByIndex(houseID);    houseIDBit = (1 << houseID);    if (houseID == HOUSE_ATREIDES && unit->o.type != UNIT_SANDWORM) {        houseIDBit |= (1 << HOUSE_FREMEN);    }    if ((unit->o.seenByHouses & houseIDBit) != 0 && h->flags.isAIActive) {        unit->o.seenByHouses |= houseIDBit;        return;    }

This affected about Allied AI Units behaviour against other AI Units.
Here it does Left Shift of 1 to N positions where N is HouseID (0, 1, 2, 3, 4, 5 = H, A, O, F, S, M): 1 << houseID.

Left Shift corresponds to multiply value (1 in this case) by 2 every N times that you have specify in second operand.

Then it does Bitwise OR of -> Left Shift of 1 to 3 positions (Fremen ID) that is 8h (1000 binary).
Bitwise OR put the ones (1) binaries that find in second operator to give them in final result.
example:
  00001110
| 00011000
= 00011110


Changes:
hp = House_Get_ByIndex(g_playerHouseID);
ui = &g_table_unitInfo[unit->o.type];
h = House_Get_ByIndex(houseID);
houseIDBit = (1 << houseID);

if (
(houseID == HOUSE_ATREIDES || houseID == HOUSE_FREMEN) && unit->o.type != UNIT_SANDWORM) {
houseIDBit |= (1 << HOUSE_FREMEN)
+(1 << HOUSE_ATREIDES);
}

if ((unit->o.seenByHouses & houseIDBit) != 0 && h->flags.isAIActive) {
unit->o.seenByHouses |= houseIDBit;
return;
}

 

 

 


[2 of 4] is asm reference about c++ chunk of code:
src/unit.c

if (unit->o.houseID == g_playerHouseID || (unit->o.houseID == HOUSE_FREMEN && g_playerHouseID == HOUSE_ATREIDES)) {        unit->o.seenByHouses = 0xFF;    } else {        unit->o.seenByHouses |= houseIDBit;    }

Here it does check if object is human, or if object is Fremen and human is Atreides, then set to 1111 1111 (FFh) binary the object unit variable.
Else it does Bitwise OR with houseIDBit mask to give the ones to the object unit variable.

Changes:
if (unit->o.houseID == g_playerHouseID || (unit->o.houseID == HOUSE_FREMEN && g_playerHouseID == HOUSE_ATREIDES)

|| (unit->o.houseID == HOUSE_ATREIDES && g_playerHouseID == HOUSE_FREMEN)) {
unit->o.seenByHouses = 0xFF;
} else {
unit->o.seenByHouses |= houseIDBit;
}

 

 

 


[3 of 4] is asm reference about c++ chunk of code:
src/house.c

bool House_AreAllied(uint8 houseID1, uint8 houseID2){    if (houseID1 == HOUSE_INVALID || houseID2 == HOUSE_INVALID) return false;    if (houseID1 == houseID2) return true;    if (houseID1 == HOUSE_FREMEN || houseID2 == HOUSE_FREMEN) {        return (houseID1 == HOUSE_ATREIDES || houseID2 == HOUSE_ATREIDES);    }    return (houseID1 != g_playerHouseID && houseID2 != g_playerHouseID);}

Changes explained some post above.




[4 of 4] is asm reference about c++ chunk of code:
src/map.c

s = Structure_Get_ByPackedTile(packed);    if (s != NULL) {        s->o.seenByHouses |= 1 << houseID;        if (s->o.houseID == HOUSE_ATREIDES) s->o.seenByHouses |= 1 << HOUSE_FREMEN;    }

This affected about Allied AI Units behaviour against other AI Structures.
Here it does Left Shift of 1 to N positions where N is HouseID (0, 1, 2, 3, 4, 5 = H, A, O, F, S, M): 1 << houseID.
Then IF object is Atreides it does Bitwise OR of -> Left Shift of 1 to 3 positions (Fremen ID) that is 8h (1000 binary).

Changes:
s = Structure_Get_ByPackedTile(packed);
if (s != NULL) {
s->o.seenByHouses |= 1 << houseID;
if (s->o.houseID == HOUSE_ATREIDES
|| s->o.houseID == HOUSE_FREMEN) s->o.seenByHouses |= (1 << HOUSE_FREMEN)+(1 << HOUSE_ATREIDES);
}

Posted

That wasn't what I had in mind, but okay.  If you don't have the player playing both Atreides and Fremen, you could always just swap the two around.

 

If you play against Fremen and another non-Atreides house (say Harkonnen), the current logic causes H and F to not be considered allies.  I think this can cause H tanks to run over Fremen.  In Dune 2 eXtended, in one of the final levels, Harkonnen will launch deathhand missiles at the Fremen.

Posted

It could be right, since by background, Fremen & Atreides never can be allied to Harkonnen, even if you have them in same Scenario level against your Human House! :)

 

However I think no, because:

src/unit.c

int16 Unit_GetTargetUnitPriority(Unit *unit, Unit *target){    const UnitInfo *targetInfo;    const UnitInfo *unitInfo;    uint16 distance;    uint16 priority;    if (unit == NULL || target == NULL) return 0;    if (unit == target) return 0;    if (!target->o.flags.s.allocated) return 0;    if ((target->o.seenByHouses & (1 << Unit_GetHouseID(unit))) == 0) return 0;    if (House_AreAllied(Unit_GetHouseID(unit), Unit_GetHouseID(target))) return 0;    unitInfo   = &g_table_unitInfo[unit->o.type];    targetInfo = &g_table_unitInfo[target->o.type];    if (!targetInfo->o.flags.priority) return 0;    if (targetInfo->movementType == MOVEMENT_WINGER) {        if (!unitInfo->o.flags.targetAir) return 0;        if (target->o.houseID == g_playerHouseID && !Map_IsPositionUnveiled(Tile_PackTile(target->o.position))) return 0;    }    if (!Map_IsValidPosition(Tile_PackTile(target->o.position))) return 0;    distance = Tile_GetDistanceRoundedUp(unit->o.position, target->o.position);    if (!Map_IsValidPosition(Tile_PackTile(unit->o.position))) {        if (targetInfo->fireDistance >= distance) return 0;    }    priority = targetInfo->o.priorityTarget + targetInfo->o.priorityBuild;    if (distance != 0) priority = (priority / distance) + 1;    if (priority > 0x7D00) return 0x7D00;    return priority;}

If you play Ordos, and you have against Fremen & Harkonnen in Scenario mission, the check:

 

if ((target->o.seenByHouses & (1 << Unit_GetHouseID(unit))) == 0) return 0;

 

always return 0 if target is Fremen and Unit is Harkonnen, because of o.seenByHouses variable, it's set to FFh (1111 1111 binary) to Fremen ONLY if you play Atreides:

 

if (unit->o.houseID == g_playerHouseID || (unit->o.houseID == HOUSE_FREMEN && g_playerHouseID == HOUSE_ATREIDES)) {
unit->o.seenByHouses = 0xFF;
} else {
unit->o.seenByHouses |= houseIDBit;
}

 

The first check is done before the other check:

 

if (House_AreAllied(Unit_GetHouseID(unit), Unit_GetHouseID(target))) return 0;

 

So if first check isn't 0, then it checks this other one.

 

 

Indeed if we think to Original Dune 2 game, enemy AI when spawning Fremen Troopers by Atreides Palace, always they go against Human Player and other enemy AI Houses never attack them.

 

I'll do some more tests about this...

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...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.