[GUIDE] Adding new random map options

Discussion in 'Modding' started by Ebel, Dec 19, 2016.

  1. Ebel

    Ebel Moderator Staff Member

    [​IMG]
    Will try to explain what is needed to add custom options to the random map mode in this guide. As an example let's add new 'additional options' for the diplomatic center: default - no diplomatic center - expensive mercenaries.

    3 things are needed :
    1) the actual code that makes the options work (scripts) ,
    2) making the options appear in the interface (gui) and
    3) localisation for the languages.

    Notes:
    - You can name the new option whatever you want, as long as you use the same name everywhere. I used .limitdiplo in the example, you may as well call it .banana. But one typo and it won't work.
    - Line numbers below are indicators, these can change as gsc patches files.



    1. Let's add entries to make this new option work.

    1.1
    Let's start by defining the names which we will use in all the files. Go to
    data\script\dmscript.global and add:

    Code:
    Line 1020 +
       gc_mapsettings_limitdiplo_default = 0;
       gc_mapsettings_limitdiplo_nodiplo = 1;
       gc_mapsettings_limitdiplo_expensivemercs = 2;
    
    Add a new value aswell for the price modifier for mercenaries which we'll use later on in the player.script
    Code:
       gc_gameplay_expensivemercskoef = 3;
    
    1.2 Next, add the new limitdiplo to data\scripts\lib\classes.script

    Line 46 +
    Code:
       limitdiplo: Integer;
    
    1.3 Next, go to data\scripts\lib\player.script :

    Find the cannons options somewhere around line 2664+ . Make sure the following matches the column of the option above (cannons). This states that if the diplo option isn't default then, 2 cases: no diplo or expensive mercs. In the case of no diplo, if the object usage is dipcenter then bproduceenabled is false, and in the case of expensive mercs, if the object is a bmercenary then multiply the price by the given value we put in dmscript.global above.
    Code:
       if (gMap.settings.additional.limitdiplo<>gc_mapsettings_limitdiplo_default) then
       begin
          for pl:=0 to gc_MaxPlayerCount-1 do
          begin
             for cid:=0 to gc_MaxCountryCount-1 do
             for id:=0 to gc_country_maxmembers-1 do
             begin
                pobjbase := gPlayer[pl].objbase[cid][id];
                pobjprop := gObjProp[cid][id];
                case gMap.settings.additional.limitdiplo of
                   gc_mapsettings_limitdiplo_nodiplo : begin
                      if (TObjProp(pobjprop).usage=gc_obj_usage_dipcenter) then
                      begin
                         TObjBase(pobjbase).bproduceenabled := False;
                         var csid : String;
                         _country_GetSIDByID(cid, csid);
                      end;
                   end;
                   gc_mapsettings_limitdiplo_expensivemercs : begin
                      if (TObjProp(pobjprop).bmercenary) then
                      begin
                         var res : Integer;
                         for res:=0 to gc_ResCount-1 do
                         TObjBase(pobjbase).price[res] := TObjBase(pobjbase).price[res]*gc_gameplay_expensivemercskoef;
                      end;
                   end;
                end;
             end;
          end;
       end;
    
    2. We'll make the necessary entries now to make it appear in the GUI.
    2.1
    Go to data\gui\menu.inc\showcustomgame.inc :

    Adjust this value to however many new options are added. In our case of the no diplo +1
    Line 557:
    Code:
          [*] = ;const cAdditionalSettingsCount = 7;  // 6+1
    
    Next, make sure to adjust the number in front if you stick it in the middle somewhere and the numbers below.
    Line 566:
    Code:
          [*] = ;      3 : textid := 'randommap.settings.limitdiplo';
    
    Again adjust numbers below this option to match:
    Line 601:
    Code:
          [*] = ;      3 : begin
          [*] = ;         case gMap.settings.additional.limitdiplo of
          [*] = ;            gc_mapsettings_limitdiplo_default : s2 := 'default';
          [*] = ;            gc_mapsettings_limitdiplo_nodiplo : s2 := 'nodiplo';
          [*] = ;            gc_mapsettings_limitdiplo_expensivemercs : s2 := 'expensivemercs';
          [*] = ;         end;
          [*] = ;      end;
    
    If you dont add expensive mercenaries and no diplo is the last option, then add this one here, if your last option is something else, add this here.
    Line 683
    Code:
          [*] = ;      3 : begin
          [*] = ;      textid := 'randommap.settings.limitdiplo';
          [*] = ;      count := gc_mapsettings_limitdiplo_expensivemercs+1;
          [*] = ;   end;
    
    Line 745
    Code:
          [*] = ;   3 : begin
          [*] = ;      for i:=0 to gc_mapsettings_limitdiplo_expensivemercs do
          [*] = ;      begin
          [*] = ;         case i of
          [*] = ;            gc_mapsettings_limitdiplo_default : s2 := 'default';
          [*] = ;            gc_mapsettings_limitdiplo_nodiplo : s2 := 'nodiplo';
          [*] = ;            gc_mapsettings_limitdiplo_expensivemercs : s2 := 'expensivemercs';
          [*] = ;         end;
          [*] = ;         var text : String = GetLocaleTableListItemByID('gui', textid+'.'+s2);
          [*] = ;         GUIListBoxAddItem(elmHnd, text, i);
          [*] = ;      end;
          [*] = ;      SetGUIListBoxItemIndexSilent(elmHnd, gMap.settings.additional.limitdiplo);
          [*] = ;   end;
    
    2.2 Next file, data\gui\menu.inc\eventcustomgame.inc

    Again, make sure to adjust the numbers of the options below this line if you put it at nr3. If you add it last, do so everywhere.
    Line 50: (ish)
    Code:
          [*] = ;            3 : gMap.settings.additional.limitdiplo := tag;
    

    2.3 Next file to adjust: data\gui\menu.inc\initmapsettings.inc

    Line 20:
    Code:
          [*] = ;   gMap.settings.additional.limitdiplo := 0;
    

    2.4 Last file to get it to work: data\scripts\lib\miscext2.script

    Line 2075:
    Code:
       roomdata := roomdata+IntToStr(gMap.settings.additional.limitdiplo)+gc_gui_delimitercharstr;
    
    Line 2293:
    Code:
                   18 : map.settings.additional.limitdiplo := istr; // again adjust the numbers below.
    

    3) Localisation: without it , the text won't show up in game.

    There are 3 versions of the language editor: An unofficial one which you can find on the c3 forums here ( it displays cyrillic, but you can't add new strings with it, so don't bother with this one for this example) , a standalone official language editor by gsc (get it here) and an inbuilt one in the editor.exe (which has slightly more options, but not required for this). The standalone version (editorlang.exe) will do just fine for this.

    You'll want to open it, and 'load' data/locale/en/gui.lng.
    Press the 'add' button and fill out the keys i posted below (or whichever names you used for your entries, eg randommap.settings.limitdiplo )
    Press ok and fill out the 'translation' in english in the field. Do so for every line of options. Don't bother moving them up with the rest.
    Then go to File - save, and save as gui.lng and again go to File- and this time select the option 'save as .txt'.

    Code:
    randommap.settings.limitdiplo                               Diplomatic Center
    randommap.settings.limitdiplo.default                 Default
    randommap.settings.limitdiplo.nodiplo                No Diplomatic Center
    randommap.settings.limitdiplo.expensivemercs Expensive Mercenaries
    
    If you did everything right you should have your new no diplo options in game:
    [​IMG]
    [​IMG]

    Questions? Ask!
     
    Last edited: Dec 20, 2016
    Furious Peasant, Setakat and Ferox like this.
  2. Ebel

    Ebel Moderator Staff Member

    4) Some extra information:

    4.1 A bit more information about player.script:

    Assuming you want to do something differently, perhaps disable another building/unit, you can find gc_obj_usages in data\scripts\lib\unit.script or data\scripts\lib\dmscript.global
    Code:
       gc_obj_usage_none = 0; // Default
       gc_obj_usage_mill = 1;
       gc_obj_usage_farm = 2;  // Housing
       gc_obj_usage_center = 3;
       gc_obj_usage_storage = 4;
       gc_obj_usage_tower = 5;
       gc_obj_usage_field = 6;
       gc_obj_usage_mine = 7;
       gc_obj_usage_fasthorse = 8;
       gc_obj_usage_mortar = 9; // Howitzer
       gc_obj_usage_cannon = 10;
       gc_obj_usage_grenadier = 11;
       gc_obj_usage_hardwall = 12;  // Stone Wall
       gc_obj_usage_weakwall = 13; // Wooden wall
       gc_obj_usage_battleship = 14;
       gc_obj_usage_weak = 15;
       gc_obj_usage_fisher = 16;
       gc_obj_usage_artdepo = 17;
       gc_obj_usage_supermortar = 18; // Mortar
       gc_obj_usage_port = 19;
       gc_obj_usage_lightinfantry = 20;
       gc_obj_usage_shooter = 21;
       gc_obj_usage_hardhorse = 22;
       gc_obj_usage_peasant = 23;
       gc_obj_usage_horseshooter = 24;
       gc_obj_usage_frigate = 25;
       gc_obj_usage_galley = 26;
       gc_obj_usage_yacht = 27;
       gc_obj_usage_xebec = 28;
       gc_obj_usage_transport = 29;
       gc_obj_usage_archer = 30;
       gc_obj_usage_mcannon = 31; // Multibarrel cannon
       gc_obj_usage_dipcenter = 32;
    
    Not every building/unit has a defined gc_obj_usage. For example mercenary units don't, as you can see above I've used .bmercenary which you can find back in units.script, or if for example you want to disable the market, use bmarket as in the code below:

    Code:
       if (gMap.settings.additional.limitmarket<>gc_mapsettings_limitmarket_default) then
       begin
          for pl:=0 to gc_MaxPlayerCount-1 do
          begin
             for cid:=0 to gc_MaxCountryCount-1 do
             for id:=0 to gc_country_maxmembers-1 do
             begin
                pobjbase := gPlayer[pl].objbase[cid][id];
                pobjprop := gObjProp[cid][id];
                case gMap.settings.additional.limitmarket of
                   gc_mapsettings_limitmarket_nomarket : begin
                      if (TObjProp(pobjprop).bmarket) then
                      begin
                         TObjBase(pobjbase).bproduceenabled := False;
                         var csid : String;
                         _country_GetSIDByID(cid, csid);
                      end;
                   end;
                end;
             end;
          end;
       end;
    
    Assuming you also want to disable some upgrades along with some units. Look at the following lines which disables every artillery piece and some of it's related artillery upgrades in the academy:

    Code:
       if (gMap.settings.additional.cannons<>gc_mapsettings_cannons_default) then
       begin
          for pl:=0 to gc_MaxPlayerCount-1 do
          begin
             for cid:=0 to gc_MaxCountryCount-1 do
             for id:=0 to gc_country_maxmembers-1 do
             begin
                pobjbase := gPlayer[pl].objbase[cid][id];
                pobjprop := gObjProp[cid][id];
                case gMap.settings.additional.cannons of
                   gc_mapsettings_cannons_noartillery : begin
                      if (TObjProp(pobjprop).usage=gc_obj_usage_cannon) or (TObjProp(pobjprop).usage=gc_obj_usage_mortar) or (TObjProp(pobjprop).usage=gc_obj_usage_supermortar) or (TObjProp(pobjprop).usage=gc_obj_usage_mcannon) then
                      begin
                         TObjBase(pobjbase).bproduceenabled := False;
                         var csid : String;
                         _country_GetSIDByID(cid, csid);
                         var upgind : Integer = _country_GetUpgradeIndexByUpgradeID(cid, csid+'art.cannon.1.1', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'art.cannon.2.1', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'art.howitzer.1.1', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'art.howitzer.2.1', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'aca.18', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'aca.19', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'aca.20', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'aca.21', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                         upgind := _country_GetUpgradeIndexByUpgradeID(cid, csid+'aca.27', False);
                         if (upgind>-1) then
                         gPlayer[pl].upgstate[cid, upgind].enabled := False;
                      end;
                   end;
                   gc_mapsettings_cannons_expensivecannons : begin
                      if (TObjProp(pobjprop).bartillery) then
                      begin
                         var res : Integer;
                         for res:=0 to gc_ResCount-1 do
                         TObjBase(pobjbase).price[res] := TObjBase(pobjbase).price[res]*gc_gameplay_expensivecannonskoef;
                      end;
                   end;
                end;
             end;
          end;
       end;
    
    Finding the id's for the academy upgrades is easy: look in data\scripts\dmglobal.script or in data\scripts\lib\country.script
    The unit upgrades are a bit more tricky. They aren't written in full anywhere, but the format is "upgradeplace.member.id" So 'art.howitzer.1.1' is in the artillery depot for the howitzer and is the first top upgrade, while 2.1 is the bottom upgrade. Since these upgrades are linked, you only need to disable the first one.

    4.2 Language editor and cyrillic (non latin languages)

    The official language editor doesn't display cyrillic and the unofficial language editor doesnt allow to add new entries, only edit them. So, here's how to get around it and make adjustments to the russian/ukrainian language files:

    Go to Editor.exe -> Modules -> Locale table -> Choose table -> Edit selected table -> File -> Save as TXT
    Next open the text file you just saved in your preferred text editor (I use sublime text ), go to File -> Reopen with encoding -> Cyrillic (Windows 1251). It will now display cyrillic properly.
    Edit the text file with your new entries.
    File -> Save with encoding -> Cyrillic (Windows 1251)
    Back to the editor.exe -> Modules -> Locale table -> Load as .txt -> Select your edited file -> Save as .lng


    4.3 Some pointers on files involved in other random map options:

    - Map Shape : data\game\var\generator.cfg, data\gen\terrainmasks\, data\gen\terrainmasks.src\, data\script\dmscript.global, data\scripts\common.inc\dogenerate.inc
    - Peace Time: data\scripts\lib\misc.script, data\gui\menu.inc\showcustomgame.inc,
    - Start Options : data\game\var\startingsettings.cfg , data\script\dmscript.global, data\gui\menu.inc\showcustomgame.inc
    - Resource options: data\scripts\lib\serial.script, data\scripts\common.inc\initmapgen.inc,
    - Map Size : see post below in this thread.
     
    Last edited: Dec 20, 2016
    Setakat and Loner like this.
  3. Carlos

    Carlos New Member

    How can I edit the map sizes?
     
  4. A. Soldier

    A. Soldier Active Member

    There are 2 or 3 separate size "options" in the dmscript.global file but I'm not sure if they really do anything.
     
  5. Carlos

    Carlos New Member

    I have tried to modify that file but it looks like it freezes when generating the new map. Specifically at the generating hills and mountains stage. I know that there are other files that need to be edited but I dont know what files.
     
  6. Ebel

    Ebel Moderator Staff Member

    Assuming you want to increase the mapsize, doubt anyone would want to make it smaller than it already is.
    We'll go with an increase in the example ( 640 -> 720 ) and calling it "Carlos Size"

    1. data\scripts\dmscript.global

    Line 48 : Adjust following values

    Code:
       gc_idlegrid_mapwidth = 720;
       gc_idlegrid_mapheight = 720;
       gc_idlegrid_countx = 900;//gc_idlegrid_mapwidth*1.25;
       gc_idlegrid_county = 900;//gc_idlegrid_mapheight*1.25;
    
       gc_scangrid_mapwidth = 720;
       gc_scangrid_mapheight = 720;
    
       gc_resgrid_mapwidth = 720;
       gc_resgrid_mapheight = 720;
    
       gc_soundgrid_mapwidth = 720;
       gc_soundgrid_mapheight = 720;
    
       gc_terraindata_mapwidth = 720;
       gc_terraindata_mapheight = 720;
    
    Line 125
    Code:
       gc_MaxMapWidth = 720;
       gc_MaxMapHeight = 720;
    
    2. data\scripts\common.inc\dogenerate.inc
    Code:
    Line 430
           [*] = ;   const cMapSize = 720;
    
    Line 1298
    Code:
    [*] = ;if (mapW<>720) or (mapH<>720) then
    [*] = ;   var modifier : Float = (720/((mapW+mapH)/2));
    
    3. data\scripts\common.inc\generatemap.inc
    Line 618
    Code:
          [*] = ;   const cWaterMapArrSize = (720 div cWaterFieldSize);
    
    Line 657
    Code:
    [*] = ;   var mapsizemod : Float = (cWaterMapArrSize/((720/mapheight)*2))*cWaterFieldSize; // var mapsizemod : Float = (cWaterMapArrSize div ((720 div mapheight)*2))*cWaterFieldSize;
    
    Line 684
    Code:
           [*] = ;   var tmpPatternMask : array [0..720-1] of array [0..720-1] of Boolean;
    
    4. data\scripts\common.inc\postprocess.inc
    Line 35
    Code:
          [*] = ;var mask : array [0..720-1] of array [0..720-1] of TColor;
          [*] = ;var maskTmp : array [0..720-1] of array [0..720-1] of TColor;
    
    5. data\scripts\common.inc\smoothtiles.inc
    Line 27
    Code:
          [*] = ;var atilemap : array [0..720] of array [0..720] of Integer;
    
    6. data\scripts\lib\misc.script
    Line 3260
    Code:
    procedure _misc_StandPatternPlaceMask(patName : String; standX, standZ, angle : Float; var tmpPatternMask : array [0..719] of array [0..719] of Boolean);
    
    7. gui\menu.inc\donewgame.inc
    Line 6
    Code:
           [*] = ;const cMapSize = 720;
    
    Line 36
    Code:
          [*] = ;case gMap.settings.gen.mapsize of
          [*] = ;   0 : genMapSize := 320;
          [*] = ;   1 : genMapSize := 480;
          [*] = ;   2 : genMapSize := 640;
          [*] = ;   3 : genMapSize := 720;
          [*] = ;   else
          [*] = ;   genMapSize := 320;
          [*] = ;end;
    
    8. gui\menu.inc\showcustomgame.inc
    Line 124
    Code:
          [*] = ;procedure FillComboBoxMapSize(elmHnd : Integer);
          [*] = ;begin
          [*] = ;   var cTextSizeNormal, cTextSizeLarge, cTextSizeHuge, CTextSizeCarlosSized : String;
          [*] = ;   _misc_GetNewTextLocale('map.size.normal', cTextSizeNormal);
          [*] = ;   _misc_GetNewTextLocale('map.size.large', cTextSizeLarge);
          [*] = ;   _misc_GetNewTextLocale('map.size.huge', cTextSizeHuge);
          [*] = ;   _misc_GetNewTextLocale('map.size.carlossize', cTextSizeCarlosSized);
          [*] = ;   var i : Integer;
          [*] = ;   if (GetGUIListBoxItemsCount(elmHnd)=0) then
          [*] = ;   begin
          [*] = ;      GUIListBoxAddItem(elmHnd, cTextSizeNormal, 0);
          [*] = ;      GUIListBoxAddItem(elmHnd, cTextSizeLarge, 1);
          [*] = ;      GUIListBoxAddItem(elmHnd, cTextSizeHuge, 2);
          [*] = ;      GUIListBoxAddItem(elmHnd, cTextSizeCarlosSized, 3);
          [*] = ;      SetGUIListBoxItemIndexSilent(elmHnd, 0);
          [*] = ;   end;
          [*] = ;end;
    
    9. Localisation.
    Mapsize strings for english are in /data/locale/needloc/new.lng
    Other languages in /data/locale/xx/new.lng
    See to guide in first post how to use Language editor.
    Add string:
    Code:
    map.size.carlossize     Carlos Size
    

    [​IMG]

    Note: Scrollbar or not.
    10. gui\menu.inc\showcustomgame.inc
    Line 552
    No scroll bar :
    Code:
          [*] = ;elmHnd := _gui_CreateComboBox('mapsize', elmMain, 4, 0, gc_halParentLeft, gc_valParentTop, 805+cAddOffsetL, 103+ind*cOffY, 145, gc_halLeft, gc_valMiddle, 5, 0, gc_font_serif_12, bAllowChange, eventstate, bupdate, True);
    
    Scrollbar :
    Code:
          [*] = ;elmHnd := _gui_CreateComboBox('mapsize', elmMain, 3, 0, gc_halParentLeft, gc_valParentTop, 805+cAddOffsetL, 103+ind*cOffY, 145, gc_halLeft, gc_valMiddle, 5, 0, gc_font_serif_12, bAllowChange, eventstate, bupdate, True);
    
    [​IMG]

    Without scroll bar for this option is better I think.

    Took a long time to generate the map, because of the size. Especially the forest stage. I hope you have a good computer.
    I didn't thoroughly test this, it's very well possible I forgot to change something somewhere, but it works on first glance.
     
    Last edited: Dec 20, 2016
  7. Carlos

    Carlos New Member

    Thank you for that information I appreciate it. I made the changes and It is weird. When I change the values to 645 it takes very long time to create. When I change it back to normal (640) everything is ok. There is not big difference.
     
  8. Ebel

    Ebel Moderator Staff Member

    Yeah, 640->645 isn't a big increase, hardly noticeable. About the slow creating time. I remember reading in a patch note they optimized something in regards to terrain generation. It's very well possible I read over it in the files and didn't include it in my changes above.
     
  9. Carlos

    Carlos New Member

    Yeah I will keep trying and see what happens thanks again for your help.
     
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice