Adding New Cloned Units


Original Thread by Setakat


For this guide I'm going to be going over the basics of introducing a new unit into the game, making it trainable and configuring it so it's affected by upgrades.

I'm going to be making a custom Dragoon based off the visuals of the Light Cavalry unit since I have the Early Bird DLC, and outside of the Diplomatic Center, its not used. I could have just modified the base unit, but creating a whole new unit is far more interesting and useful. If you don't have this DLC and have or want to use a different unit, go right ahead.

Preparation
First of all, grab your favourite text editor and open the following files:
- data/scripts/country.script
- data/scripts/unit.script
- data/hud/hud.mat
- data/objects/units.objects

Creating the Basics
Next, we'll need to create the units .prop file. These files can be found in data/objects, and contain the visuals/animation references for our new unit. I'm going to make a copy of the 'lightcavalry.prop' file and rename it to 'cusdragoon.prop'. Once you've copied and renamed your new unit file, open it for editing.

Once opened, look for the two lines (should be 4 & 5) that start with 'CustomName' and 'BaseName'. Change these to be the id of your new unit. I'm going to go with 'cusdragoon'. Save and close the file.
Note: Its important to use the correct id that you specified for the BaseName elsewhere, as this currently appears to be the id that gets used in later files.

How do we use it?
Once we've got our prop file, we'll need to tell the game to load it. Go to units.objects and search for the line that adds your base unit, duplicate it and change the file that it points to.
In my case, I wanted to find and duplicate the line that read 'ObjectItems[*].PropertiesFileName=.\data\objects\units\lightcavalry.prop', and then edit it so it points to my 'cusdragoon.prop' file.
Once your done, save and close the file.

The new guy needs a photo
Now to set the hud icon. Switch to data/hud/hud.mat, find the section that corresponds to your base unit, duplicate it, and change the 'Material.Name' line to reference your new units id. Mine looks like this:
section.begin {refurl=.\data\hud\ref\reflibmat.mat}
   Material.Name = icons.unit.cusdragoon
   Material.LibTextureName = iconsunits
   Material.TextureCoord.ImageW = 512
   Material.TextureCoord.ImageH = 512
   Material.TextureCoord.CoordX = 276
   Material.TextureCoord.CoordY = 368
   Material.TextureCoord.CoordW = 46
   Material.TextureCoord.CoordH = 46
section.end

Save and close the file.

Setting some basic info
Next up, switch to 'data/scripts/unit.script'. Time to give our new Dragoon some properties, otherwise he'll die whenever he spawns.
Because I'm making a new Dragoon, I want to look for this line
Code:

'dragoon', 'kingmusketeer', 'dragoon18fra', 'dragoon18', 'dragoon18dip', 'lightcavalry', 'lightcavalrydip' : begin

What this does, is when a unit gets created, if its id matches any of the above, execute the following code, So lets add our new id to the end:
Code:

'dragoon', 'kingmusketeer', 'dragoon18fra', 'dragoon18', 'dragoon18dip', 'lightcavalry', 'lightcavalrydip', 'cusdragoon' : begin

Much better. Now, we could just leave it here, but because I haven't figured out how to implement training drills for him yet, lets make him a bit different from regular Dragoons. Look down a bit, you'll see a line that reads 'case objprop.sid of', and directly below that:
 

               'dragoon' : begin
                  objprop.aiforce := 10;
               end;

Lets make a copy of that, change the id, boost our new soldiers health and damage, alter his training time and tweak how much he boosts our ingame score by.
 

               'cusdragoon' : begin
                  objbase.maxhp := 350;
                  SetObjBaseWeapon(objprop, objbase, 0, 17, 200, 300, 900, 0, 100000, gc_obj_weapon_kind_bullet, True);
                  SetObjBaseSearchBuildVisionScore(objprop, objbase, 900, 1000, 3, 30);
               end;

I decided to drop his build time down a bit to 1000 - the third parameter in the 'SetObjBaseSearchBuildVisionScore' method call, and the score he provides to 30 - the last parameter since he'll ultimately be worse than the regular Dragoon. Save and close the file.

Assignment
Now our new Dragoon needs to know how to form a formation, be recruited by a nation, benefit from some upgrades, and show up in the spawn menu.
Lets start with formations. Look for the following two lines
 

   _country_ClearOfficerFormations(country);
   var ind : Integer;

Somewhere below that, with the rest of the cavalry formations, add 'AddOfficersFormationCavExt(country, ind, 'cusdragoon', 1);'. If you're doing an infantry unit, use the appropriate infantry formation call.

Next up, we'll assign him to a nation. I'll go for England, as they are the 1st of the nations list in the spawn menu without a cavalry unit in the 2nd Stable slot. Look for '// new units to preserve indexation put here', and below that add
 

      if (eng) then
      _country_AddMember(country, 'cusdragoon', ind, True, gc_country_editorplace_category_cavalry, 25, gc_ai_unit_dragoon17);

Next, we need to add him to a building. Look for '// FIXED PRODUCE' and scroll down a bit. You'll find a bunch of lines starting with '_country_AddFixedProduceWithAccessControl' that add units to buildings. Since my unit is a Dragoon, I'm going to find the stable section, copy the dragoon reference, update its id to 'cusdragoon' and change its position (the number immediately after the id) from '2' to '1' so it looks something like this:
 

_country_AddFixedProduceWithAccessControl(country, fixedproduceind, member, 'cusdragoon', 1, 0, ind, csid+'bla', '', '');

Now, upgrades. Look for '// UPGRADE + UPGRADEPLACE + UPGRADEENABLE + UPGRADELINKS'. Below this, it'll create some arrays, and below that, it'll add units to them. We want to add our new Dragoon to the bottom of the following arrays: 'sarrUnitsAll', 'sarrUnitsShooters', 'sarrUnitsCavalry'.
Note: the arrays only have 64 positions available, and the 'sarrUnitsAll' array currently uses 59 of them. I haven't tested to see if it can safely be expanded out to 128.
Our new lines should look something like this:
Code:

k := k+1; sarrUnitsAll[k] := 'cusdragoon';
k := k+1; sarrUnitsShooters[k] := 'cusdragoon';
k := k+1; sarrUnitsCavalry[k] := 'cusdragoon';

In Closing...
If I've written the above correctly and haven't missed anything out (99% sure I have), and you've followed it correctly, you should be able to start up the game, go to England (or whatever nation you assigned your new unit to), select it from the spawn menu and place it down without it dying instantly.
You should also be able to throw down a bunch of buildings and train it normally, and assign it into formations.

 

Upgrades

First up, open up country.script. We're going to have to find the appropriate position to add our new unit in at. Because I've made a custom Dragoon, and put him in the second unit slot in the stable, I'm going to find a shooting unit that shares the same position. France's King's Musketeer matches, so we'll do a search for 'kingsmuskeeter', and about half way down the file, we find something promising:
 

   case cid of
      _fra : member := 'kingsmusketeer';
      else
      member := '';
   end;
   if (member<>'') then
   begin
      case cid of
         _fra : SetUpgStructFoodGold(upgstruct, upgplace, member, 1, 2000, 1350, True, 1, 1500, 2100, True, 1, 5000, 3300, True, 1, 10500, 4400, True, 1, 12600, 5500, True, 9, 40000, 6000, blacksmith, ''); // Korolrv_Mus
      end;
      AddUpgradePack(country, upgstruct, ctypeProtection, gc_upg_tooltiptype_horsedef, 1, 2, ind, linkind);
   end;

This stuff is a little complex, so I'm going to go over it in bulk.
First up, we check the country code. If we're creating the France country, we'll add upgrades for the King's Musketeer. Otherwise, no unit.
If we have a unit that needs upgrades, check the country code, and create the upgrade data. Since we're currently France, we'll create the upgrade data, and then set it.

The Integer, Integer, Integer, Bool pattern in the 'SetUpgStructFoodGold' sets the bonus, the food cost and then the gold cost. There's also a 'SetUpgStructFoodGoldIron', which has a 4 Integer pattern, with the 4th being the Iron Cost of the upgrade, and there is also 'SetUpgStructFoodGoldIronCoal'. The boolean value currently doesn't seem to do anything, so we'll ignore it, and set it to true since thats what every other upgrade does.

So, we'll use the country code of our Dragoons native country of England - '_eng' to add some attack and defense upgrades - but for the purpose of this tutorial, we'll won't give him any defense upgrades, but because of the way the script works, we still need to add them. I'll post my code so you can see the changes.
Code:

   case cid of
      _fra : member := 'kingsmusketeer';
      _eng : member := 'cusdragoon';
      else
      member := '';
   end;
   if (member<>'') then
   begin
      case cid of
         _eng: SetUpgStructFoodGold(upgstruct, upgplace, member, 1, 2000, 100, True, 1, 1000, 300, True, 2, 500, 700, True, 0, 0, 0, True, 0, 0, 0, True, 0, 0, 0, blacksmith, '');
      end;
      AddUpgradePack(country, upgstruct, ctypeDamageBullet, gc_upg_tooltiptype_shooterdmg, 1, 1, ind, linkind);
      case cid of
         _eng : SetUpgStructFoodGold(upgstruct, upgplace, member, 0, 0, 0, True, 0, 0, 0, True, 0, 0, 0, True, 0, 0, 0, True, 0, 0, 0, True, 0, 0, 0, blacksmith, '');
         _fra : SetUpgStructFoodGold(upgstruct, upgplace, member, 1, 2000, 1350, True, 1, 1500, 2100, True, 1, 5000, 3300, True, 1, 10500, 4400, True, 1, 12600, 5500, True, 9, 40000, 6000, blacksmith, ''); // Korolrv_Mus
      end;
      AddUpgradePack(country, upgstruct, ctypeProtection, gc_upg_tooltiptype_horsedef, 1, 2, ind, linkind);
   end;

As you can see, we've added a new 'case' statement here that sets the musket damage upgrade. Since I'm lazy I just copied the 17thc Musketeer's upgrade costs/bonus which will give our new Dragoon +4 Musket once upgraded, going from 17 to 21 damage. A bit less than the regular 17thc Dragoon, but he has some extra health to offset this.
We've also added a line to set the costs for the defense upgrade, except we've made the cost and bonus 0 for all. This effectively remove the upgrade from the unit ingame, so sadly our new Dragoon cannot be upgrades to have bonus protection against Arrows, Pikes and Swords. He'll just have to rely on his extra health to survive.

 

Descriptions

Today we're going to add unit descriptions by editing our respective languages units.txt in the 'data/locale/' folder, and then running the provided .bat file to update the language files.

Unfortunately, the 'txt_to_lng.bat' file only does a few languages, and doesn't batch convert everything, which for me, doesn't include English. Lets fix that.
Open the .bat file, and add the following lines to the very bottom.
..\..\tools\locale\editorlang.exe .\en\units.txt .\en\units.lng c
pause

If you're modifying a language other than english, change the '\en\' to the 2 character code of your language.
Since we're just doing a single file, we'll only include it in here. No need to waste time processing everything else.

Also, I like my .bat files to end in pause, so I don't start them, go off and do something else (e.g. read forums) come back and wonder if I actually ran the bat. By adding the 'pause' command, it'll wait until you press the enter key, and then exit. You probably already know this already, but if not, you'll have learnt at least 2 new things today.

Now that's that, lets add our new units description. Find your the folder for your respective language, navigate into it and open the 'units.txt' file.

There's a whole lot of stuff here, but the part that concerns me is the line that reads '@UNITS.CAV.SHOOTERS'. This is where I'll stick my new Dragoon's description, just after the Tatar's description, and before the Mercs. If your unit is a different type, find the appropriate section, and put your units description there. Don't know if it'll affect anything, but lets do it just to be safe.
 

    @cusdragoon
Setakat's Custom Dragoon
    @cusdragoon.ext
%include(units;descr.cav.any.musket)%
%include(units;descr.canshoot)%
%include(units;descr.cantshotclose)%
%include(units;descr.params.highattack)%
%include(units;descr.combination.lowrateoffirehighbuildtime)%

Not terribly complex. I just copied the 17thc Dragoons description, replaced the 'dragoon' id with my own and changed the units name on the second line. Once you've added this in, save the file.

Now the .bat file we modified a minute ago? Go run it, and when its finished, open Cossacks 3, pop into the editor, spawn your new unit, and hopefully you should see your units name showing up, and if you place the cursor over its training icon in whatever building spawns, and you should see its list of attributes show up in the toolkit.