Modding - Robosturm/Commander_Wars GitHub Wiki

Introduction

Commander Wars is especially designed to be modable. The reason beeing is that Advance Wars Games differed a lot in themself and a lot of people like to add their own CO Unit or building to the game.

For debugging and testing take a look here

For Variable Support take a look here

For a general tutorial on JavaScript visit: https://www.w3schools.com/js/

Modding Concept

Commander Wars uses Qt's Qml-Engine to extend and provide unit, co, terrain, building etc. data to the core C++-Engine. Making it easy to add new functionality to the game by providing a javascript.

In general the C++-Engine loads and finds all scripts that are in the specific folders and treats them as such. E.g.: A javascript in the unit folder is treated as a unit. The idea is to provide an extra folder which contains the same folder hierachy as the base game and add it to the game modding path (see the ini-file generated by the game). The game than loads the javascript files in the modding folder instead of the normal script if it has the same name.

Another important concept is that all objects are owned by the C++-Engine by default -> see the Qt-Documentation for JavaScript-Ownership. Thus objects especially QmlVectors have to be deleted by the Javascript to avoid memory-leaks since the garbage-collector won't delete them.

Also the C++-Engine uses all javascripts as callback functions with the actual C++-Object as a pointer. Take a look at the general-script folder to get the list of callbacks used by the engine.

Base Classes for Units, Terrain, etc.

The resource folder resource/general holds the base javascript classes for each class type you can add. You need to derive from them in order to get a well function new unit, co etc. Afterwards you can overwrite the functions you need for your new unit, co etc. All other functions will have a default behaviour. The best way to learn how to create a new unit, co or ingame action is to check out the existing ones.

Global Objects

This is a list of global objects that are additionally provided by the game in addition to Qml-Objects and Javascript-Objects like Math or Qt.

  • map -> the current map object
  • GameConsole -> the ingame console reachable via F1
  • audio -> the audio engine use it to play cool sounds and music. Let's rock.
  • globals -> variable containing static functions provided to the engine -> like randInt
  • coSpriteManager -> access for removing and manipulating some co data from the game
  • unitSpriteManager -> access for removing units from the game
  • buildingSpriteManager -> access for removing buildings from the game
  • terrainSpriteManager -> access for removing terrains from the game
  • coPerkSpriteManager -> access for removing perks from the game
  • Global -> pointer object to the global javascript object which owns everything
    • Using this object is key to access certain information from anywhere in the game. The object contains all loaded javascripts in a table accessing one of the scripts can be done by the following line:

      Global["INFANTRY"]

    • This would give you the infantry script functions into your hand and allows you to access all functions of that object. For example the following code would access the static unit type of a given unit id:

      Global[unitId].getUnitType()

What functions of the C++ Engine are avaible.

Take a look at the header of the object you want to use, e.g game/unit.h for units. All functions listed under public slots: can be called and used by your modding scripts.

Action Modding with AI

Actions starting with the following name need to fullfil the following requirements so the AI will use them:

  • ACTION_SUPPORTSINGLE Actions starting with this name must have a another selectable single unit as target. Compare with ACTION_SUPPORTALL_REPAIR
  • ACTION_SUPPORTALL Actions starting with this name must have no other options. Compare with ACTION_SUPPORTALL_RATION
  • ACTION_PLACE Actions starting with this name must have a single field as target. Compare with ACTION_PLACE_WATERMINE

As a guideline of avaible commands:

  • either clone the repository or go on github into the folder game. All files ending with .h are the interesting once.
  • All functions that are listed below the line "public slots:" are avaiable in the scripts for use.
  • So for example if you have a player( getOwner() from a unit. You can go to the file game/player.h and everything listed below "public slots:" can be used in your scripts to create conditions and commands.
  • if a c++ function returns an Object starting with the name QmlVector make sure to call the function remove() before leaving the function in order to free the memory else you get some sweet memory leaks.

Getting Help

If a comment of the function or a function name aren't clear. Please contact me or open an issue and i will try to clarify the command in the header-file.

Attack/Weapon Damage modding

There are several options to easily add new units with old damage charts or new onces. Here's a list of the several ways you can do it.

Use existing stuff

This can be done in the unit script. E.g you created a new unit called stealth fighter. Those lines will make our unit take the same damage as a fighter.

STEALTHFIGHTER.getUnitDamageID : function()
{
    return "FIGHTER"; // unit id that will be used to calculate the damage we take
};

Modyfing existent weapons

Sometimes you wan't to use a complete new way on how you recieve damage. For that there are two ways: Solution a:

STEALTHFIGHTER.getUnitDamage : function(weaponID, defender)
{
    // weaponID string of the used weaponID
    // defender pointer to the which is attacked or used to check how much damage we will deal to it
    // gets called if no normal damage entry was found.
    // use this function to impl the damage this unit takes from certain weapons
    return -1;
};

Solution b: Modify the damage tables for a unit in a single file:

Global["WEAPON_A_AIR_GUN"].damageTable.push(["STEALTHFIGHTER", 150]);
Global["WEAPON_HOVERVULCAN_CANNON"].damageTable.push(["STEALTHFIGHTER", 150]);

CSV-Support for Movement and Weapon Tables

Each column is seperated by a ; and id's are always treated/converted into upper case words. The Header for weapon tables is:

weaponid;weaponname;@custom;INFANTRY
weapon_recon_mg;;;200
weapon_dummy;;dummy;100

And the file has to have the name weapontable.csv in the folder resources\scripts\weapons The header line for movement tables is

movementid;movementname;@custom;PLAINS
move_tire_a;;;1
move_dummy;;dummy;2

Both CSV-Tables have the same order: Empty lines have no impact e.g. leave the original value unchanged. -1 stands for unattackable or not possible to be crossed.

  • The first Column is the weapon id or movement id.
  • The seconcd is custom js code for example to add code for making buildings attackable:
this.getEnviromentDamage = function(enviromentId)
{
    return 45;
};
  • The third is the ingame name of the weapon or movement.
  • All other columns represent the terrain id or movement id you want to modify.

Modding Gamerules

Modding in a new game rule requires some extra infos. Modding in is similar to how new victory rules are modded. The main difference is that is that the script folder is rules and the base object is gamerule.js. But the most important part is gamerules do nothing by themself. It's up to you to use them. The first thing you need to know is how to get the infos about the selected rule setup. This can be done with the following lines of code:

var rules = map.getGameRules();

var rule = rules.getGameRule("RuleName");

Next you can read the script variables from the rule object as usual and enable, disable and execute code based on those variables.