Notice: Modding tutorials assume you know at least the basics of coding or scripting. Commander Wars uses Javascript as the Scripting Language. In case you want to learn more about Javascript, you can check the tutorial here: Derek Banas' Javascript tutorial , purchase O'Reilly's excellent book on the subject JavaScript: The Definitive Guide, or check out W3 Schools Interactive Tutorials

This tutorial references https://github.com/Robosturm/Commander_Wars/blob/master/resources/scripts/cos/co_andy.js, the source code of the actual vanilla Andy in COW.

THIS IS UNFINISHED DO NOT COMPLAIN ABOUT MISSING SECTIONS

Small Disclaimer

This will only go through vanilla Andy's js code, and not any other files. This is intended for newer players to understand the workings of what the code they're copy-pasting actually does. If you want to make a brand new CO in a mod, a good starting point is Custom CO. Alternatively, download a mod and edit to suit your needs.

Also I refer to normal CO powers as COP and super CO powers as SCOP, just clearing that up

Some stuff in the header

var Constructor = function()
{

The very first line (or two) of code. This defines a variable called Constructor to be a function. What does the function do? It's defined in the curly brackets {} following it. Notice how only the opening bracket is present. This is a long function (the whole CO).

    this.getCOStyles = function()
    {
        return ["+alt", "+alt2", "+alt3"];
    };

Due to some js... weirdness, we treat functions as objects that you can define properties of. If we called Constructor.getCOStyles() after finishing the Constructor function, we would get this. Specifically it would return ["+alt", "+alt2", "+alt3"]. This is telling the game to look for alternate CO images labeled "andy+alt", "andy+alt2", and "andy+alt3" as well as simply "andy". If you look in the corresponding images folder ([1]), we do actually find said images. This is Commander Wars's way to get CO styles, so if you want to have extra costumes for your CO, this is how you do it.

    this.getAiUsePower = function(co, powerSurplus, unitCount, repairUnits, indirectUnits, directUnits, enemyUnits, turnMode)
    {
        if (turnMode === GameEnums.AiTurnMode_StartOfDay)
        {
            if (co.canUseSuperpower())
            {
                return GameEnums.PowerMode_Superpower;
            }
            else if (powerSurplus <= 0.5 &&
                     co.canUsePower())
            {
                return CO.getAiUsePowerAtUnitCount(co, powerSurplus, turnMode, repairUnits);
            }
        }
    };

This is a custom function for the AI behavior of Andy. If it looks scary, that's because it kinda is there's just a bunch of variables and if statements flying around. Let's break this down further

    this.getAiUsePower = function(co, powerSurplus, unitCount, repairUnits, indirectUnits, directUnits, enemyUnits, turnMode)
    {

Again, a function definition. But this time, with words inside the function() brackets. Those are called parameters, and how you can pass data into a function. Here, the game is passing in:

  • The CO (co) (specifically the player's instance of a CO, in an andy mirror match both andys are actually considered different COs)
  • The power charge more than what the COP needs (powerSurplus)
  • The count of all owned units on the field (unitCount)
  • Count of all units less than 10hp (repairUnits)
  • Count of all units that can shoot at more than 1 range (indirectUnits)
  • Count of all units not an indirect unit (directUnits)
  • The number of enemy units
  • The turn mode of the AI, set to start of day, during the day, and end of day.

The vast majority of the time, a significant portion of these will not be used (for example, Andy doesn't really care if his units are direct or indirect, so long as they're repaired)

        if (turnMode === GameEnums.AiTurnMode_StartOfDay)
        {

This checks that the turn mode is start of day. This makes sure that Andy only ever uses his power at the start of each day.

            if (co.canUseSuperpower())
            {
                return GameEnums.PowerMode_Superpower;
            }

If Andy can use his SCOP of course he uses his SCOP

            else if (powerSurplus <= 0.5 &&
                     co.canUsePower())
            {
                return CO.getAiUsePowerAtUnitCount(co, powerSurplus, turnMode, repairUnits);
            }

If Andy has at most 0.5 stars more than his COP (and if he can use his COP in the first place), return CO.getAiUsePowerAtUnitCount(co, powerSurplus, turnMode, repairUnits);?

Referencing CO.getAiUsePowerAtUnitCount, it first checks if turnMode is equal to start of day, and also if repairUnits (in Andy's getAiUsePower at least, the name is changed during the function call to unitCount) is at least 5.

If either of these conditions are not fulfilled, don't use any power.

If both of these conditions are fulfilled, use SCOP is possible, and use COP if powerSurplus <= 0.5 (and if COP is usable in the first place)

So essentially, Andy doesn't want to Hyper Repair unless he has just enough power charge and if he can repair at least 5 units.

        }
    };

Closing brackets you always need those

You may be put off at the lack of a return statement here. Won't the code break if the function doesn't return anything?

I'm put off too.

Also the semicolon at the end? This is because we're actually defining a variable (getAiUsePower) as this function. Defining a variable is a code statement. We need semicolons after each code statement so the computer knows where to end each block of code. This is a property of c++ and java as well as javascript.

Next segment!

Power stuff

    this.init = function(co, map)
    {
        co.setPowerStars(3);
        co.setSuperpowerStars(3);
    };

init() is generally a function called to make sure that something is ready and to set up any needed variables. In this case, the only things that are done are setting COP stars to 3 and setting SCOP stars to 3. Note how the SCOP does not cost 3 stars, rather this is 3 stars on top of the COP cost of 3 stars, for a total of 6 stars. Since the next function probably won't fit on the screen all at once, I'll just break it down now.

    this.activatePower = function(co, map)
    {
        var dialogAnimation = co.createPowerSentence();
        var powerNameAnimation = co.createPowerScreen(GameEnums.PowerMode_Power);
        dialogAnimation.queueAnimation(powerNameAnimation);

The function is called activatePower, which is used when you activate power (COP specifically)

dialogAnimation and powerNameAnimation are used for the flashy effects whenever you use a power, the ones that appear, fill the screen with the power name, and disappear before your units get sparkles on them.

.queueAnimation is used to make sure that the whole screen is filled after the dialog finishes.

        var units = co.getOwner().getUnits();
        var animations = [];
        var counter = 0;
        units.randomize();

To go through all the units and make animations, we'll need to get all the units and have a place to store all the animations. counter is set to 0 and will correspond to animations's size (incidentally both are 0 right now) units.randomize() makes sure that the units will be considered in a random order. Since animations happen in the same order, the animations are randomized as well.

        for (var i = 0; i < units.size(); i++)
        {
            var unit = units.at(i);

The for loop will iterate through the units, with i being the index and unit being the current unit. This is randomized because units was randomized beforehand.

            var animation = GameAnimationFactory.createAnimation(map, unit.getX(), unit.getY());
            animation.writeDataInt32(unit.getX());
            animation.writeDataInt32(unit.getY());
            animation.writeDataInt32(CO_ANDY.powerHeal);
            animation.setEndOfAnimationCall("ANIMATION", "postAnimationHeal");

Here the animation is set up. The animation is created on the map at the unit's position in createAnimation. Then the unit's position is written to the animation and CO_ANDY.powerHeal. powerHeal is an integer specifying the COP healing, in this case 2. The variable is useful to avoid "magic numbers", constant values that are typed in directly. If you want to change a magic number, you have to manually go into the code and edit every instance of that magic number. Keeping your constants in variables like CO_ANDY.powerHeal allows you to change the value quickly and easily from one place. You'll see variables like this later in the code.

At the end of the animation, the units will be healed for 2 hp. postAnimationHeal uses the prior three values to know what position to heal as well as how much to heal. setEndOfAnimationCall tells the animation engine to call a function (in this case postAnimationHeal) from an object (ANIMATION) at the end of the animation. Here's the actual postAnimationHeal if you're curious. [2]