Results 1 to 30 of 268

Thread: Tutorial - Adding a unit to the game

Threaded View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Member Member Musashi's Avatar
    Join Date
    Nov 2002
    Location
    The Mists of Legend
    Posts
    811

    Default Tutorial - Adding a unit to the game

    Ok. This is a LONG and involved process, and it will probably be made significantly easier when CA releases a few more tools. However, this is the process required to get a new unit into the game at the current time.

    I'm going to be using a unit I created as an example throughout this process. My Byzantine Dragoons are sort of a cross between Reiters and Camel Gunners. They're nasty and very powerful, but keep in mind they're for an alternate history fantasy type mod I'm working on. This is a picture of the finished product:


    I'm also going to be assuming you've already run the unpacker.

    Step One: The Unit File

    Go into your data folder and open export_descr_unit.txt. We'll be adding a new unit block to this file. I like to keep the file somewhat organized, so I generally group my additions by type and faction and so on, but it doesn't really matter much where you place them.

    We're going to be creating a unit similar to Reiters, so the simplest thing is to start with the entry for Reiters:
    Code:
    type             Reiters
    dictionary       Reiters      ; Reiters
    category         cavalry
    class            missile
    voice_type       Heavy
    banner faction   main_cavalry
    banner holy      crusade_cavalry
    soldier          Reiters, 32, 0, 1
    mount            heavy horse
    mount_effect     elephant -4, camel -4
    attributes       sea_faring, hide_forest, hardy, can_withdraw, can_formed_charge, cantabrian_circle, gunpowder_unit, start_not_skirmishing, guncavalry
    formation        2, 4.4, 3, 6, 4, square
    stat_health      1, 0
    stat_pri         20, 3, pistol_bullet, 45, 20, missile, missile_gunpowder, piercing, none, musket_shot_set, 25, 1
    ;stat_pri_ex      0, 0, 0
    stat_pri_attr    ap
    stat_sec         11, 5, no, 0, 0, melee, melee_blade, piercing, spear, 25, 1
    ;stat_sec_ex      0, 0, 0
    stat_sec_attr    no
    stat_pri_armour  7, 6, 0, metal
    ;stat_armour_ex   7, 8, 0, 0, 6, 0, 0, metal
    stat_sec_armour  0, 0, flesh
    stat_heat        5
    stat_ground      0, -2, -4, 0
    stat_mental      9, normal, trained
    stat_charge_dist 45
    stat_fire_delay  0
    stat_food        60, 300
    stat_cost        1, 920, 250, 120, 95, 920, 4, 230
    armour_ug_levels 3, 4
    armour_ug_models Reiters, Reiters_ug1
    ownership        hre
    era 2            hre
    ;unit_info        11, 20, 13
    So what we will do is copy and paste that block into the file in another spot, and then make some small changes to it to get it exactly the way we want it.

    The first thing to do is change the type variable. This is the label the game uses for the unit internally. The main thing we need to concern ourselves with for our current purposes is that the game will try to find a unit icon based on this name.

    I've decided to call my troops Byzantine Dragoons, and the game tends to use ES_ or GR_ to designate a Byzantine unit (Although in this case I could simply call them Byzantine Dragoons, that would work just as well), so I've chosen to set the type to GR_Dragoons like so:
    Code:
    type             GR_Dragoons
    Next we have to set the Dictionary entry. The game looks for an entry in the export_units.txt.bin file in order to find the display name and description of the unit. There can't be any spaces in this entry. If I'd called my new unit "Byzantine Dragoons" I'd have had to use a dictionary entry of "Byzantine_Dragoons", or some other one word string.

    The next few lines we leave alone... It's still cavalry, still a missile troop, no need to change the voice or banners... But we do need to change the Soldier entry.

    Experience modding the model db file allows me to say with certainty that the soldier type sets the skeleton and animation sets, while the model and textures are taken from the armour_ug_models line. Technically we could leave the soldier line alone, since we're going to be using the Reiters' animation set. But just for the sake of continuity I'm setting it to GR_Dragoons like so:
    Code:
    soldier          GR_Dragoons, 32, 0, 1
    I also changed the "mount" entry, because I wanted to have them riding the Kataphractoi's horses, but it didn't take. I'll be looking into this later.

    The next thing I changed was the "stat_pri" line. This sets the stats of the primary weapon, in this case, a musket. I didn't want this unit to be an exact clone of the Reiters, rather I wanted it to be a long range skirmisher like the Camel Gunners, so I copied the line from the Camel Gunners' entry.

    I wanted their secondary weapon and armor to match Reiters, so I didn't change any of that. Basically I went all the way down to the armour_ug_models line before making any more changes. This is critical because if we don't change this line, the game is going to look in the model db file for Reiters models, and not find any texture entries for byzantium, and we'll end up with invisible troops even though we did all the hard Model DB work.

    In the end, the entry for my new unit looks like this:
    Code:
    type             GR_Dragoons
    dictionary       GR_Dragoons      ; Byzantine Dragoons
    category         cavalry
    class            missile
    voice_type       Heavy
    banner faction   main_cavalry
    banner holy      crusade_cavalry
    soldier          GR_Dragoons, 32, 0, 1
    mount            eastern armoured horse
    mount_effect     elephant -4, camel -4
    attributes       sea_faring, hide_forest, hardy, can_withdraw, can_formed_charge, cantabrian_circle, gunpowder_unit, start_not_skirmishing, guncavalry
    formation        2, 4.4, 3, 6, 4, square
    stat_health      1, 0
    stat_pri         16, 3, musket_bullet, 180, 20, missile, missile_gunpowder, piercing, none, musket_shot_set, 25, 1
    ;stat_pri_ex      0, 0, 0
    stat_pri_attr    ap
    stat_sec         11, 5, no, 0, 0, melee, melee_blade, piercing, spear, 25, 1
    ;stat_sec_ex      0, 0, 0
    stat_sec_attr    no
    stat_pri_armour  7, 6, 0, metal
    ;stat_armour_ex   7, 8, 0, 0, 6, 0, 0, metal
    stat_sec_armour  0, 0, flesh
    stat_heat        5
    stat_ground      0, -2, -4, 0
    stat_mental      9, normal, trained
    stat_charge_dist 45
    stat_fire_delay  0
    stat_food        60, 300
    stat_cost        1, 920, 250, 120, 95, 920, 4, 230
    armour_ug_levels 3, 4
    armour_ug_models GR_Dragoons, GR_Dragoons_ug1
    ownership        byzantium
    era 2            byzantium
    ;unit_info        11, 20, 13
    Step Two: The EEEEVIL Model DB File

    Now it's time to move on to the next, and hardest step. Coding an entry in the data/unit_models/battle_models.modeldb file, which was obviously never meant to be alterable by hand.

    Be aware that this file ONLY works in the base data/unit_models folder and will NOT work from a mod folder. This obviously has unfortunate implications for our ability to allow mod users to maintain multiple mod installations simultaneously, but there's basically nothing we can do about it until CA gives us some manner of fix or workaround.

    You will need to add --io.file_first to your batch file to get it working.

    What you do is you open the file in notepad. It will look like chaos to the untrained eye (And even to the trained eye it's a royal... erm... well you get the idea).

    Since our unit will actually be using the Reiter model with different textures, prudence dictates that we start by copying the entry for Reiters:
    Code:
    7 reiters 1 4 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod0.mesh 121 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod1.mesh 900 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod2.mesh 2500 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod3.mesh 6400 1 3 hre 73 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_hre.texture 76 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_normal.texture 35 unit_sprites/hre_Reiters_sprite.spr 1 3 hre 65 unit_models/AttachmentSets/Final European CB Gun_hre_diff.texture 65 unit_models/AttachmentSets/Final European CB Gun_hre_norm.texture 0  1 5 Horse 14 MTW2_HR_Pistol 13 MTW2_HR_Spear 1 22 MTW2_HR_Pistol_Primary 1 21 MTW2_HR_spear_Primary 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002 11 reiters_ug1 1 4 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod0.mesh 121 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod1.mesh 900 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod2.mesh 2500 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod3.mesh 6400 1 3 hre 73 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_hre.texture 76 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_normal.texture 39 unit_sprites/hre_Reiters_ug1_sprite.spr 1 3 hre 65 unit_models/AttachmentSets/Final European CB Gun_hre_diff.texture 65 unit_models/AttachmentSets/Final European CB Gun_hre_norm.texture 0  1 5 Horse 14 MTW2_HR_Pistol 13 MTW2_HR_Spear 1 22 MTW2_HR_Pistol_Primary 1 21 MTW2_HR_spear_Primary 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002
    Ugly, isn't it?

    So what can we make of all this? Let's take it one step at a time.

    The first thing to remember is that almost every entry in the file is in the format of "n xxxxx" where n is the number of characters in the string that follows it, and xxxxx is the string.

    Our first entry is "7 reiters". That's 7, the number of characters in the word reiters, and then the word itself. Personally I assume they are using some sort of serialization library that reads all these values into dynamically allocated memory, using the string length numbers to know how many characters to read in, and then looking for another string length directive. But that's really only interesting to nerds like me ;)

    The next entry is "1 4". 4 is naturally a one character string. What this represents is the number of LOD entries the game should be trying to load. This is only really important to know if you're changing the actual meshes for a unit (But it did bite me in the butt once, which is naturally how I figured out what the number does hehe).

    The next three entries:
    Code:
    53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod0.mesh 121 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod1.mesh 900 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod2.mesh 2500 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod3.mesh 6400
    These are meshes to use at various distances from the unit. Note the mesh string, and then the distance. It's fairly straightforward.

    Next up is the start of an actual texture block.
    Code:
    1 3 hre 73 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_hre.texture 76 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_normal.texture 35 unit_sprites/hre_Reiters_sprite.spr
    The 1 is the number of texture blocks it should try to read in. The easiest way to think of this is just as the number of factions who can use the unit. In the case of Reiters, only the HRE can use this soldier type, so the number is one, and there is only one texture block.

    3 is the number of letters in the name of the faction the following texture block is for. In this case, the HRE. hre is of course the faction name. This is followed by the length of the next string, which will be the path of the texture which should be used for this unit when it is being employed by the given faction. The next path is to what I think is some kind of alpha map or transparency guide. Don't worry, there's one in every texture directory, so just link to the one that corresponds to the model and texture you're attempting to use.

    The last path is to the sprite file, which is used to render the unit when it's farther away than the distance set for the lowest LOD.

    The next block of code is this:
    Code:
    1 3 hre 65 unit_models/AttachmentSets/Final European CB Gun_hre_diff.texture 65 unit_models/AttachmentSets/Final European CB Gun_hre_norm.texture 0  1 5 Horse 14 MTW2_HR_Pistol 13 MTW2_HR_Spear 1 22 MTW2_HR_Pistol_Primary 1 21 MTW2_HR_spear_Primary 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002
    This is a set of attachments your unit uses. I'm not really 100% sure what any of this stuff does, except that you need to start this block with the number of such blocks it's reading in (Again, the number of factions that use the unit), and the faction name in the usual length-string format.

    And as you can see the whole thing is repeated for the armor upgrade model(s).

    Now lets see what this looks like after we edit it for our new unit (My personal suggestion is to copy the whole block, paste it into a separate notepad window, edit it there, and then paste it back into the file. Be SURE that when you paste it back in, you put the block at the end of another block, and have a single space at both ends).

    Code:
    11 GR_Dragoons 1 4 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod0.mesh 121 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod1.mesh 900 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod2.mesh 2500 53 unit_models/_Units/RN_Half_3Q_Plate/reiters_lod3.mesh 6400 1 9 byzantium 79 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_byzantium.texture 76 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_normal.texture 41 unit_sprites/byzantium_Reiters_sprite.spr 1 9 byzantium 65 unit_models/AttachmentSets/Final European CB Gun_hre_diff.texture 65 unit_models/AttachmentSets/Final European CB Gun_hre_norm.texture 0  1 5 Horse 14 MTW2_HR_Pistol 13 MTW2_HR_Spear 1 22 MTW2_HR_Pistol_Primary 1 21 MTW2_HR_spear_Primary 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002 11 reiters_ug1 1 4 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod0.mesh 121 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod1.mesh 900 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod2.mesh 2500 57 unit_models/_Units/RN_Half_3Q_Plate/reiters_ug1_lod3.mesh 6400 1 9 byzantium 79 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_byzantium.texture 76 unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_normal.texture 45 unit_sprites/byzantium_Reiters_ug1_sprite.spr 1 9 byzantium 65 unit_models/AttachmentSets/Final European CB Gun_hre_diff.texture 65 unit_models/AttachmentSets/Final European CB Gun_hre_norm.texture 0  1 5 Horse 14 MTW2_HR_Pistol 13 MTW2_HR_Spear 1 22 MTW2_HR_Pistol_Primary 1 21 MTW2_HR_spear_Primary 16 -0.090000004 0 0 -0.34999999 0.80000001 0.60000002
    As you can see, a few changes have been made. I kept the meshes, because I want to use the Reiter models. I've changed the faction name, and the texture as well. Note that there is no unit_models/_Units/RN_Half_3Q_Plate/textures/rn_half_3q_plate_byzantium.texture , so we'll have to create one. If you read through the section above you should be able to see what's been changed and why.

    Step Three: Texture Alteration

    So, now we have to create our texture! No wait... it's not quite as hard as it sounds.

    First you go to unit_models/_Units/RN_Half_3Q_Plate/textures. In here you'll see textures for this model type for a bunch of different factions. What you need to do is open one, say rn_half_3q_plate_england.texture, with a hex editor, and cut (Cut to the clipboard, you're going to need to paste it back in later) the first 48 bytes. Now rename the file from .texture to .dds, and load it up in your favorite image processing software. I'm going to be talking about how to work with it in Photoshop CS2, because that's what I own.

    What you do now is turn all those areas of British red into Byzantine purple. The way we do that is to go to image->adjustments->replace color, and use the cursor to select a bright red spot. Now use the HSB sliders on the bottom to adjust that bright red to a bright purple. Now adjust the threshold slider at the top until the image looks the way you want it. Presto!

    If you're anal you can work your faction emblem into it the purple fields now, but it will look good as is. Just save the file, change the file extension back to .texture, and paste those 48 bytes back into the beginning of the file.

    You can now start the game and use your new unit in custom games! Aren't you proud of yourself?

    You might notice there are some things missing though. Like their icon looks like a peasant, and when you mouse over the unit it says "unlocalized placement text". We should probably fix that huh?

    Of course we should!

    Step Four: Giving Your Unit An Icon

    So go to data/ui/units/hre and copy #reiters.tga over to the data/ui/units/byzantium folder, and rename it #gr_dragoons.tga. Optionally you can go in and color parts of the icon purple. It's up to you.

    Your unit now has it's very own shiny icon!

    All that's left is the text.

    Step Five: Editing the Unit Text File

    So, what you're going to do is get Alpaca's txt.bin converter from the thread here in this forum, place it in your data/text folder, and run it!

    Now you can edit export_units.txt. Just copy the entry for some other unit, Reiters for instance, and change the labels.

    In other words copy and paste this:
    Code:
    {Reiters}	Reiters
    {Reiters_descr}	Reiters derive their name from the German word reiter, meaning horseman. Generally from German states, Reiters are armed with a pistol and spear, and well protected by plate armour. They often employ the shooting circle tactic to create a continuous cycle of firing and reloading. Once the enemy are softened up by this treatment, they charge in and finish them off the old fashioned way.
    {Reiters_descr_short}	Effective gunpowder units, Reiters are armed with a pistol and spear, and protected by plate armour.
    And change it to this:
    Code:
    {GR_Dragoons}	Reiters
    {GR_Dragoons_descr}	Reiters derive their name from the German word reiter, meaning horseman. Generally from German states, Reiters are armed with a pistol and spear, and well protected by plate armour. They often employ the shooting circle tactic to create a continuous cycle of firing and reloading. Once the enemy are softened up by this treatment, they charge in and finish them off the old fashioned way.
    {GR_Dragoons_descr_short}	Effective gunpowder units, Reiters are armed with a pistol and spear, and protected by plate armour.
    And you're all finished.

    You might want to change the actual text to something more appropriate of course. But my fingers are getting tired from typing all this.

    Thank you for flying Musashi mod lines, we hope you have a pleasant modding experience.
    Last edited by Musashi; 12-22-2006 at 02:24. Reason: Added Unit Portrait + Info about DB file
    Fear nothing except in the certainty that you are your enemy's begetter and its only hope of healing. For everything that does evil is in pain.
    -The Maestro Sartori, Imajica by Clive Barker

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Single Sign On provided by vBSSO