GRAW Adding new characters.
By: Kenneth Johansson/GRIN
Published : 29 November 2006

This tutorial is the missing character tutorial! When GRIN shipped modding tutorials with GRAW patches one of the guides was overwritten by mistake. Thanks to GRIN_Wille we now have this tutorial, as originally written by Kenneth Johansson of GRIN.

The guide shows in great depth how to mod your own character models into GR:AW.

Depending of what sort of character you want to add/replace you should use the appropriate max file as a base, this is to make sure that all the necessary align objects that are needed for that type of character are present when exporting.

The supplied max files are:

ghost_lead.max – Use this file if you want to make a new singleplayer ghost character (Could be either the player himself or a teammate). The file contains additional align ojbects, such as the camera align for the crosscom, and twist bones on the arms to support first person view.

mex_mp.max – Used for multiplayer characters. Much the same as ghost_lead but with a few objects removed for easier use.

mexican_army_rifleman – Used for singleplayer enemy characters. An even more optimized rig without twist bones and reduntant align objects.

The following two max files contains skeleton animation data only:

default_pose_skeleton – A default T-pose. Use it when skinning your character to the skeleton.

ragdoll_pose_skeleton – Used to make sure that characters behave more natural when they die and ragdoll. This pose should be applied on the skeleton just before you export it to the game.

In 3dsmax, to load a different pose onto your skeleton go to File>Merge Animation and load the max file containing the pose you want. Press Auto Name Mapping to match the imported bones with your current ones, and then press Merge Animation to apply it to your skeleton.

Remember: When skinning your character make sure that the Bone Affect Limit is set to 2 (two). (This option can be found under Advanced Parameters on the skin modifier rollout.)

Model xml

In order to make your character work ingame you need to edit a few things in the model xml. In this case I will use mex_mp.xml as an example.

Let’s say you’re making a character named captain_convoy to be used in multiplayer. We need to create a new folder for him under data\objects\beings\ called captain_convoy. This is where you put the diesel, model xml, and material xml for that character.

So, in this folder you should have

captain_convoy.diesel (That’s the file exported from 3dsmax containing your model)
captain_convoy.xml (The model.xml this should be a copy of mex_mp.xml renamed to captain_convoy.xml we are going to edit this file to make it work with your new character)
material.xml (I’ll explain this later on)

Alright, lets open up captain_convoy.xml

Take a look at this line of code:

<diesel file="/data/objects/beings/mex_mp/mex_mp.diesel" orientation_object="root_point" materials="/data/objects/beings/mex_mp/materials.xml" viewports="default|crosscom"/>

It tells the engine where to find the model file (.diesel) and the materials xml file (materials.xml). You’ll need to edit the paths so that they point to your new character’s location.

After the appropriate changes has been made, the line should look like this:

<diesel file="/data/objects/beings/captain_convoy/captain_convoy.diesel" orientation_object="root_point" materials="/data/objects/beings/captain_convoy/materials.xml" viewports="default|crosscom"/>

Lets move on, the next piece of code you need to take a look at is:

<graphic_group name="mex_mp" culling_object="gfx_body_loda">
<lod_object name="body">
<object name="gfx_body_loda" shadow_caster="true" max_distance="1000" increase_bounding_volume="600" max_draw_lod="0"/>
<object name="gfx_body_lodb" shadow_caster="true" max_distance="1500" lod="1"/>
<object name="gfx_body_lodc" shadow_caster="true" max_distance="2000" lod="2"/>
<object name="gfx_body_lodd" shadow_caster="true" max_distance="15000" lod="3"/>

This is where you specify the culling properties and LOD (Level Of Detail) steps for the character. Depending on the polygon count of your character, you might not need lod steps, but it is still highly recommended in order to keep the framerate up. I won’t go into details regarding these two subjects, they will be covered in another document later on. But they are pretty self explanatory.

Characters can be divided into multiple graphic groups. As you can see in this xml there are three groups:

mex_mp – The main body of the character. Could be named whatever you want, perhaps body is more appropriate. If you are making a non playable character, such as an enemy, you only need this group.
gloves – I you’re making a playable character (as in he will be viewed in first person) the mesh for the hands needs to be put in this group. This is to prevent unwanted culling of the hands wich can occur if they are attached to the body. Must be named “gloves” or the game won’t know what to to with it.
head – Like the gloves, if your making a playable character the head mesh and everything that is on the head, like helmets, hats, monocles, etc needs to be put in this group. Objects in this group will not be rendered in the player’s viewport, but will be visible in third person. This is to prevent the mesh from clipping with the viewport camera. Same as gloves, must be named “head”.

So basically, if your making an enemy character for use in singleplayer, make the entire character as one mesh and put it in a graphic group named “body”. If your making a character for multiplayer, or a playable character for use in singleplayer, make sure to separate the head and the hands from the body and put them in their corresponding graphic groups.

And that’s it really. Now let’s take a quick look at the materials xml

Materials xml

The material.xml is pretty self explanatory, just make sure you use the “skinned_bump” shader on all meshes that has a skin modifier on it.

If you apply a “skinned_bump” shader to a mesh that has no skin modifier on it, the game will most likely crash.

Example (from mex_mp):

<material name="mex_mp_body" xsrc="skinned_bump">
<diffuse_texture file="mex_mp_body_df"/>
<bump_normal_texture file="mex_mp_body_bm"/>

name – The name of the material applied to the mesh in 3dsmax.
src – Defines what shader to use, in this case “skinned_bump”. For a character without normalmaps you should use “skinned_diffuse”
diffuse_texture – Defines wich diffuse texture file to use.
bump_normal_texture – Defines wich normalmap texture to use. (This line can be removed if you're not using a normalmap shader)

Remember: The only thing that matters when exporting from 3dsmax is the material name, it doesn’t matter wich texture files you have applied. You still have to define them in the material.xml.

Coming up: The unit.xml!


The only thing you really need to change in the unit xml is the name of the unit and the path to the model xml file, the rest should be as it is. Unless you want to do some advanced changes to the characters. But that will have to be covered in another tutorial. This is just the basic stuff to get your character creation going.

If you simply wan’t to replace a specific character, you could just change the path to the model.xml for that character, instead of making an entirely new one. But for the sake of learning things, Im going to show you how to make a completely new one.

So lets take a look at the stuff you need to change (Yet again I’ll start of with the unit file for mex_mp). You can find it in data\units\beings\u_multiplayer.xml) just search for mex_mp.xml and you should find a unit named “mex_domination”.

Copy the entire unit block, that is from <unit type="being" name="mex_domination" slot="5"> all the way down to </unit>

Now you have a copy of the mex_domination unit, lets change the name and paths so that it loads your new character instead.

The top three lines should then look like this:

<unit type="being" name="captain_convoy" slot="5">
<model file="/beings/captain_convoy/captain_convoy.xml"/>
<network sync="client" remote_unit="mex_domination_husk" sync_rotation="false">

And there you have it, a new unit named “captain_convoy” ready to be spawned!

Actually, not yet.. there’s one last thing to do. Look at the third line:

<network sync="client" remote_unit="mex_domination_husk" sync_rotation="false">

Do a search for “mex_domination_husk”. You should find another unit named, go figures: “mex_domination_husk”. This is a special unit used only for multiplayer characters. I have no idea what it’s actually used for, so let's just make a copy of that unit, rename it to “captain_convoy_husk” and change the model file path to the same as the captain_convoy unit.

Finally go back to the original captain_convoy unit, and on the third line change the remote_unit to the newly created husk. Should look like this:

<network sync="client" remote_unit="captain_convoy_husk " sync_rotation="false">

And that would make the three top lines of our captain_convoy unit look like this:

<unit type="being" name="captain_convoy" slot="5">
<model file="/beings/captain_convoy/captain_convoy.xml"/>
<network sync="client" remote_unit="captain_convoy_husk" sync_rotation="false">

And that’s all you need to do! Hopefully your character should work now.

Using your character in the game

Ok, so you have your new character all set up and ready to go. But how do you actually use him ingame?

If you’re making a singleplayer enemy or a ghost team member, all you need to do is edit the group_manager.xml found in data/lib/managers/xml/

Just change the name of wichever character you wan’t to replace with your new one, and he should show up ingame.

However, in this tutorial we are doing a multiplayer character, and that unit is nowhere to be found in the group_manager.xml

To change the units being used in multiplayer, you need to edit Gametype.dsf wich can be found in data\lib\script_network\gametype\.

Do a search for “mex_domination” and you should find a couple of lines that looks something like this:

_sides.push_back( Side.SideServer().init( 1, Localizer.lookup("status_us_team"), "ghost_domination" ));

_sides.push_back( Side.SideServer().init( 2, Localizer.lookup("status_mex_team"), "mex_domination" ));

Simply change “ghost_domination” or “mex_domination” depending on which team you wan’t to change, to your new unit’s name. And it should work.