How To Add or Modify Vehicles - Subject9x/battleMETAL GitHub Wiki
This article covers how to add a new vehicle to the game. This article also explains how to modify existing vehicles, because the pipeline for both is fairly identical. The process for adding / modifying mech data is a mix of game code and 3D assets, depending on what a person would like to accomplish.
Vehicles are not playable in vanilla battleMETAL but can be with some quick modding (tutorial to come)
Example
Add Vehicle to Map? see this article.
Vehicle Data Setup
Data for Vehicles are kept in the following folder: (code root)/common/data/vehicles/
Every Vehicle has a definition file that looks something like this:
Data_foslager.qc
Inside the definition file, the data for a Vehicle is contained in a ini function:
data_ini_foslager_(){ ... };
This function is where all the Vehicle data is loaded onto the Vehicle being spawned by the game code. Data is organized by use, and labelled with comments for clarity.
Just Modifications
If you are just modifying existing Vehicle data, then simply changing values here will suffice. To test your changes, you must recompile progs.dat and csqc.dat because the data is stored in Quake C. Once you compile, your changes will be seen when you fire up battleMETAL.exe.
**Adding New Vehicles **
This next process will take you through the steps of adding a brand new Vehicle to the game. This will involve doing some level of coding but I’ve tried to keep the amount as low as possible. Let’s start by going to the following folder:
(code root)/common/data/vehicles/
- Then copy the file
data_foslager.qc
, this is the quick way of standing up a new Vehicle file. - Rename this copy to
data_(your new Vehicle ).qc
. - Open this new file.
- Change the function name from
data_ini_foslager_
todata_ini_(your new Vehicle )_
Next there’s 1 major variable that needs to be updated for new Vehicles:
self.data_idx
This is used by the game as a unique identifier for the Vehicle , this must be unique. The easiest way to keep track is to look at /common/data/vehicles/uid_vehicles.qc
to find the next unique number to assign to your new Vehicle .
-
self.vec_name
- Used by the game for display purposes. Doesn’t have to be unique, though best-practice is to make it unique.
-
self.vec_size
- Used by game for sorting and AI reaction purposes. Think of it as an abstract weight-class system.
- min size of 1
- max size of 3
- Used by game for sorting and AI reaction purposes. Think of it as an abstract weight-class system.
-
self.max_health
- total health of the center torso of the unit. All units die when their center torso health = 0!
-
self.mins
-
self.maxs
- These two variables define the collider size of the unit in-game. Quake uses 2 vector variables for collision size described as:
- mins = ‘ -X -Y -Z’
- maxs = ‘ X Y Z’
- X / -X = Forward and Rear depth.
- Y / -Y = Left and Right length of the bounding box.
- Z / -Z = Height and Depth of the bounding box.
- These two variables define the collider size of the unit in-game. Quake uses 2 vector variables for collision size described as:
Quake uses Axis-Aligned Bounding Boxes (AABB) for its collision detection. What does this mean for battleMETAL? It means all units are encased in boxes for collisions, and only ever boxes. The axis-aligned part means those boxes never rotate. The end result is that a ‘correctly’ sized box has the X and Y values equal to each other and split between positive/negative.
Example: data_foslager.qc
* self.mins = ‘ -14 -14 -35 ’;
* self.maxs = ‘ 14 14 16 ’;
* This equates to a bounding box that is 28 units wide, 28 units deep, and 51 units tall.
-
self.energyMax
- (optional)
- Max amount of Energy the unit can have.
-
self.energyRate
- the amount of Energy gained every frame when the unit can recharge.
-
self.shieldMax
- (optional)
- Max amount of shields the unit can charge up.
-
self.shieldRate
- (optional)
- the amount of Shield the unit can charge every frame
-
self.radar_range
- range in game-units of the unit's radar.
-
self.w_firetime
- This defines the lock-on time in seconds for the mech to acquire a lock on a hostile target. For players this value is straight, only modified if the player takes a piece of equipment. For AI, this will be adjusted by the AI system based on game difficulty and AI skill rank.
-
self.spreadDefault
- Vehicles are controlled by AI, their spread values are set by AI control code here
-
self.m_fspeed
- unit's max forward speed.
-
self.m_sspeed
- unit's max strafe speed, factors in whenever moving left-or-right.
-
self.m_bspeed
- unit's max reverse speed.
-
self.m_maccel
- mostly unused for AI vehicles.
-
self.yaw_speed
- AI Only
- references the Quake builtin variable. This is used to determine how quickly an AI can rotate.
-
self.turret_yaw_speed
- AI Only
- This determines how quickly an AI can rotate its turret / torso components
Vehicle Parts - Explained
This section details how to create Vehicle parts, some of which your new Vehicle require in order to work in the game.
3 Primary pieces
The new Vehicle requires the following 3 pieces to be created, no exceptions
- Center Torso
- Legs
- Camera
All Vehicle parts are created using the following function call, you can see this in data_foslager.qc
self.model = ""
For Vehicles, their 'base' model is their chassis, they do not need to specifically assign a model to M_LEGS.
Vehicles do not have hit locations like mechs, any model attachments beyond M_TOR_CENTER are for cosmetic purposes only.
data_ini_unitPiece_();
- This function takes the following parameters in the listed order:
-
partTypeId
- This is a specific value, and you should keep these unique. The following are the acceptable values and its case-sensitive.
- M_TOR_CENTER
- M_TOR_LEFT
- M_TOR_RIGHT
- This is a specific value, and you should keep these unique. The following are the acceptable values and its case-sensitive.
-
Model Path
- This is a string, which defines the file path of the 3d model you’d like to use for this part. battleMETAL uses separate files for its vehicle pieces and so when defining each piece of your vehicle - you’ll need a model for it.
-
Max Health
- default to '1' because vehicles do not have hit-locations!
-
Offset from Center
- This is a vector, as defined by single quotes and 3 decimal numbers - ‘ X Y Z ’.
- these are game units for how far from the center of the unit the mech piece will be.
- Positive X is Right-side and Negative X is Left-side.
- Y is up and down.
- Positive Z is Forwards and Negative Z is Backwards.
- The game will automatically rotate the component around the center of the unit it is attached to, so you don’t need to worry about fine-tuning angles. The game also does not put any collision on these models, so they can overlap to any degree desired without causing issues either.
-
[INFO] vehicles cannot have ARM parts, at most they can have TORSO parts.
[INFO] if you want any vehicle component to not have a model, simply pass in “q3mdl/testball.md3”
as your model and set the offsets to ‘hide’ the ball model inside another mesh.
Vehicle Parts - The Camera
[WARN] all units must have 1 and only 1 camera piece.
The camera is a unique vehicle piece that defines where the AI’s view will be when the AIis controlling the unit. The camera uses a special function data_ini_camera()
. The only value you are allowed to modify is the offset_from_center.
Once you have all the vehicle pieces filled out, we can move on to adding Hardpoints to the vehicle .
Hardpoints - Explained
The next step to creating your own vehicle data is to define the hardpoints for the vehicle . Hardpoints are the equipment slots that a unit in battleMETAL possess in order to use weapons and modules. A unit **must have at least 1 ** hardpoint defined IF you want that unit to mount any weapon/item in the game, no exceptions.
[INFO] _you can make ‘unarmed’ units as well, just don’t define any hardpoints, and make sure the unit is never given any weapons.
[WARN] _ maximum allowable hardpoints is 9._
Each hardpoint is defined using the following function call:
-
data_ini_unitHardpoint_X( ParentId, offsetFromParent, adjustAngles, hardpointSize, hardpointType);
-
Parent Id
- Similar to the field from
data_ini_unitPiece_
. This defines which unit part the hardpoint is attached to. Ideally whichever part you assign this to, you’ve defined above it using the previous section.
- Similar to the field from
-
Offset From Parent
- This is a vector, as defined by single quotes and 3 decimal numbers - ‘ X Y Z ’.
- These are game units for how far from the center of the unit part the hardpoint will be.
- Positive X is Right-side and Negative X is Left-side.
- Y is up and down.
- Positive Z is Forwards and Negative Z is Backwards.
-
Adjust Angles
- This is a vector, as defined by single quotes and 3 decimal numbers - ‘ X Y Z’.
- These values are degrees of rotation to be applied to the weapon placed in this hardpoint.
- X = pitch.
- Y = yaw.
- Z = roll.
- These values are optional and mostly for cosmetic purposes. A value of ‘0 0 0’ is completely acceptable for making no adjustment.
-
Hardpoint Size
- This value defines the maximum allowed Size of equipment to place in the hardpoint.
- Every weapon has a Size value for balancing purposes. If a weapon is larger than the Size of the hardpoint, then the weapon cannot be mounted to this hardpoint.
-
Hardpoint Type
- This value defines the types of weapons that can be mounted to the hardpoint.
- Every weapon has a Type value for balancing and game purposes.If a weapon’s type is not included in the hardpoint’s allowable types, then the weapon cannot be mounted to this hardpoint.
- The following are the defined types of weapon.
DMG_BAL
- Ballistic Damage.DMG_ENE
- Energy Damage.DMG_EXP
- Explosive / Missile Damage.DMG_MSC
- Miscellaneous; usually used for stat-buff modules like Radar, etc.- The desired types are arranged like the following when being used in the function:
( type | type | … )
- The desired types are arranged like the following when being used in the function:
-
[INFO] _AI weapon loadouts are set here and as such, Hardpoint Type isn't that important at this stage.
Make Functional
The last step for creating your vehicle data is to get this wired into the game data system. Remember the data_idx variable from the top of the file? This is why it needed to be unique. To make your new vehicle available for play, you must complete the following steps:
common/data/data_system.qc
- Locate the function:
void() initialize_data_vehicle ={....}
- You will see a bunch of
SWITCH: CASE
blocks, each one calling a specificdata_ini_(vehicle )
function. - To get your vehicle on the list, simply add a new block above the
DEFAULT
case like soCase <your vehicle id>: data_ini_<your vehicle >_(); Break;
- The break; is very important, this should always be at the end of any of your new Case statements. This allows the code to leave the function early, without having to check any other cases.
- You will see a bunch of
And that’s it for adding new Vehicle Data. Now let's get this bad boy into a map, see this article.