drnovice Posted March 21, 2013 Share Posted March 21, 2013 Maybe Death Hand Missile behaviour is different:src/structure.cvoid Structure_ActivateSpecial(Structure *s){ House *h; if (s == NULL) return; if (s->o.type != STRUCTURE_PALACE) return; h = House_Get_ByIndex(s->o.houseID); if (!h->flags.used) return; switch (g_table_houseInfo[s->o.houseID].specialWeapon) { case HOUSE_WEAPON_MISSLE: { Unit *u; tile32 position; position.s.x = 0xFFFF; position.s.y = 0xFFFF; g_var_38BC++; u = Unit_Create(UNIT_INDEX_INVALID, UNIT_MISSILE_HOUSE, s->o.houseID, position, Tools_Random_256()); g_var_38BC--; g_unitHouseMissile = u; if (u == NULL) break; s->countDown = g_table_houseInfo[s->o.houseID].specialCountDown; if (!h->flags.human) { PoolFindStruct find; find.houseID = HOUSE_INVALID; find.type = 0xFFFF; find.index = 0xFFFF; /* For the AI, try to find the first structure which is not ours, and launch missile to there */ while (true) { Structure *sf; sf = Structure_Find(&find); if (sf == NULL) break; if (House_AreAllied(s->o.houseID, sf->o.houseID)) continue; Unit_LaunchHouseMissile(Tile_PackTile(sf->o.position)); return; } /* We failed to find a target, so remove the missile */ Unit_Free(u); g_unitHouseMissile = NULL; return; }[...]There is only check:if (House_AreAllied(s->o.houseID, sf->o.houseID)) continue; and before should do the same that we have seen previous post about Targets.Indeed in original game it's not expected to have a Fremen base.I think that it's possible to fix it on C++, on EXE must look about room bytes. :) Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 21, 2013 Share Posted March 21, 2013 Testing in-game about dynasty report, actually sometimes AI (depends what structure it finds first) launches Death Hand Missile against Fremen structures (on my modified EXE, even or Atreides structures, because of new exception that I added for bilateral alliance).I tried playing Mercenary, since their ID is the last (05), enemy AI find first ID 03 (Fremen) structures to target by Death Hand Missile. There is no room bytes to add code in DeathHand creation chunk of code, so I simply swapped macro-checks in isFriendly? function: bool House_AreAllied(uint8 houseID1, uint8 houseID2){ if (houseID1 == HOUSE_INVALID || houseID2 == HOUSE_INVALID) return false; if (houseID1 == houseID2) return true; // Human Check is made BEFORE than other exceptions if (houseID1 != g_playerHouseID && houseID2 != g_playerHouseID) 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 false;} In yellow check that it's positioned BEFORE the Fremen/Atreides & Atreides/Fremen exceptions, so we can fix dynasty reported "bug". ;)I've updated previous posts. EDITED: DISCARD CHANGES -> WRONG Quote Link to comment Share on other sites More sharing options...
MrFlibble Posted March 21, 2013 Author Share Posted March 21, 2013 drnovice, awesome progress! I'll take a closer look when I'm not this sleepy :D Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 21, 2013 Share Posted March 21, 2013 It's only thanks to all of you if I have learned and discovered all these things ;) Quote Link to comment Share on other sites More sharing options...
MrFlibble Posted March 21, 2013 Author Share Posted March 21, 2013 Wouldn't do for me to get all the credit, without segra's database I'd be near helpless in many things. He did a very thorough job looking through the code, identifying most of the functions - basically, all the groundwork without which any understanding of the game would hardly be possible.Also the OpenDUNE guys did a truly great job, although I personally never read their code for modding purposes but TrueBrain helped me with several issues I wouldn't have figured out myself.And let's not forget Nyerguds' excellent tool which simplifies a lot of things. And whatever information I provided to Nyer to base the early versions of the editor on was discovered by using the older "cheat program" (basically an EXE editor for v1.0 only) written by a Jens Defendorf (you can still get it here: D2CHT10.ZIP). Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 21, 2013 Share Posted March 21, 2013 Yes indeed "all of you" means all guys that you have mentioned including yourself of course.Each one of you guys has contributed to discovered very essential things about modding to this timeless game. :) I would like to see again segra at work on asm code debugging... :) I've found C++ OpenDune code very readable and handy to undestand some particular strange operations about original code.Thanks to TrueBrain and other guys on OpenDune project. Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 22, 2013 Share Posted March 22, 2013 Now talking about which I consider a real bug on Saboteur movement.https://github.com/OpenDUNE/OpenDUNE/issues/138The issue is that he detonates the explosion on some tiles if movement is faster (depending to game speed and terrain type) than ciclying of funtion:bool Unit_Move(Unit *unit, uint16 distance){ const UnitInfo *ui; uint16 d; uint16 packed; tile32 newPosition; bool ret; tile32 currentDestination; bool isSpiceBloom = false; bool isSpecialBloom = false; [...] ret = (unit->distanceToDestination < distance || distance < 16) ? true : false; if (ret) { if (ui->flags.isBullet) { [...] } else if (ui->flags.isGroundUnit) { [...] if (unit->o.type == UNIT_SABOTEUR && (Map_GetLandscapeType(Tile_PackTile(newPosition)) == LST_WALL || (unit->targetMove != 0 && Tile_GetDistance(unit->o.position, Tools_Index_GetTile(unit->targetMove)) < 32))) { Map_MakeExplosion(4, newPosition, 500, 0); Unit_Free(unit); return true; } [...]I don't like personally to use an unit that after you do "Move" command, you always set "Stop" command before it arrives on destination to avoid that it explodes...I remember that Amiga version of Dune 2, Saboteur never exploded on free tiles, so I think this is the right behaviour anyway.To fix this bug, I simply changed jge check to jmp unconditional:seg031:06FE loc_28A5E: ; CODE XREF: unitMoveMapTileCheck:loc_2...seg031:06FE ; unitMoveMapTileCheck+6DBjseg031:06FE C4 5E 06 les bx, [bp+pUnitGamePtr] ; Load Full Pointer to ES:xxseg031:0701 26 80 7F 02 06 cmp es:[bx+_unitGame.typeIndex], 6 ; Saboteurseg031:0706 75 73 jnz short loc_28ADB ; Jump if Not Zero (ZF=0)seg031:0708 C4 5E 06 les bx, [bp+pUnitGamePtr] ; Load Full Pointer to ES:xxseg031:070B 26 83 7F 56 00 cmp es:[bx+_unitGame.scriptObjectHolding], 0 ; Compare Two Operandsseg031:0710 74 4E jz short loc_28AC0 ; Jump if Zero (ZF=1)seg031:0712seg031:0712 loc_28A72: ; Load Full Pointer to ES:xxseg031:0712 C4 5E 06 les bx, [bp+pUnitGamePtr]seg031:0715 26 FF 77 56 push es:[bx+_unitGame.scriptObjectHolding] ; objectIndexTypeseg031:0719 9A C2 01 80 24 call scriptObjectGetMapTileXY ; Call Procedureseg031:071E 59 pop cxseg031:071F 52 push dx ; buildingPosYseg031:0720 50 push ax ; buildingPosXseg031:0721 C4 5E 06 les bx, [bp+pUnitGamePtr] ; Load Full Pointer to ES:xxseg031:0724 26 FF 77 0C push word ptr es:[bx+0Ch] ; unitPosYseg031:0728 26 FF 77 0A push word ptr es:[bx+0Ah] ; unitPosXseg031:072C 9A B4 00 48 1D call distanceCalculate ; Call Procedureseg031:0731seg031:0731 loc_28A91: ; Addseg031:0731 83 C4 08 add sp, 8seg031:0734 3D 20 00 cmp ax, 20h ; ' ' ; Compare Two Operandsseg031:0737 7D 27 jge short loc_28AC0 ; Jump if Greater or Equal (SF=OF)seg031:0737 EB 27 jmp short loc_28AC0 ; Jump seg031:0739seg031:0739 loc_28A99: ; CODE XREF: unitMoveMapTileCheck+76Djseg031:0739 33 C0 xor ax, ax ; Logical Exclusive ORseg031:073B 50 push ax ; objectTypeIndexseg031:073C B8 F4 01 mov ax, 1F4hseg031:073Fseg031:073F loc_28A9F: ; HitPointsMaxseg031:073F 50 push axseg031:0740 FF 76 FC push [bp+unitPosY] ; unitPosYseg031:0743 FF 76 FA push [bp+unitPosX] ; unitPosXseg031:0746 B8 04 00 mov ax, 4seg031:0749 50 push ax ; intseg031:074A 9A 08 00 00 15 call sub_15008 ; Call Procedureseg031:074F 83 C4 0A add sp, 0Ah ; Addseg031:0752 FF 76 08 push word ptr [bp+pUnitGamePtr+2]seg031:0755 FF 76 06 push word ptr [bp+pUnitGamePtr] ; unitGamePtrseg031:0758 9A 68 05 ED 1D call unitGameDestroy ; Call Procedureseg031:075D E9 98 F9 jmp loc_28458 ; Jumpseg031:0760 ; ---------------------------------------------------------------------------seg031:0760seg031:0760 loc_28AC0: ; CODE XREF: unitMoveMapTileCheck+704jseg031:0760 ; unitMoveMapTileCheck+72Bjseg031:0760 FF 76 FC push [bp+unitPosY] ; posYseg031:0763 FF 76 FA push [bp+unitPosX] ; posX 20h corresponds to 32 decimal, value looked in C++ function.I think so the Saboteur is handier and useful. ;) Quote Link to comment Share on other sites More sharing options...
dynasty Posted March 22, 2013 Share Posted March 22, 2013 It definately is possible for non-Atreides AI tanks to crush supposedly allied Fremen infantry. It takes some setting up in the original game, but it could become common if Fremen is a major house. Death Hand targetting logic simply goes by index rather than by house. You see the problem in Dune 2 eXtended, but not Super Dune II Classic, when playing against the same houses. Your new logic isn't any better:g_playerHouseID = A;House_AreAllied(H, F) -> true;g_playerHouseID = F;House_AreAllied(H, A) -> true;g_playerHouseID = H;House_AreAllied(S, A) -> false; Try to implement something like this:bool House_AreAllied(uint8 houseID1, uint8 houseID2){ uint8 playerHouse = g_playerHouseID; if (playerHouse == HOUSE_FREMEN) playerHouse = HOUSE_ATREIDES; if (houseID1 == HOUSE_FREMEN) houseID1 = HOUSE_ATREIDES; if (houseID2 == HOUSE_FREMEN) houseID2 = HOUSE_ATREIDES; return ((houseID1 == playerHouse) == (houseID2 == playerHouse));} Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 22, 2013 Share Posted March 22, 2013 Yes, you're right. I don't have done enought testing.I'll test it, maybe there is enough room bytes to make that you described. :) Quote Link to comment Share on other sites More sharing options...
MrFlibble Posted March 22, 2013 Author Share Posted March 22, 2013 Yes indeed "all of you" means all guys that you have mentioned including yourself of course.Each one of you guys has contributed to discovered very essential things about modding to this timeless game. :)Uhh, silly me, I misread your post somehow as "thanks to you for all" or something :-/ That's what happens when you are sleepy :D Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 @dynasty: your function it's smart and simple. ;)The last check it's absolutely cool and ingenious, it isn't so banal to think and find out: return ((houseID1 == playerHouse) == (houseID2 == playerHouse)); If there was enough room bytes, teorically you could create a series of exceptions for all factions on same EXE: if (playerHouse == HOUSE_FREMEN) playerHouse = HOUSE_ATREIDES; if (houseID1 == HOUSE_FREMEN) houseID1 = HOUSE_ATREIDES; if (houseID2 == HOUSE_FREMEN) houseID2 = HOUSE_ATREIDES; if (playerHouse == HOUSE_MERCENARY) playerHouse = HOUSE_ORDOS; if (houseID1 == HOUSE_MERCENARY) houseID1 = HOUSE_ORDOS; if (houseID2 == HOUSE_MERCENARY) houseID2 = HOUSE_ORDOS; if (playerHouse == HOUSE_SARDAUKAR) playerHouse = HOUSE_HARKONNEN; if (houseID1 == HOUSE_SARDAUKAR) houseID1 = HOUSE_HARKONNEN; if (houseID2 == HOUSE_SARDAUKAR) houseID2 = HOUSE_HARKONNEN; For example assuming a classic dual alliance between all 6 factions.Unfortunately there is not enough room bytes in EXE for all these cases.However by tests done it seems there are no side effects on solution suggest by dynasty. Today I post all fixed asm. :) Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Translating on asm this modified function (1 of 4): 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; } Because of too little room bytes available on this step, I had to fix it using CX register instead pointer regards houseIndex being CL already valued on that ID: seg023:0912 loc_22B42:seg023:0912 89 46 F8 mov word ptr [bp+houseGamePtr], axseg023:0915 B8 01 00 mov ax, 1seg023:0915 B0 01 mov al, 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:091F C4 5E 06 les bx, [bp+unitGamePtr] ; Load Full Pointer to ES:xxseg023:0922 83 F9 03 cmp cx, 3 ; Compare Two Operandsseg023:0925 74 0C jz short loc_22B60 ; Jump if Not Zero (ZF=0)seg023:0927 83 F9 01 cmp cx, 1 ; Compare Two Operandsseg023:092A 75 0B jnz short notAtreOrWorm seg023: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:0933 83 4E F6 0A or [bp+houseRevealed], 0Ahseg023: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:xxSo I had to work a bit on registers (AL instead AX for example) to gain more bytes room.0Ah value instead 08 is for the bilateral Atre-Fre and Fre-Atre right behaviours (Logical OR of 1010 binary instead only 1000). Release: v1.07-EU - Address: near 0x0177A0Search for: b8 0100 8a 4e 0a d3 e0 89 46 f6 83 7e 0a 01 75 0e c45e 06 26 80 7f 02 19 74 04 83 4e f6 08 c4 5e 06Replace with: b0 018a 4e 0a d3 e0 89 46 f6 c4 5e 06 83 f9 03 74 0c83 f9 01 75 0b 26 80 7f 02 19 74 04 83 4e f6 0a Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Translating on asm this modified function (2 of 4): 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; } I removed some les (Load Full Pointer to ES:xx) instruction since it isn't really necessary being loaded once at the beginning (seg023:0BBB): 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 38 3A cmp ax, houseHumanID ; Compare Two Operandsseg023:0BC7 74 11 jz short AtreFre ; Jump if Zero (ZF=1)seg023:0BC7 74 16 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 38 3A 01 cmp houseHumanID, 1 ; Atreseg023:0BD8 75 0A jnz short loc_22E14 ; Jump if Not Zero (ZF=0)seg023:0BC9 loc_22DF9: seg023:0BC9 3C 03 cmp al, 3 ; object Fremenseg023:0BCB 75 07 jnz short checkFriend2 ; Jump if Not Zero (ZF=0)seg023:0BCD 83 3E 38 3A 01 cmp houseHumanID, 1 ; human Atreseg023:0BD2 74 0B jz short AtreFre ; Jump if Not Zero (ZF=0)seg023:0BD4seg023:0BD4 checkFriend2: seg023:0BD4 3C 01 cmp al, 1 ; object Atreidesseg023:0BD6 75 0E jnz short loc_22E14 ; Jump if Not Zero (ZF=0)seg023:0BD8 83 3E 38 3A 03 cmp houseHumanID, 3 ; human Fremenseg023:0BDD 75 07 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 EB 08 jmp short Done ; Jumpseg023:0BE4 ; ---------------------------------------------------------------------------seg023:0BE4.seg023: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:0BE6 90 nop ; No Operationseg023: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 Using altready valued AL register we can save more bytes room doing cmp to check Atre-Fre & Fre-Atre exceptions.No Operation byte it's a filler to doesn't mess the rest of code. Release: v1.07-EU - Address: near 0x017A60Search for: 11 c4 5e 06 26 80 7f 08 03 75 11 83 3e 38 3a01 75 0a c4 5e 06 26 c6 47 09 ff eb 0a c4 5e 06Replace with: 16 3c 03 75 07 83 3e 38 3a 01 74 0b 3c 01 750e 83 3e 38 3a 03 75 08 26 c6 47 09 ff eb 08 90 Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Translating on asm this modified function (3 of 4): 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); uint8 playerHouse = g_playerHouseID; if (playerHouse == HOUSE_FREMEN) playerHouse = HOUSE_ATREIDES; if (houseID1 == HOUSE_FREMEN) houseID1 = HOUSE_ATREIDES; if (houseID2 == HOUSE_FREMEN) houseID2 = HOUSE_ATREIDES; return ((houseID1 == playerHouse) == (houseID2 == playerHouse));} As suggested dynasty these new checks have a bilateral effect that works on Atre-Fre side and even Fre-Atre side.I had to replace completely chunk of code: seg023: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:0F61seg023:0F61 SetHumanHouse:seg023:0F61 A1 38 3A mov ax, houseHumanIDseg023: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:0F72seg023:0F72 SetFriend1: ; CODE XREF: isFriendly?+11jseg023:0F72 3D 03 00 cmp ax, 3 ; Compare Two Operandsseg023:0F7B 75 03 jnz short SetFriend2 ; Jump if Not Zero (ZF=0)seg023:0F9E B8 01 00 mov ax, 1seg023:0F72seg023:0F72 SetFriend2:seg023:0F78 83 FA 03 cmp dx, 3 ; DX = objectHouseID1seg023:0F7B 75 03 jnz short SetFriend3 ; Jump if Not Zero (ZF=0)seg023:0F9E BA 01 00 mov dx, 1seg023:0F72seg023:0F72 SetFriend3: seg023:0F78 83 FB 03 cmp bx, 3 ; BX = objectHouseID2seg023:0F7B 75 03 jnz short CheckFriend1 ; Jump if Not Zero (ZF=0)seg023:0F9E BB 01 00 mov bx, 1seg023:0F72seg023:0F72 CheckFriend1:seg023:0F72 3B C2 cmp ax, dx ; Compare Two Operandsseg023:0F7B 75 05 jnz short Res1False ; Jump if Not Zero (ZF=0)seg023:0F9E BA 01 00 mov dx, 1seg023:0F70 EB 03 jmp short CheckFriend2 ; Jumpseg023:0F72seg023:0F72 Res1False:seg023:0F9E BA 02 00 mov dx, 2seg023:0F72seg023:0F72 CheckFriend2:seg023:0F72 3B C3 cmp ax, bx ; Compare Two Operandsseg023:0F7B 75 05 jnz short Res2False ; Jump if Not Zero (ZF=0)seg023:0F9E BB 01 00 mov bx, 1seg023:0F70 EB 03 jmp short LastCheck ; Jumpseg023:0F72seg023:0F72 Res2False:seg023:0F9E BB 02 00 mov bx, 2seg023:0F72seg023:0F72 LastCheck: ; CODE XREF: isFriendly?+11jseg023:0F72 3B D3 cmp dx, bx ; Compare Two Operandsseg023:0F74 75 05 jnz short retFalseseg023:0F9Eseg023:0F9E retTrue: ; CODE XREF: isFriendly?+1Bjseg023:0F9E ; isFriendly?:isAtreidesj ...seg023:0F9E B8 01 00 mov ax, 1seg023:0FA1 EB 02 jmp short Doneseg023:0F6Eseg023:0F6E retFalse: ; CODE XREF: isFriendly?:loc_23197jseg023:0F6E ; isFriendly?:notAtreidesj ...seg023:0F6E 33 C0 xor ax, ax seg023:0FA3 ; ---------------------------------------------------------------------------seg023:0FA3seg023:0FA3 loc_231D3: ; CODE XREF: isFriendly?:loc_231A0jseg023:0FA3 5D pop bp Using AX register I valued global houseHumanID variable and I have done all requested checks.LastCheck tests on DX & BX registers that I valued to 1 if true or 2 if false. ;) You might choose other values to represent true or false, the important thing is that they are equal to represent true or false values. Release: v1.07-EU - Address: near 0x017DF0Search for: 83 fa ff74 05 83 fb ff 75 04 33 c0 eb 31 3b d3 75 02 eb26 83 fa 03 74 05 83 fb 03 75 0e 83 fa 01 74 0583 fb 01 75 02 eb 10 eb de 3b 16 38 3a 74 06 3b1e 38 3a 75 02 eb d0 b8 01 00 eb cdReplace with: a1 38 3a3d 03 00 75 03 b8 01 00 83 fa 03 75 03 ba 01 0083 fb 03 75 03 bb 01 00 3b c2 75 05 ba 01 00 eb03 ba 02 00 3b c3 75 05 bb 01 00 eb 03 bb 02 003b d3 75 05 b8 01 00 eb 03 33 c0 90 Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Translating on asm this modified function (4 of 4): 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); } I thought to remove notNull check to free room bytes, apparently it doesn't have any side effects, but if we do some more tests it's better: ovr194: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:1335 83 7E 08 03 cmp [bp+HouseID], 3 ; Fremenovr194:1339 74 08 jz short AtreOrFrem ; Jump if Zero (ZF=1)ovr194: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:133F 75 07 jnz short notAtreOrFre ; Jump if Not Zero (ZF=0)ovr194:1341 90 90 nop ; No Operationsovr194:1343ovr194:1343 AtreOrFrem: ; CODE XREF: mapGamePieceReveal+C1jovr194:1343 26 80 4F 09 08 or es:[bx+_buildingGame.housesRevealed], 8 ; Logical Inclusive ORovr194:1343 26 80 4F 09 0A or es:[bx+_buildingGame.housesRevealed], 0Ah ; Logical Inclusive ORovr194:1348ovr194:1348 loc_57858: ; CODE XREF: mapGamePieceReveal+C1jovr194:1348 Also in this case there was the possibility to use valued CL register to do cmp to save two room bytes, but added to two 90 nopED, it didn't give the 5 bytes useful to leave notNull check at the beginning that I removed.Again the Logical OR is made on 0Ah value instead 08 to use bilateral Atre-Fre & Fre-Atre mask (1010 binary instead only 1000). Release: v1.07-EU - Address: near 0x04CC20Search for: 0b 46 fa 74 1c c4 5e f8 b001 8a 4e 08 d2 e0 26 08 47 09 83 7e 08 01 75 08c4 5e f8 26 80 4f 09 08Replace with: c4 5e f8 b0 01 8a 4e 08 d2e0 26 08 47 09 83 7e 08 03 74 08 83 7e 08 01 7507 90 90 26 80 4f 09 0a Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Doing exactly all these steps we can have definitively a bilateral alliance between 2 Houses.I make examples about Atre-Fre & Fre-Atre alliance, but it's possible make what we would like just changing NUMBERS on compare (cmp) checks on HouseIDs. ;)I invite all of you to do some other tests because maybe I did something wrong, so we can fix it if necessary. MrFlibble, moreover I successfully changed Sardaukar Trooper "trike explosion" to "foot units dead", so no more side effect about run over them and cause damage on vehicles (assuming the presence of explosive equipment, but it's not like Dune Background).Later I'll post workaround about it. :) Including "Sabouter Tile Detonation Fix" (previous thread page), we should have fixed the major issues about modding, right?What else? Quote Link to comment Share on other sites More sharing options...
MrFlibble Posted March 24, 2013 Author Share Posted March 24, 2013 drnovice, once again, excellent work! Or should I say, super awesome excellent work, as you're dealing with this issues very professionally. Nice to see such dedicated approach :DDoing exactly all these steps we can have definitively a bilateral alliance between 2 Houses.I make examples about Atre-Fre & Fre-Atre alliance, but it's possible make what we would like just changing NUMBERS on compare (cmp) checks on HouseIDs. ;)I invite all of you to do some other tests because maybe I did something wrong, so we can fix it if necessary.Once again I don't have the time to carefully look through all your code analysis, but am I right that what you have posted means we can have an alliance that works both ways within the same EXE? No more "allies" who just stand there and do nothing, right? MrFlibble, moreover I successfully changed Sardaukar Trooper "trike explosion" to "foot units dead", so no more side effect about run over them and cause damage on vehicles (assuming the presence of explosive equipment, but it's not like Dune Background).Later I'll post workaround about it. :)Great, thanks a lot!There are lots of deviations from the original books already though, and the Sardaukar are described as fanatically loyal to the Emperor, so perhaps the explosive effect could be retained, albeit with a different animation?Including "Sabouter Tile Detonation Fix" (previous thread page), we should have fixed the major issues about modding, right?What else?You've fixed the saboteurs' accidental detonation? Did I miss that? If you have, that's uber awesome, no less ^_^Once again, sorry I don't have the time to properly study and appreciate all your work right now, but at any rate, what you're doing is an immeasurable contribution to the Dune II modding community. Thanks! Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 24, 2013 Share Posted March 24, 2013 Once again I don't have the time to carefully look through all your code analysis, but am I right that what you have posted means we can have an alliance that works both ways within the same EXE? No more "allies" who just stand there and do nothing, right?Exactly. No problem if you don't have much time, you can take a look anytime. Great, thanks a lot!There are lots of deviations from the original books already though, and the Sardaukar are described as fanatically loyal to the Emperor, so perhaps the explosive effect could be retained, albeit with a different animation?Maybe but you should change somewhere even on EXE file, because UNIT.EMC calls some sub-rutines marked on EXE, that regards explosion animation dependig type of units and what it calls.I just decompile original UNIT.EMC within DUNE.PAK, changing the calls of the sub-rutines (using DST_1.2): [Trooper]PushReg 0Push 10Evaluate EqualIfNotGoto l1617Execute StopMovePush 30Push 4Push 0Execute RandomNumberAddSP 2PushOp 0Evaluate AddExecute PlaySFXAddSP 1PushReg 1Push 255Evaluate NotEqualIfNotGoto l1616Execute sub_279ABl1616:Execute Destroyl1617:PushOp 1Goto l1363Pop (Return) I took sub_279AB (manages foot units death animation) and put it on Raider Trike: [RaiderTrike]PushReg 0Push 10Evaluate EqualIfNotGoto l2102Execute StopMovePushReg 1Push 255Evaluate NotEqualIfNotGoto l2100Push 10Execute sub_26A69Execute sub_279ABAddSP 1l2100:Execute DestroyedMessageExecute Destroyl2102:PushOp 1Goto l1363Pop (Return) Then recompile the TXT and repack DUNE.PAK with new UNIT.EMC. You can research these "sub_xxxxx" on segra db.If you don't want alter DUNE.PAK to keep original Dune 2 gameplaying, you can pack UNIT.EMC into your EXPAND.PAK archive and then define where DUNEX.EXE takes it with Nyerguds' editor on "Files" section. :) You've fixed the saboteurs' accidental detonation? Did I miss that? If you have, that's uber awesome, no less ^_^Once again, sorry I don't have the time to properly study and appreciate all your work right now, but at any rate, what you're doing is an immeasurable contribution to the Dune II modding community. Thanks!Yes, take a look on previous page. ;) 1 Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 25, 2013 Share Posted March 25, 2013 On my tests I also noticed that a pre-placed Raffinery don't have spice storage capacity limit anymore, so yo can storage much more than what you may have regularly (ie 1000 Credits per Raffinery or Silos). Quote Link to comment Share on other sites More sharing options...
dynasty Posted March 25, 2013 Share Posted March 25, 2013 There are lots of deviations from the original books already though, and the Sardaukar are described as fanatically loyal to the Emperor, so perhaps the explosive effect could be retained, albeit with a different animation?I thought I already fixed this in the "Dune II editor with 1.07 support" thread. It was a single byte change, so no recompiling really required.You've fixed the saboteurs' accidental detonation? Did I miss that? If you have, that's uber awesome, no less ^_^Yes, take a look on previous page. ;)As I described elsewhere, the detonation depends on both terrain and game speed. On normal speed, the saboteur will almost always detonate when reaching the destination. As far as I can tell, this was the intended behaviour. I don't know about the Amiga version though. I think your change will make it impossible for to saboteur to explode on units. For Dune II, you probably have to pick between saboteurs that are easy to control but can't explode on units, or saboteurs that will detonate wherever they stop. BTW, consider changing the call to Unit_Free below to Unit_Remove. This has to do with the "trace" that saboteurs leave behind after "random" detonation. You can see both issues here: https://github.com/OpenDUNE/OpenDUNE/issues/138 1 Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 25, 2013 Share Posted March 25, 2013 I thought I already fixed this in the "Dune II editor with 1.07 support" thread. It was a single byte change, so no recompiling really required.Sorry I can't find it in forum threads. Can you post here the link? As I described elsewhere, the detonation depends on both terrain and game speed. On normal speed, the saboteur will almost always detonate when reaching the destination. As far as I can tell, this was the intended behaviour. I don't know about the Amiga version though.I think your change will make it impossible for to saboteur to explode on units. For Dune II, you probably have to pick between saboteurs that are easy to control but can't explode on units, or saboteurs that will detonate wherever they stop.Yes it's a 'de gustibus' argument.Do you prefer to detonate always your saboter when you must move him somewhere even if you haven't yet a real target?I prefer detonate him when I looking for a main enemy structure.Then you could always put saboteur below a Tank and wait that enemy shoot against it, saboteur will explode after a while. :) BTW, consider changing the call to Unit_Free below to Unit_Remove. This has to do with the "trace" that saboteurs leave behind after "random" detonation.You can see both issues here:https://github.com/O...DUNE/issues/138You're right, there is another matter about exploded tiles that can't be used anyway after it.I was considering whether it could be an advantage to those who detonates the saboteur, or if it is really an annoying thing. Quote Link to comment Share on other sites More sharing options...
MrFlibble Posted March 25, 2013 Author Share Posted March 25, 2013 As I described elsewhere, the detonation depends on both terrain and game speed. On normal speed, the saboteur will almost always detonate when reaching the destination. As far as I can tell, this was the intended behaviour. I don't know about the Amiga version though.Hmm, I never considered the possibility of this having been intended behaviour really. Then again, it is my understanding that at some point in the development, the player wasn't supposed to control the saboteur anyway, as it would belong to the allied Mercenary faction (as is the case in the SMD version of the game). Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 25, 2013 Share Posted March 25, 2013 If for SMD you mean Sega Mega Drive, I don't know this version, but I remember perfectly that Saboteur in Amiga Version doesn't detonate on free tiles anyway.Since that default Sabouter command is "Sabotage" and CPU doesn't change this, of course "Move" command it's suitable to Human player, and on PC original version it's very impratical. Quote Link to comment Share on other sites More sharing options...
drnovice Posted March 26, 2013 Share Posted March 26, 2013 I uploaded a test by WinUAE with AmigaOS & WHDLoad for Dune 2 Amiga version. Sorry for bad quality sound... @dynasty: do you like it? ;) 1 Quote Link to comment Share on other sites More sharing options...
dynasty Posted March 27, 2013 Share Posted March 27, 2013 Sorry I can't find it in forum threads. Can you post here the link?dune2x sardaukar trooper explosion change: http://forum.dune2k.com/topic/19114-dune-2-dune-ii-editor-with-107-support/?p=377807 @dynasty: do you like it? ;)Looks better to use than saboteurs that explode all the time. They might have reworked the detonation behaviour in the Amiga version. Still, I couldn't resolve the weird Tile_GetDistance call in any other way. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.