(Created Andy Breakdown page, added basic intro text)
 
(Header code. There's actually a lot of it.)
Line 2: Line 2:


'''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 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.'''
== 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 ==
<syntaxhighlight lang="javascript" line="1" start="1">
var Constructor = function()
{
</syntaxhighlight>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).<syntaxhighlight lang="javascript" line="1" start="3">
    this.getCOStyles = function()
    {
        return ["+alt", "+alt2", "+alt3"];
    };
</syntaxhighlight>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 ([https://github.com/Robosturm/Commander_Wars/tree/master/resources/images/co/os]), 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.<syntaxhighlight lang="javascript" line="1" start="8">
    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);
            }
        }
    };
</syntaxhighlight>This is a custom function for the AI behavior of Andy. If it looks scary, that's because <s>it kinda is</s> there's just a bunch of variables and if statements flying around. Let's break this down further<syntaxhighlight lang="javascript" line="1" start="8">
    this.getAiUsePower = function(co, powerSurplus, unitCount, repairUnits, indirectUnits, directUnits, enemyUnits, turnMode)
    {
       
</syntaxhighlight>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)<syntaxhighlight lang="javascript" line="1" start="10">
        if (turnMode === GameEnums.AiTurnMode_StartOfDay)
        {
           
</syntaxhighlight>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.<syntaxhighlight lang="javascript" line="1" start="12">
            if (co.canUseSuperpower())
            {
                return GameEnums.PowerMode_Superpower;
            }
</syntaxhighlight>If Andy can use his SCOP of course he uses his SCOP<syntaxhighlight>
            else if (powerSurplus <= 0.5 &&
                    co.canUsePower())
            {
                return CO.getAiUsePowerAtUnitCount(co, powerSurplus, turnMode, repairUnits);
            }
</syntaxhighlight>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.<syntaxhighlight lang="javascript" line="1" start="21">
        }
    };
</syntaxhighlight>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.

Revision as of 14:59, 17 December 2023

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.

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.