Adding New Map Options


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:


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

   gc_gameplay_expensivemercskoef = 3;
 

1.2 Next, add the new limitdiplo to data\scripts\lib\classes.script

Line 46 +

   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.

   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:

      [*] = ;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:

      [*] = ;      3 : textid := 'randommap.settings.limitdiplo';
 

Again adjust numbers below this option to match:
Line 601:

      [*] = ;      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 don't 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
 

      [*] = ;      3 : begin
      [*] = ;      textid := 'randommap.settings.limitdiplo';
      [*] = ;      count := gc_mapsettings_limitdiplo_expensivemercs+1;
      [*] = ;   end;

 

Line 745

      [*] = ;   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)

      [*] = ;            3 : gMap.settings.additional.limitdiplo := tag;
 


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

Line 20:

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


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

Line 2075:

   roomdata := roomdata+IntToStr(gMap.settings.additional.limitdiplo)+gc_gui_delimitercharstr;
 

Line 2293:

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


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:


Additional Notes


* 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,

 

* 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
   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:

 

   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:

 

   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.