1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Modding Civilization I - Patterns for Huts and Special Resources

Discussion in 'Civ1 - General Discussions' started by Gowron, Oct 17, 2009.

  1. Gowron

    Gowron Chieftain

    Joined:
    May 21, 2007
    Messages:
    62
    Modifying the map is fun, but it's even more fun if you can also alter the patterns which govern the placement of huts and special resources in the map :)

    The following article contains code and data addresses, both of which will only be correct for the uncompressed civ.exe version 1, as described here.


    The Special Resources Pattern

    As many players will have noticed, the special resources patterns on different maps look similar and often are the same. The pattern is determined by a special number, the so-called resource seed. Depending on the seed, there are 16 different possible patterns.
    The resource seed of a running game can be found inside the RAM at position 0x40FB0.

    But there's more ingredients. Each square has a horizontal index, the x coordinate, and a vertical index, the y coordinate. Both are used to determine if a square will contain a special resource or not.

    And finally, there's a complex formula which reads the seed and the coordinates and tells the game whether a given square is a special resource square or not. Since it's not easy to rewrite the whole formula, I'll propose a relatively easy way to do limited changes by changing two constants inside the formula. This only requires a hex editor.

    The first constant is 13 by default (0x0D in hex code) and can be found at position 0x1F016. The second constant, 11 by default (0x0B) is found at position 0x1F024. Changing the constants will change the look of the special resources pattern. The change may be more or less distinct, depending on which values you choose.

    Of course, you can also go ahead and rewrite the whole formula, but be aware that some basic knowledge of the x86 assembler language is required.

    Here's the relevant code chunk:
    Code:
    seg012:1828                 push    bp                          
    seg012:1829                 mov     bp, sp
    seg012:182B                 sub     sp, 2
    seg012:182E                 cmp     [bp+arg_4], 1     // check if y coordinate is smaller than 2
    seg012:1832                 jle     short loc_2C88A
    seg012:1834                 cmp     [bp+arg_4], 30h   // check if y coordinate is greater than 47
    seg012:1838                 jl      short loc_2C88E
    seg012:183A                 sub     ax, ax
    seg012:183C                 jmp     short loc_2C8D2
    
    seg012:183E                 mov     ax, [bp+arg_2]    // load x coordinate
    seg012:1841                 sar     ax, 1             // divide by 2
    seg012:1843                 sar     ax, 1             // divide by 2
    seg012:1845                 mov     cx, 0Dh
    seg012:1848                 imul    cx                // multiply by 13
    seg012:184A                 mov     cx, ax
    
    seg012:184C                 mov     ax, [bp+arg_4]    // load y coordinate
    seg012:184F                 sar     ax, 1             // divide by 2
    seg012:1851                 sar     ax, 1             // divide by 2
    seg012:1853                 mov     bx, 0Bh           
    seg012:1856                 imul    bx                // multiply by 11
    
    seg012:1858                 add     cx, ax            // add both results
    seg012:185A                 add     cx, word_40FB0    // add resource seed
    seg012:185E                 mov     [bp+var_2], cx    // save result (first value)
    
    seg012:1861                 mov     ax, [bp+arg_2]    // load x coordinate
    seg012:1864                 and     ax, 3             // reduce it modulo 4
    seg012:1867                 shl     ax, 1             // multiply by 2
    seg012:1869                 shl     ax, 1             // multiply by 2
    seg012:186B                 mov     cx, [bp+arg_4]    // load y coordinate
    seg012:186E                 and     cx, 3             // reduce it modulo 4
    
    seg012:1871                 add     ax, cx            // add both results (second value)
    
    seg012:1873                 mov     cl, byte ptr [bp+var_2]  // load first value
    seg012:1876                 sub     ch, ch
    seg012:1878                 and     cx, 0Fh           // reduce it modulo 16
    seg012:187B                 cmp     ax, cx            // compare the result to the second value
    seg012:187D                 jnz     short loc_2C88A   // if both are the same, the square is a special resource square
    seg012:187F                 mov     ax, 1
    seg012:1882                 mov     sp, bp
    seg012:1884                 pop     bp
    seg012:1885                 retf
    


    The Huts Pattern

    The huts pattern is very similar to the special resources pattern.

    Again, there are two constants which allow for limited changes (it's even the same constants), the first one (13=0x0D by default) at position 0x1F08B, and the second one (11=0x0B by default) at position 0x1F099.

    Also, the same resource seed is used.

    And finally, here's the relevant code chunk for hut locations:
    Code:
    seg012:1886                 push    bp
    seg012:1887                 mov     bp, sp
    seg012:1889                 sub     sp, 2
    seg012:188C                 push    si
    seg012:188D                 cmp     [bp+arg_0], 0Ah
    seg012:1891                 jz      short loc_2C8FF
    seg012:1893                 mov     ax, 32h
    seg012:1896                 imul    [bp+arg_2]
    seg012:1899                 mov     si, ax
    seg012:189B                 mov     bx, [bp+arg_4]    // load y coordinate
    seg012:189E                 test    byte ptr [bx+si+7FF8h], 1
    seg012:18A3                 jnz     short loc_2C8FF
    seg012:18A5                 cmp     bx, 1             // check if it's smaller than 2
    seg012:18A8                 jle     short loc_2C8FF
    seg012:18AA                 cmp     bx, 30h           // check if it's greater than 47
    seg012:18AD                 jl      short loc_2C903
    seg012:18AF                 sub     ax, ax
    seg012:18B1                 jmp     short loc_2C95B
    
    seg012:18B3                 mov     ax, [bp+arg_2]    // load x coordinate
    seg012:18B6                 sar     ax, 1             // divide by 2
    seg012:18B8                 sar     ax, 1             // divide by 2
    seg012:18BA                 mov     cx, 0Dh
    seg012:18BD                 imul    cx                // multiply by 13
    seg012:18BF                 mov     cx, ax
    
    seg012:18C1                 mov     ax, [bp+arg_4]    // load y coordinate
    seg012:18C4                 sar     ax, 1             // divide by 2
    seg012:18C6                 sar     ax, 1             // divide by 2
    seg012:18C8                 mov     bx, 0Bh
    seg012:18CB                 imul    bx                // multiply by 11
    
    seg012:18CD                 add     cx, ax            // add both results
    seg012:18CF                 add     cx, word_40FB0    // add resource seed
    seg012:18D3                 add     cx, 8             // add 8
    seg012:18D6                 mov     [bp+var_2], cx    // save result
    
    seg012:18D9                 mov     ax, [bp+arg_2]    // load x coordinate
    seg012:18DC                 and     ax, 3             // reduce it modulo 4
    seg012:18DF                 shl     ax, 1             // multiply by 2
    seg012:18E1                 shl     ax, 1             // multiply by 2
    seg012:18E3                 mov     cx, [bp+arg_4]    // load y coordinate
    seg012:18E6                 and     cx, 3             // reduce it modulo 4
    
    seg012:18E9                 add     ax, cx            // add both results
    
    seg012:18EB                 mov     cl, byte ptr [bp+var_2]  // load first value
    seg012:18EE                 sub     ch, ch            
    seg012:18F0                 and     cx, 1Fh           // reduce it modulo 32
    seg012:18F3                 cmp     ax, cx            // compare the result to the second value
    seg012:18F5                 jnz     short loc_2C8FF   // if both are the same, a hut is placed on the square
    seg012:18F7                 push    [bp+arg_4]
    seg012:18FA                 push    [bp+arg_2]
    seg012:18FD                 push    cs
    seg012:18FE                 call    near ptr sub_2C5C7
    seg012:1901                 add     sp, 4
    seg012:1904                 test    al, 1
    seg012:1906                 jnz     short loc_2C8FF
    seg012:1908                 mov     ax, 1
    seg012:190B                 pop     si
    seg012:190C                 mov     sp, bp
    seg012:190E                 pop     bp
    seg012:190F                 ret
    

    Note that not much has changed in Civilization II, see here:
    http://apolyton.net/forums/showthread.php?t=68481
     
  2. Dack

    Dack Terra Form Moderator

    Joined:
    Nov 26, 2003
    Messages:
    532
    Location:
    civ dos 474.05
    I found your research into this fascinating. In my own program TerraForm I could not deduce the formula for the Minor Tribes or as commonly known Huts. I was left with the alternative of producing tables for the location of the huts.
    Terraform post 117
    Terraform post 120

    Using your posted code; if the following are equal then there you will have a hut.
    [((x \ 4) * &HD) + ((y \ 4) * &HB) + TerrainMasterWord + 8] and &H1F&
    = (x And 3) * 4 + (y And 3)

    I haven’t incorporated this into my code but with a test program I see that I have a few errors in my hut location table.

    A few questions:
    What are you using to de-compile the CIV code?
    Have you tried code view or something similar to step thru the running code?

    I’m wondering if the layout on the SVE file is the same in memory as appears in it’s file.

    Getting people to tinker with the EXE using a hex editor( Freeware Hex Editor XVI32 ) might be difficult. I assume that most CIV DOS users would prefer a program that would manipulate the data or in this case the EXE. Then of course what version of CIV one should support. In my opinion support for version .01 and .05 are definite choices. Version .01 because of the cheat factor (Shift-56). Some like it but for me the bugs outweigh the advantages. The lost civilization bug makes version .01 worthless for me.

    Anyway to the point of all this rambling. I have modified CIVMAP to work within DOSBOX ( CIVMAP21 revisited ). It seems a perfect platform for your idea for modification or manipulation of the placement of the huts and special resource squares. CIVMAP is already coded to allow map, terrain improvements and special resource squares placement.

    One could zap those pesky barbarians.
     
  3. Gowron

    Gowron Chieftain

    Joined:
    May 21, 2007
    Messages:
    62
    I did not decompile the code, I merely disassembled it using IDA. I did not use any debuggers either.

    I doubt that. At least the earth map looked totally different in the RAM than it looked in the file. In the RAM, it was easy to recognize, while in the file it looked very cryptic.
     
  4. Tristan_C

    Tristan_C Emperor

    Joined:
    Aug 16, 2006
    Messages:
    1,712
    While the Resources form an easy-to-recognize pattern on the map (to the point that when you find a group of them you can deduce the locations of all hidden ones, particularly those concealed by Grassland which you can turn into Forest), it seems to me the Huts have nothing of the sort. No visible pattern.


    Are barbs more likely to spawn on a landmass with a Hut?
     
  5. Dack

    Dack Terra Form Moderator

    Joined:
    Nov 26, 2003
    Messages:
    532
    Location:
    civ dos 474.05
    To quote myself
    if the following is equal then there you will have a hut.
    [((x \ 4) * &HD) + ((y \ 4) * &HB) + TerrainMasterWord + 8] and &H1F& = (x And 3) * 4 + (y And 3)


    Yes there is a pattern but not readily apparent.
     
  6. Tristan_C

    Tristan_C Emperor

    Joined:
    Aug 16, 2006
    Messages:
    1,712
    Yes, I did read the thread, and I realize that I sound like an idiot barging in here and saying that there's "no visible pattern" after you gave the algorithm in x86. I was just saying that the huts are too difficult for me to sight out, whereas the resources are extremely easy.
     
  7. Dack

    Dack Terra Form Moderator

    Joined:
    Nov 26, 2003
    Messages:
    532
    Location:
    civ dos 474.05

    Myself an idiot also. I could never figure it out and hard coded all of the possibilities into TerraForm. "no visible pattern” is certainly the appropriate statement.
     
  8. Adamos

    Adamos Chieftain

    Joined:
    Jan 29, 2011
    Messages:
    9
    Location:
    Havířov, Czech republic
    i played with the formula, made an simple simulation in excel, my suggestion:

    you can see in excel file a sample of pattern

    i can't test it, cause i uncompressed exe file i am not able to run. I somebody wants to break a law and send me 475.01 version which works for Gowron, you are welcomed at Adam.Podstavka@gmail.com . (and if this note is against rules of forum, please edit it, or let me know, thx)

    hell, Gowron, how did you inserted that Code window? with uniwidth text...
     

    Attached Files:

  9. Adamos

    Adamos Chieftain

    Joined:
    Jan 29, 2011
    Messages:
    9
    Location:
    Havířov, Czech republic
    well, i made it :) My pattern works quite well i think. It should work on every version of CIV DOS.
    Just open CIV.EXE in some hexa editor, find this chunk of code:

    D1F8 D1F8 B90D 00F7 E98B C88B 460A D1F8 D1F8 BB0B
    00F7 EB03 C803 0E80 6E89 4EFE 8B46 0825 0300 D1E0
    D1E0 8B4E 0A83 E103 03C1 8A4E FE2A ED83 E10F 3BC1

    and replace by this:
    D1F8 D1F8 D1F8 B903 00F7 E98B C88B 460A D1F8 D1F8
    BB01 00F7 EB03 C803 0E80 6E89 4EFE 8B46 0825 0300
    D1E0 8B4E 0A83 E103 03C1 8A4E FE2A ED83 E108 3BC1

    formulas, which decides, whether a square content a special resource - if sides are equal:
    constants (bolded in code above in their order)
    A = first constatn value (orig 13, my 3)
    B = second constant value (orig 11, my 1 or 2)

    original formula:
    ((x div 4)*A + (y div 4)*B + Seed) mod 16 = (x mod 4)*4 + (y mod 4)

    my new formula is:
    ((x div 8)*A + (y div 4)*B + Seed) mod 8 = (x mod 4)*2 + (y mod 4)

    there are just 5 changes, now i find it more "randomous behaving", which was my goal :)

    you cannot see the differencies in TerraForm, cause it calculates positions of special resources with original formula. So i place screenshots from testing in random new game here. First is with B=1, second with B=2. It affects also saved games, cause .sve nor .map file does't contain information abou specials.
     

    Attached Files:

  10. enneagon

    enneagon Chieftain

    Joined:
    Apr 16, 2011
    Messages:
    18
    Location:
    Latvia
    WOW!!!
    :woohoo:

    That something I dreamed about 17 years!!!

    Can You make the formula and parameters in a way, that one combination leads to world with damn meny resurce&huts, but anoder - for very rarely resurce&huts?
     
  11. hannurabi

    hannurabi Warlord

    Joined:
    Aug 29, 2005
    Messages:
    173
    I once reversed the formula so that most of the tiles were special resources.Game experience was crazy as you can imagine:lol: I don't have the exe anymore but you only have to change this instruction
    to other jump instruction that will set the tile to bonus resource tile. Maybe JMP instruction would make every tile bonus tile, I'm not sure.
     
  12. Bussunda

    Bussunda Chieftain

    Joined:
    Jul 27, 2011
    Messages:
    10
    Location:
    PANTANAL - BRASIL
    is an algorithm
    difficult
    to create the general matrix
    programming
     
  13. Tristan_C

    Tristan_C Emperor

    Joined:
    Aug 16, 2006
    Messages:
    1,712
    A storm of posts
    threads erupt from long-forgotten strata
    as white glass washed on the night-shrouded shores

    A cowherd will cull yearlings
    shouting "Haw!" just so
     
  14. axx

    axx Chieftain

    Joined:
    Feb 19, 2011
    Messages:
    99
    excavated from the depths
    years in running, problems remain
    Mar someone a piece of the task,
    which requires knowing binary arithmetic?
     

Share This Page