Jump to content
drnovice

Hex Editing Collection on EXE

Recommended Posts

I've published on this Thread a Collection of ALL hex editing discussions about Dune 2 EXE.

I've collected from all topics regards Dune 2 Hex Editing, researches for bugs fixed and game customizing.

All the infos have been sorted and cataloged, within URL link reference and a short explanation regards the modify.

All Documents are in PDF format. Only v1.07-EU supported.

I hope that this will serve to Dune 2 fans to reach better what they would like looking for and understand more clearly about Hex Editing. :)

A special Thanks is for MrFlibble about forum support and many suggestions, Nyerguds about his wonderful EXE editor, Segra about his IDA db research that has permitted to recognized many steps on functions that regulates game playing of Dune 2.

Again many Thanks to all users that have contributed with them posts to make possibile all this Collection. :)

Main topics:

  • Full Bilateral Alliance between two factions (when play as Atreides or as Fremen for example)
  • Fix Conquest Map Vanishing House bug
  • Fix Concrete Slabs bug
  • Fix remap colours of House IX
  • Fix Loop Reinforcements
  • Remove Decay Structures built on concrete slabs
  • Increase limit number of units that Sandworms can swallow
  • Fix GUI of Units Menu that 'loses' focus on selected unit (11/04/2013)
  • Fix use of Timeout Key on INI Scenario files as victory condition (21/04/2013)
  • Fix: Saboteur no more detonates with Move command (29/04/2013)
  • Fix: capturing structures with deviated units did not unlock tech (03/05/2013)
  • Fix: Windtrap power information incorrect after capturing a Windtrap (03/05/2013)
  • Fix: Radar scan double-counted some units and missed others (03/06/2013) - CORRECTION
  • Change Sandworm best target behaviour to avoid attacking Fremen Warrior/Warriors (03/06/2013)
Last Update: 03/06/2013

Dune 2 v1.07-EU - Hex Editing PDF Collection.zip

P.S. Bytes opcodes can be a bit different between v1.07-EU and segra's IDA db, because of db is obtained from a different version.

  • Upvote 1

Share this post


Link to post
Share on other sites

Yes I didn't see on this forum discussions about these changes, we can update the Collection every time we find out a solution about new stuff (hex editing or by c++ functions).

Share this post


Link to post
Share on other sites

drnovice, thanks for your marvellous efforts yet again!

dynasty, your input is highly appreciated! If you see other things that need to be mentioned, don't hesitate to post them here! (e.g. I didn't even know the things in your post above are fixable :))

Share this post


Link to post
Share on other sites

@dynasty: I saw fixes about your reports, but I don't understand how they work...

However if you want that I find this code in opcode EXE, by segra's db IDA, I can try looking for them. :)

Share this post


Link to post
Share on other sites

2 documents added to the collection: how to set count number for Sandworm swallowed units and the fix about 'lost' focus of selected units by GUI units menu. :)

  • Upvote 1

Share this post


Link to post
Share on other sites

Cool, nice progress! And as always, thanks for your hard work! :D

Share this post


Link to post
Share on other sites

MrFlibble I could give you a release for DuneX with fix about Sardaukar troops and other. ;)

Share this post


Link to post
Share on other sites

Another update: added the fix to victory condition of Timeout Key on INI Scenario file. :)

 

Here it's explained the workaround.

  • Upvote 1

Share this post


Link to post
Share on other sites

For the timeout, the code needs to be:

finish = (g_timerGame - g_tickScenarioStart >= mapSettingTimeout)

because the game timer is not reset to 0 at any stage.  Otherwise, the timeout condition will trigger prematurely in all but for the first level you play when starting up the game. Because Dune II doesn't check for victory/defeat in the first two minutes of a level, we need to test with 3 minutes. Create a survival scenario using:

  • Timeout=10800 (3 min * 60 sec/min * 60 ticks/sec)
  • WinFlags=11
  • LoseFlags=9
  • start scenario, wait 3 minutes -> win.
  • exit Dune II, and start it up again.
  • start scenario, wait 1 minute, restart scenario, wait 2 minutes -> win.  Wrong!

Share this post


Link to post
Share on other sites

Thanks for explaination. :)
I'm looking c++ code only recently, and I don't know still all about these variables... btw should be enough room on EXE (since I've nopED some bytes) to get subtraction in opcode: http://forum.dune2k.com/topic/18875-dune-2-exe-editing-programming-issues/page-25#entry380308
 
I saw why first 2 minutes the game don't checks about end condition:

if (g_timerGame - g_tickScenarioStart < 7200) return false;

 
The correct variable in c++ code should be g_scenario.timeOut:

/* Check for reaching timeout */    if (!win && (g_scenario.loseFlags & 0x8) != 0) {        win = (g_timerGame - g_tickScenarioStart  >= g_scenario.timeOut);    }

mapSettingTimeout is the name that segra write into opcode. :)

 

 

EDITED: I tested about it and now it works. I've updated Attached Collection file.

Share this post


Link to post
Share on other sites

Correction of Radar unit count fix, and added how to change Sandworm 'best target' behaviour to avoid attacking Fremen Warriors. ;)

On this page the explaination.

  • Upvote 2

Share this post


Link to post
Share on other sites

I was wondering, would it be possible to track down and fix the bugs related to building repair? I have no idea if they are related or not, but the effects are as follows:

  • Repairs in v1.07 cost much less than the formula suggests, because of numbers being rounded up.
  • Structures that have more than 500 hit points get repaired for free (this results in free repairs for the Palace).

Share this post


Link to post
Share on other sites

The v1.07 repair cost formula (cost per tick, which is up to 5hp) is:

 
    repairCost = ((2 * 256 / si->o.hitpoints) * si->o.buildCredits + 128) / 256;
 
Whereas the v1.0 repair formula appears to be:
 
    repairCost = ((10 * 256 / si->o.hitpoints) * si->o.buildCredits + 128) / 256;
 
"Appears to be" because I didn't locate it in the binary
(I haven't tried, but I'd love to have this verified).
 
The divisions here round down, so the repair cost for structures with
greater than 512 hitpoints becomes free.  The "+ 128" bit is just for
rounding up.
 
The OpenDUNE code is in the commit linked below (search for 0x2000,
emu_Math_ValueToPercent, emu_Math_PercentToValue).  You probably could
just invert the order of emu_Math_ValueToPercent and
emu_Math_PercentToValue to get something decent, but the repair cost
for the other structures might change do to rounding.
 
 
  • Upvote 2

Share this post


Link to post
Share on other sites

Here the assembly:

 

seg007:0315
seg007:0315                   loc_17AC5:                                                  ; CODE XREF: gameHandleBuildings:loc_17AC0j
seg007:0315 B8 02 00                          mov     ax, 2
seg007:0318 50                                push    ax
seg007:0319
seg007:0319                   loc_17AC9:                                                  ; Load Full Pointer to ES:xx
seg007:0319 C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:031D
seg007:031D                   loc_17ACD:
seg007:031D 26 FF 77 10                       push    es:[bx+_buildingData.HitPoints]
seg007:0321
seg007:0321                   loc_17AD1:                                                  ; Call Procedure
seg007:0321 9A 2A 00 C4 42                    call    j_unknownCalc
seg007:0326 59                                pop     cx
seg007:0327 59                                pop     cx
seg007:0328 8B F0                             mov     si, ax
seg007:032A 56                                push    si
seg007:032B
seg007:032B                   loc_17ADB:                                                  ; Load Full Pointer to ES:xx
seg007:032B C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:032F 26 FF 77 16                       push    es:[bx+_buildingData.Cost]
seg007:0333
seg007:0333                   loc_17AE3:                                                  ; Call Procedure
seg007:0333 9A 20 00 C4 42                    call    j_unknownCalc2
seg007:0338
seg007:0338                   loc_17AE8:
seg007:0338 59                                pop     cx
seg007:0339 59                                pop     cx
seg007:033A
seg007:033A                   loc_17AEA:
seg007:033A 8B F0                             mov     si, ax
seg007:033C
seg007:033C                   loc_17AEC:                                                  ; Load Full Pointer to ES:xx
seg007:033C C4 1E 3E 39                       les     bx, houseGamePtrCurrent
seg007:0340
seg007:0340                   loc_17AF0:                                                  ; Compare Two Operands
seg007:0340 26 39 77 12                       cmp     es:[bx+_houseGame.credits], si
seg007:0344 72 60                             jb      short loc_17B56                     ; Jump if Below (CF=1)
seg007:0346
seg007:0346                   loc_17AF6:                                                  ; Load Full Pointer to ES:xx
seg007:0346 C4 1E 3E 39                       les     bx, houseGamePtrCurrent
seg007:034A 26 29 77 12                       sub     es:[bx+_houseGame.credits], si      ; Integer Subtraction
seg007:034E C4 1E C0 84                       les     bx, buildingGamePtrCurrent          ; Load Full Pointer to ES:xx
seg007:0352
seg007:0352                   loc_17B02:
seg007:0352 26 8A 47 08                       mov     al, es:[bx+_buildingGame.houseID]
seg007:0356
seg007:0356                   loc_17B06:                                                  ; AL -> AX (with sign)
seg007:0356 98                                cbw
seg007:0357 3B 06 2C 3A                       cmp     ax, houseHumanID                    ; Compare Two Operands
seg007:035B
seg007:035B                   loc_17B0B:                                                  ; Jump if Zero (ZF=1)
seg007:035B 74 12                             jz      short buildingRepairMore
seg007:035D
seg007:035D                   loc_17B0D:                                                  ; Compare Two Operands
seg007:035D 83 3E A6 38 03                    cmp     missionNumberPrevious, 3
seg007:0362 7D 0B                             jge     short buildingRepairMore            ; Jump if Greater or Equal (SF=OF)
seg007:0364
seg007:0364                   loc_17B14:                                                  ; Load Full Pointer to ES:xx
seg007:0364 C4 1E C0 84                       les     bx, buildingGamePtrCurrent
seg007:0368 26 83 47 0E 03                    add     es:[bx+_buildingGame.HitPoints], 3  ; Add
seg007:036D
seg007:036D                   loc_17B1D:                                                  ; Jump
seg007:036D EB 09                             jmp     short loc_17B28
seg007:036F                   ; ---------------------------------------------------------------------------
seg007:036F
seg007:036F                   buildingRepairMore:                                         ; CODE XREF: gameHandleBuildings:loc_17B0Bj
seg007:036F                                                                               ; gameHandleBuildings+35Bj
seg007:036F C4 1E C0 84                       les     bx, buildingGamePtrCurrent          ; Load Full Pointer to ES:xx
seg007:0373 26 83 47 0E 05                    add     es:[bx+_buildingGame.HitPoints], 5  ; Add
seg007:0378
seg007:0378                   loc_17B28:                                                  ; CODE XREF: gameHandleBuildings:loc_17B1Dj
seg007:0378 C4 1E C0 84                       les     bx, buildingGamePtrCurrent          ; Load Full Pointer to ES:xx
seg007:037C
seg007:037C                   loc_17B2C:
seg007:037C 26 8B 47 0E                       mov     ax, es:[bx+_buildingGame.HitPoints]
seg007:0380
seg007:0380                   loc_17B30:                                                  ; Load Full Pointer to ES:xx
seg007:0380 C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:0384
seg007:0384                   loc_17B34:                                                  ; Compare Two Operands
seg007:0384 26 3B 47 10                       cmp     ax, es:[bx+_buildingData.HitPoints]
seg007:0388
seg007:0388                   loc_17B38:                                                  ; Jump if Less or Equal (ZF=1 | SF!=OF)
seg007:0388 7E 1A                             jle     short loc_17B54
seg007:038A
seg007:038A                   loc_17B3A:                                                  ; Load Full Pointer to ES:xx
seg007:038A C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:038E 26 8B 47 10                       mov     ax, es:[bx+_buildingData.HitPoints]
seg007:0392 C4 1E C0 84                       les     bx, buildingGamePtrCurrent          ; Load Full Pointer to ES:xx
seg007:0396
seg007:0396                   loc_17B46:
seg007:0396 26 89 47 0E                       mov     es:[bx+_buildingGame.HitPoints], ax

 

The functions j_unknownCalc and j_unknownCalc2 make the expression showed by dynasty:

 

ovr191:0155                   ; int __cdecl far unknownCalc(int max,int current)
ovr191:0155                   unknownCalc     proc far                                    ; CODE XREF: j_unknownCalcJ
ovr191:0155
ovr191:0155                   var_2           = word ptr -2
ovr191:0155                   max             = word ptr  6
ovr191:0155                   current         = word ptr  8
ovr191:0155
ovr191:0155 55                                push    bp
ovr191:0156 8B EC                             mov     bp, sp
ovr191:0158 83 EC 02                          sub     sp, 2                               ; Integer Subtraction
ovr191:015B
ovr191:015B                   loc_557AB:
ovr191:015B 8B 46 08                          mov     ax, [bp+current]
ovr191:015E 32 F6                             xor     dh, dh                              ; Logical Exclusive OR
ovr191:0160 8A D4                             mov     dl, ah
ovr191:0162
ovr191:0162                   loc_557B2:
ovr191:0162 8A E0                             mov     ah, al
ovr191:0164 32 C0                             xor     al, al                              ; Logical Exclusive OR
ovr191:0166 8B 5E 06                          mov     bx, [bp+max]
ovr191:0169
ovr191:0169                   loc_557B9:                                                  ; CODE XREF: unknownCalc+28j
ovr191:0169 83 FA 00                          cmp     dx, 0                               ; Compare Two Operands
ovr191:016C 74 11                             jz      short loc_557CF                     ; Jump if Zero (ZF=1)
ovr191:016E 05 01 00                          add     ax, 1                               ; Add
ovr191:0171 83 D2 00                          adc     dx, 0                               ; Add with Carry
ovr191:0174 D1 EA                             shr     dx, 1                               ; Shift Logical Right
ovr191:0176
ovr191:0176                   loc_557C6:                                                  ; Rotate Through Carry Right
ovr191:0176 D1 D8                             rcr     ax, 1
ovr191:0178 83 C3 01                          add     bx, 1                               ; Add
ovr191:017B D1 EB                             shr     bx, 1                               ; Shift Logical Right
ovr191:017D EB EA                             jmp     short loc_557B9                     ; Jump
ovr191:017F                   ; ---------------------------------------------------------------------------
ovr191:017F
ovr191:017F                   loc_557CF:                                                  ; CODE XREF: unknownCalc+17j
ovr191:017F C7 46 FE FF FF                    mov     [bp+var_2], 0FFFFh
ovr191:0184 83 FB 00                          cmp     bx, 0                               ; Compare Two Operands
ovr191:0187
ovr191:0187                   loc_557D7:                                                  ; Jump if Zero (ZF=1)
ovr191:0187 74 05                             jz      short loc_557DE
ovr191:0189 F7 F3                             div     bx                                  ; Unsigned Divide
ovr191:018B 89 46 FE                          mov     [bp+var_2], ax
ovr191:018E
ovr191:018E                   loc_557DE:                                                  ; CODE XREF: unknownCalc:loc_557D7j
ovr191:018E 8B 46 FE                          mov     ax, [bp+var_2]
ovr191:0191 EB 00                             jmp     short $+2                           ; Jump
ovr191:0193 8B E5                             mov     sp, bp
ovr191:0195 5D                                pop     bp
ovr191:0196
ovr191:0196                   locret_557E6:                                               ; Return Far from Procedure
ovr191:0196 CB                                retf
ovr191:0196                   unknownCalc     endp

 

and

 

ovr191:0129                   ; int __cdecl far unknownCalc2(int multiplyer,int)
ovr191:0129                   unknownCalc2    proc far                                    ; CODE XREF: j_unknownCalc2J
ovr191:0129
ovr191:0129                   var_2           = word ptr -2
ovr191:0129                   multiplyer      = word ptr  6
ovr191:0129                   pM              = word ptr  8
ovr191:0129
ovr191:0129 55                                push    bp                                  ; 46db:0129
ovr191:012A 8B EC                             mov     bp, sp
ovr191:012C 83 EC 02                          sub     sp, 2                               ; Integer Subtraction
ovr191:012F 8B 56 06                          mov     dx, [bp+multiplyer]
ovr191:0132 8B 46 08                          mov     ax, [bp+pM]
ovr191:0135 F7 E2                             mul     dx                                  ; Unsigned Multiplication of AL or AX
ovr191:0137 05 80 00                          add     ax, 80h                             ; Add
ovr191:013A 83 D2 00                          adc     dx, 0                               ; Add with Carry
ovr191:013D
ovr191:013D                   loc_5578D:
ovr191:013D 8A C4                             mov     al, ah
ovr191:013F
ovr191:013F                   loc_5578F:
ovr191:013F 8A E2                             mov     ah, dl
ovr191:0141 80 FE 00                          cmp     dh, 0                               ; Compare Two Operands
ovr191:0144 74 03                             jz      short loc_55799                     ; Jump if Zero (ZF=1)
ovr191:0146 B8 FF FF                          mov     ax, 0FFFFh                          ; was overflow in ax
ovr191:0149
ovr191:0149                   loc_55799:                                                  ; CODE XREF: unknownCalc2+1Bj
ovr191:0149 89 46 FE                          mov     [bp+var_2], ax
ovr191:014C
ovr191:014C                   loc_5579C:
ovr191:014C 8B 46 FE                          mov     ax, [bp+var_2]
ovr191:014F
ovr191:014F                   loc_5579F:                                                  ; Jump
ovr191:014F EB 00                             jmp     short $+2
ovr191:0151 8B E5                             mov     sp, bp
ovr191:0153 5D                                pop     bp
ovr191:0154
ovr191:0154                   locret_557A4:                                               ; Return Far from Procedure
ovr191:0154 CB                                retf
ovr191:0154                   unknownCalc2    endp

 

  • Upvote 1

Share this post


Link to post
Share on other sites

So, how would you like to fix the bug about 512+ HP structures repair?

I saw on OpenDune source code that it's fixed so:

repairCost = si->o.buildCredits * 2 / si->o.hitpoints;

Maybe it could be possibile have enough room for bytes.

Share this post


Link to post
Share on other sites

The v1.07 repair cost formula (cost per tick, which is up to 5hp) is:

 

    repairCost = ((2 * 256 / si->o.hitpoints) * si->o.buildCredits + 128) / 256;

 

Whereas the v1.0 repair formula appears to be:

 

    repairCost = ((10 * 256 / si->o.hitpoints) * si->o.buildCredits + 128) / 256;

 

"Appears to be" because I didn't locate it in the binary

(I haven't tried, but I'd love to have this verified).

[...]

Yes I disassembled by IDA Pro even v1.0 and the expression is that showed, with the 10 instead 2 ;)

Share this post


Link to post
Share on other sites

Yes I disassembled by IDA Pro even v1.0 and the expression is that showed, with the 10 instead 2 ;)

Cool, thanks!

 

So, how would you like to fix the bug about 512+ HP structures repair?

I saw on OpenDune source code that it's fixed so:

repairCost = si->o.buildCredits * 2 / si->o.hitpoints;
Maybe it could be possibile have enough room for bytes.

I don't like this formula much. In v1.07, the repair costs per tick for each structure work out to be:

0, if palace5, if heavy factory or repair facility1, if barracks or turret2, everything else
Using the OpenDUNE formula, the repair costs change like this:

+1, for palace+2, for repair factory+1, for heavy factory, windtrap, and barracks-1, for refinery and outpost
The heavy factory and repair facility changes seem quite significant since the AI likes to target them.

You might as well just do:

if (heavy factory || repair facility) cost = 5;else if (turret || barracks) cost = 1else cost = 2;
Hopefully that fits.

Share this post


Link to post
Share on other sites

I think it should affect the relationship between hp and cost of every structure, indipendently to the fixed values that we saw on original game.

e.g. CY have relation to 1:1 (400 hp and 400 [pseudo]cost) so it could be 1 as repair cost.

If we have a relation to 1:2 (near Windtrap) the repair cost would be 2 or 1:3 (as Heavy Factory) the repair cost would be 5 and so on...

 

A general formula could be:

repairCost = (si->o.buildCredits * 5) / (si->o.hitpoints * 3);

Since it could expect a structure that have a relation 2:1 (hp : cost) and the repair cost would be 0 for free!

Share this post


Link to post
Share on other sites
I don't think you can actually divide by the hitpoints, which is why

they go through the whole * 256 / hitpoints, * cost / 256 thing.

 

If you don't care about keeping the repair cost of the other

structures the same, then inverting the order of

emu_Math_ValueToPercent and emu_Math_PercentToValue

seems like the easiest thing to do.

  • Upvote 1

Share this post


Link to post
Share on other sites

emu_Math_ValueToPercent & emu_Math_PercentToValue are unknownCalc & unknownCalc2 in asm?

Why I can't divide by the hp? I try with dosbox debugger:

e.g. Repair Facility:

mov ax,2BCh  ; 700 costmov bx,5mul bxmov si,axmov ax,C8h   ; 200 hpmov bx,3mul bxmov di,axmov ax,sidiv di

return AX=5

 

another example, with a hypothetical structure having hp=500 and cost=299:

mov ax,12Bh  ; 299 costmov bx,5mul bxmov si,axmov ax,1F4h  ; 500 hpmov bx,3mul bxmov di,axmov ax,sidiv di

return AX=0 as well.

Share this post


Link to post
Share on other sites

The change about my formula if anyone would like to try:

 

seg007:0315                   loc_17AC5:                                                  ; CODE XREF: gameHandleBuildings:loc_17AC0j
seg007:0315 B8 02 00                          mov     ax, 2
seg007:0318 50                                push    ax
seg007:0319
seg007:0319                   loc_17AC9:                                                  ; Load Full Pointer to ES:xx
seg007:0319 C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:031D
seg007:031D                   loc_17ACD:
seg007:031D 26 FF 77 10                       push    es:[bx+_buildingData.HitPoints]
seg007:0321
seg007:0321                   loc_17AD1:                                                  ; Call Procedure
seg007:0321 9A 2A 00 C4 42                    call    j_unknownCalc
seg007:0326 59                                pop     cx
seg007:0327 59                                pop     cx
seg007:0328 8B F0                             mov     si, ax
seg007:032A 56                                push    si
seg007:032B
seg007:032B                   loc_17ADB:                                                  ; Load Full Pointer to ES:xx
seg007:032B C4 1E BC 84                       les     bx, buildingDataPtrCurrent
seg007:032F 26 FF 77 16                       push    es:[bx+_buildingData.Cost]
seg007:0333
seg007:0333                   loc_17AE3:                                                  ; Call Procedure
seg007:0333 9A 20 00 C4 42                    call    j_unknownCalc2
seg007:0338
seg007:0338                   loc_17AE8:
seg007:0338 59                                pop     cx
seg007:0339 59                                pop     cx

seg007:0315 C4 1E 30 84                       les     bx, buildingDataPtrCurrent
seg007:0319 26 8B 47 10                       mov     ax, es:[bx+_buildingData.HitPoints]
seg007:031D B9 03 00                          mov     cx, 3
seg007:0320 F7 E1                             mul     cx                                  ; Unsigned Multiplication of AL or AX
seg007:0322 90 90 90 90 90 90                 nop                                         ; No Operations
seg007:0328 8B F0                             mov     si, ax
seg007:032A 26 8B 47 16                       mov     ax, es:[bx+_buildingData.Cost]
seg007:032E B9 05 00                          mov     cx, 5
seg007:0331 F7 E1                             mul     cx                                  ; Unsigned Multiplication of AL or AX
seg007:0333 F7 F6                             div     si                                  ; Unsigned Divide
seg007:0335 90 90 90 90 90                    nop                                         ; No Operations

seg007:033A
seg007:033A                   loc_17AEA:
seg007:033A 8B F0                             mov     si, ax

 

 

Search for:
               b8 02 00 50 c4 1e 30 84 26 ff 77
10 9a 2a 00 ca 32 59 59 8b f0 56 c4 1e 30 84 26
ff 77 16 9a 20 00 ca 32 59 59 8b f0


Replace with:
               c4 1e 30 84 26 8b 47 10 b9 03 00
f7 e1 90 90 90 90 90 90 8b f0 26 8b 47 16 b9 05
00 f7 e1 f7 f6 90 90 90 90 90 8b f0

 

 

I tested the cost on Mission 9:

  • Palace: 1 per tick (5hp)
  • Repair Facility: 5 per tick
  • R-Turret: 2 per tick
  • CY: 1 per tick
  • Windtrap: 2 per tick
  • Upvote 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


×