battleMETAL is a successor to the 90's mech simulators of old. A delightful modernization of commanding giant robots bristling with firepower.
Players choose and customize their war machines, and then drop into the blighted world of Geiserath. Players will be tasked with completing a variety of mission types and they must choose the best mechs and weapons to complete their objectives. The initial campaign offers 12 missions and 4 difficulty settings.
battleMETAL sits somewhere between Mechwarrior 2 / Earthsiege and Quake. Mechs have specific move speeds for forward, strafe, reverse, and each mech has unique speed values. Player do not have to manage torso alignment, however. Default controls are FPS style. Combat is very much a mech-flavored affair, all mechs have proper hit-locations with the ability to destroy targets piece by piece. Mechs can have up to 9 weapon slots, along with 14 weapons and 7 upgrade modules.
Players will have to manage their mechs energy, shields, armor, and weapons to find success in battle. Combat scenarios offer a large variety of play styles and
approaches to mission objectives. Weather elements are present as well; rain, snow, and fog.
Rage through 12 campaign maps across desert, glaciers, and urban war zones. Follow a dark tale as a civil war triggers the arrival of something far worse...
did you know? battleMETAL game code is open-source and uses a common map-editing tool for map creation!
Players can tweak almost everything in the game's source code, and new maps can be built just like Quake mapping.
battleMETAL offers PvP in both Deathmatch and Team Deathmatch modes, as well as Co-Op support for the base campaign. Players will have to use port-forwarding to host their own servers at the moment.
your METAL is waiting. Lock-in and power up, DEAD_HAND.
This article covers how to add or modify items in battleMETAL. ‘Items’ are a catch-all for describing both Weapons and Equipment because there is a code distinction between the two, however both are used by the hardpoint system. Items are attached to units via hardpoints, the hardpoints are defined in the unit’s data_ file.
[INFO] This article is in-depth, laying out how exactly all the pieces of getting weapons to work in battleMETAL are arranged.
[INFO] take notice of the # ifdef CSQC
- these are compiler markers to pick what code is compile to CSQC and what is compiled for the Server.
Examples Non-projectile weapons - Light Laser
Projectile weapons - Ion Coil
Upgrade modules - Recharge Capacitor
Item Data Setup
Data for items are kept in the following folder: (code root)/common/data/items/
Every item has a definition file that looks something like this: Data_emp.qc
Inside the definition file, the data for a item is contained in a ini function: data_ini_weapon_emp_(){ ... };
This function is where all the item data is loaded onto the item being spawned by the game code. Data is organized by use, and labelled with comments for clarity.
Just Modifications
[WARN] back up your /id1/progs.dat
and /id1/csqc.dat
files before compiling any changes you make in Quake C!
[WARN] back up a copy of any .qc files you work on.
[INFO] if you are using the git source control tools, you can just keep your code in a side branch and you won’t have to backup files anywhere.
If you are just modifying existing item 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 Items
[WARN] There is a maximum limit of 256 unique items that can be in the game, this limit is found in /common/data/data_values_game.qc
This next process will take you through the steps of adding a brand new item to the game. This will involve doing some level of coding but I’ve tried to keep the amount as low as possible.
te_muzzle_emp
to te_muzzle_(your new item)
data_ini_emp_
to data_ini_(your new item)_
data_attack_emp_
to data_attack_(your new item)_
data_update_emp_
to data_update_(your new item)_
Next there’s 1 major variable that needs to be updated for new items:
/common/data/items/uid_items.qc
to find the next unique number to assign to your new item.Initialize the Item Data
First we’ll take a look at the main ini function where most of the Item data is kept. Go to the function named data_ini_(your new item)
. You must have the following variables set with your desired values in order for the item to work properly. This article uses /common/data/items/weapons/data_emp.qc
as the example values.
.data_idx
= 2;
.w_clipsize
= 1;
.reloadRate
= 0.1;
.reloadMax
= 6;
.energyRate
= 266.7;
energy
variable..w_range
= 1700;
.damageValue
= 400;
.damageType
= (DMG_ENE | EFF_STX | EFF_ENE);
Every item has a Type value for balancing and game purposes.The following are the defined types of weapon.
The desired types are arranged like the following when being used in the function: ( type | type | … )
note Beta 2 v1.0.0 deprecates most of the DMG_ types in favor of .equipSize
.techLevel
= 2;
.equipSize
= ;
.spreadDefault
= '0.009 0.008 0';
.wepFireOffset
= '0 0.1 7';
makevectors(wepAngles)
call plus weapon.origin
.w_name
= "";
.fire_sound
= "sound/weapons/emp_fire.ogg";
.model
= "q3mdl/weapons/w_emp.md3";
.abbrev
= "";
.description
= "";
.icon
= "gfx/ui/wep_icons/wi_mlgd.png";
.itemMuzzleFlash
= te_muzzle_lgm()
;
.w_isburst
= FALSE
.w_attack
= data_ini_attack_emp;
.think
= default_weapon_think;
.data_ini_projectile
= data_projectile_ini_emp_;
.item_run_upgrade
= <pointer to function>();
item_remove_upgrade
= <pointer to function>();
Define the Attack function behavior
The next step is to define the ‘fire’ or ‘attack’ behavior for the item. This function is called every time the unit or Player makes the ‘fire’ command.
Above your item’s ini function, write the following function definition: void() data_ini_attack_(your item name)_;
This allows the main item ini function to point to the attack function, and then you can define the attack function later, mostly for readability.
Now, below your ini function, create a function block that has the same name as the attack function like so: void() data_ini_attack_(your item name)_ ={...};
This is where you will put all the behavior for when the item is ‘fired.’
[INFO] using other existing weapons as examples will assist in writing the code for your own weapons.
There are few major sections to the attack function that are important too almost every item.
As seen with most of the original Energy weapons in battleMETAL, some weapons require the Unit have a required amount of energy stored before the weapon can be fired. The EMP is a good example, it requires the Unit to have 266.7 Energy available before it can fire. After during the fire function, this amount of Energy is also subtracted from the Unit’s total Energy. If the Unit does not have enough Energy to fire, the EMP cannot be fired.
This effect is achieved using the following function you should put at the top of the attack function block: if( !_ctrl_weapon_checkEnergy()_ ){ return;}
This will prevent the item from firing if the Unit does not have the energy amount prescribed in the weapon’s ini value of self.energyRate
.
Next we have the ammo-tracking function. Most items have a form of ammo and a time it takes to reload. To enable this functionality in your new weapon, you simply invoke the following function:
ctrl_weapon_updateAmmo_( **FALSE**, 1.75 );
This takes 2 main arguments - burstFire_, and burstRate.
burstFire is a TRUE / FALSE.
burstRate is divided by self.reloadRate to produce the ‘Recoil’ wait time between shots.
Other than these 2 values, the function takes care of the rest of the item state-management. Now that we have item management out of the way, we can move to actually executing the shot code itself.
The last step for defining the attack function for your new item is filling out any damage-dealing behavior, projectile spawning, or special effects.
battleMETAL takes care of the heavy lifting for you with a specific function called: ctrl_weapon_fireOffset();
This function calculates the required angle, positions, and the engine tracelinefunction call for this shot.
ctrl_weapon_fireOffset()
populates the following globals after being run:
In Quake based on calling traceline()
entity trace_ent
vector trace_endpos
float trace_fraction
float trace_plane_dist
(there are a few more, but these aren’t necessary for understanding. I do recommend you look them up if you want to get deeper into modding Quake C.)
battleMETAL custom globals
vector FIRE_OFFSET
entity WEAPON_PARENT
entity FIRE_ENT
vector FIRE_ORIGIN
vector FIRE_ENDPOINT
[WARN] do not rely on these globals to hold their value at all after you use them in the current function.
To have the item spawn a projectile, the following steps need to be taken:
That’s cool too; this is what’s called a ‘hitscan’ shot then, where the shot instantly hits whatever is at the FIRE_ENDPOINT of the shot. To set this up, we just call t_damage directly -
t_damage ( entity trg, entity inflictor, entity attacker, float dmg_amt, vector dmg_point, vector force );
Trg
Inflictor
Attacker
Dmg_amt
Dmg_point
Force
[INFO] best example of the above code is either the data_light_laser.qc or data_light_atc.qc weapons.
How about special effects?
Weapon special effects are defined in the weapon's te_muzzle_<weapon>
function. These muzzleflash functions are run in CSQC whenever a unit fires a weapon.
.attackFlag
with their hardpointId
bitflag.SendEntity
to each client.te_muzzle_<item>
function.Using other weapon files as examples, you can also have sound and particle effects triggered in this code.
Both systems use different function sets which are outside the scope of this article. There are numerous examples within the existing weapon files to understand the basics of doing special effects.
Define the Update function behavior
Remember this variable in your item’s ini function? self.think
=default_weapon_think_;
This defines the update function for the item during gameplay. The controlling code calls this function for every item the unit has, and on every frame (meaning very frequently).
The default function, default_weapon_think, basically handles reloading the item. You can find this function over in the file common/data/data_header.qc .
Majority of items in vanilla battleMETAL don’t adjust the think()
behavior, for the off-hand that you want to change some bits, this section details how to at least setup the alternate behavior.
Because this new update function is referenced in the _ini_
you will need to define it before the _ini_
. You can either write the whole function above the _ini_
or just the reference, and then define it later. For readability, I usually just define the reference and then write the function below.
Now that you’ve defined the function, make sure to assign this function to the item’s .think value, replacing default_weapon_think. self .think = (your new think function);
If you still want the default reload code in your custom think, you can just copy the code in default_weapon_think and past it into your new function. Other than that, the sky's the limit for adding behavior. To get the player entity in this function you can just call self.owner.
Wiring the Item into Place
The last step for creating your item 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 item available for play, you must complete the following steps:
common/data/item/uid_items.qc
Locate the function:
void() initialize_data_item_={....}
You will see a bunch of SWITCH: CASE blocks, each one calling a specific data_ini(item)_ function.
To get your item on the list, simply add a new block above the DEFAULT case like so
Case : data_ini_(your item)_()
; 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.
Now post it online, and celebrate! And that’s it for this article. I hope this clears up how to create your own weapons and equipment for battleMETAL.
[INFO] there is another article for adding your weapon to the menu system.
battleMETAL is built on the Darkplaces Quake sourceport, and is coded entirely in Quake's game code language of QuakeC. This article is a reference article...
battleMETAL now live on ModDB! in the tradition of great game modding, the game is now listed here too.
Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.