How To Add or Modify Mechs - Subject9x/battleMETAL GitHub Wiki

This article covers how to add a new playable mech to the game. This article also explains how to modify existing mechs, 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.

Example

Balaket Light Mech

Mech Data Setup

Data for mechs are kept in the following folder: (code root)/common/data/mechs/

Every mech has a definition file that looks something like this: Data_balaket.qc

Inside the definition file, the data for a mech is contained in a ini function: data_ini_balaket_(){ ... };

This function is where all the mech data is loaded onto the mech 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 mech 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 Mechs

[WARN] _There is a maximum limit of 256 unique mechs 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 mech 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/mechs/

  • Then copy the file data_balaket.qc, this is the quick way of standing up a new mech file.
  • Rename this copy to data_(your new mech).qc.
  • Open this new file.
  • Change the function name from
    • data_ini_balaket_ to data_ini_(your new mech)_

Next there’s 1 major variable that needs to be updated for new mechs: self.data_idx This is used by the game as a unique identifier for the mech, this must be unique. The easiest way to keep track is to look at /common/data/mechs/uid_mechs.qc to find the next unique number to assign to your new mech.

  • 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
  • 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.

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_balaket.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

    • Max amount of Energy the unit can have.
  • self.energyRate

    • the amount of Energy gained every frame when the unit can recharge.
  • self.shieldMax

    • Max amount of shields the unit can charge up.
  • self.shieldRate

    • the amount of Shield the unit can charge every frame
  • self.startupDelay

    • time in seconds it takes for mech to fully powerup on player-spawn.
  • self.evasionDrain

    • amount of .energy spent for mech to move at Evasion speed.
  • 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

    • This defines the base-line convergence for the unit. The following are allowable values for this variable:
      • ACCURACY_SKIRMISH
      • ACCURACY_SNIPER
      • ACCURACY_MARKSMAN
      • ACCURACY_LOWTECH
      • ACCURACY_PRIMITVE
      • The exact value of each can be found here
      • type the value exactly as it appears above, this is a vector var, not a string.
  • self.data_speed_forward

    • unit's max forward speed.
  • self.data_speed_strafe

    • unit's max strafe speed, factors in whenever moving left-or-right.
  • self.data_speed_backward

    • unit's max reverse speed.
  • self.data_speed_accel

    • unit's speed key accleration. Quake has a 'run' mechanic when pressing (usually) shift, this is the value that determines the multiplier to the unit's speed while 'running.
  • self.ramUpMax

    • time in seconds it takes to charge up the mech's ram-shock move.
    • total ram duration is ramUpMax / 2.
  • self.ramCooldown

    • time in seconds it takes for mech to recharge its ram-shock move.
  • 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

Mech Parts - Explained

This section details how to create mech parts, some of which your new mech require in order to work in the game.

  • ifded CSQCQ
    • this must be before the part ini function calls for any mech data!

3 Primary pieces

The new mech requires the following 3 pieces to be created, no exceptions

  • Center Torso
  • Legs
  • Camera

All Mech parts are created using the following function call, you can see this in data_balaket.qc

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
        • M_ARM_LEFT
        • M_ARM_RIGHT
        • M_LEGS
      • The game uses this value when locating parts on a unit.
    • 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 mech pieces and so when defining each piece of your mech - you’ll need a model for it.
    • Max Health

      • Defines the maximum allowable health for this part. New copies of this unit get this value for the unit piece at the start. Current health stats are balanced against existing Weapon damage characteristics, modifying these values will affect overall gameplay experience.
    • 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] If you are thinking of making a mech with no side torsos, then you should treat the side torso pieces as arms and do not mount arms themselves.

  • data_ini_unitPiece_( M_TOR_LEFT, “the/mechs/arm_model”, …)

[INFO] if you want any mech 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.

Mech Parts - The Camera

[WARN] all units must have 1 and only 1 camera piece.

The camera is a unique mech piece that defines where the Player’s view will be when the Player is 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 mech pieces filled out, we can move on to adding Hardpoints to the mech.

Hardpoints - Explained

The next step to creating your own mech data is to define the hardpoints for the mech. 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.
    • 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 SizeType

      • This values defines the acceptable Size-and-Type of Weapons allowed in Hardpoint
      • Every weapon has a SizeType bitflag value. see here
    • 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 | … )

Make Functional

The last step for creating your mech 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 mech available for play, you must complete the following steps:

  • common/data/data_system.qc
  • Locate the function:
    • void() initialize_data_mech ={....}
      • You will see a bunch of SWITCH: CASE blocks, each one calling a specific data_ini_(mech) function.
      • To get your mech on the list, simply add a new block above the DEFAULT case like so
        • Case <your mech id>: data_ini_<your mech>_(); 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.

And that’s it for adding new Mech Data. Now post it online, and celebrate!

[INFO] for adding or modifying mech HUD data, please see the appropriate article. [INFO] for adding this mech data as an enemy AI, please see the appropriate article.

⚠️ **GitHub.com Fallback** ⚠️