Creating a Single Player Mission

Win/Lose Conditions (5.4)

Lets make our mission winnable by adding a Win condition. If you haven't given the player any units to start with, do so now (place a couple units on the player's team near the player's start location). Place all of the player's starting units into a Tag (see Section 3.6: Tags Brush). Name the tag "players_units".

Lets say that the player needs to move his troops to a specific spot to win the mission. Create a Region somewhere near the player's start location. Name it "goal". Make it large enough to fit a few units inside. (see Section 3.5: Regions Brush). This will be where the player needs to go to win. You may want to paint or color the area under the region, or place an object there, so you can tell where it is in the game.

Now lets alter the "objective_player_at_goal" objective, so that it will test when the player is in the "goal" region, and give the Win screen when they are. There is a condition type for just this type of thing called "InRegion". Open "objective_player.cfg". Change the condition statement of the Objective to the following:

  Condition("InRegion")
  {
    Region("goal");
    Tag("players_units")
    {
      Amount(0);
      Operator(">");
    }
  }

...and replace the action statement with:

  Action()
  {
    Win();
  }

Your objective should now look just like this:

CreateObjectType("objective_player_at_goal", "Objective")
{
  Condition("InRegion")
  {
    Region("goal");
    Tag("players_units")
    {
      Amount(0);
      Operator(">");
    }
  }

  Action()
  {
    Win();
  }
}

The condition type InRegion calls for several bits of info as you can see. "Region" is the region to be tested. "Tag" is which tag will be tested. Then the tag wants input of its own, being "Amount" and "Operator". The example above is saying "greater than zero", or in other words "one or more" - "is there one or more object from this tag in the region?". (You can change the Amount and Operator values to suit many purposes. Amount can be any number. Operator will most often be either < (less than), > (greater than), or == (equal to / is).

The command to give the victory screen is simply Win();. Now load up your mission in the game. When you move your starting troops into the goal area, you should get the Victory screen. If you don't, go back and make sure you did everything correctly.

Our mission seems a bit easy, don't you think? Let's make a way to lose. First, place some enemies near the start location. Make sure to place them far away from the players units enough so they can't be seen immediately when starting gameplay. (We will move them in script.) Make the enemy force roughly match your player force. Now place all the enemy units into a tag and call it "enemy_units". Now let's make the player lose if all their units get destroyed before they can reach the goal.

Now we'll edit the AI's objective "objective_attack_player". Open objective_ai.cfg and replace the current objective_attack_player objective with this one:

CreateObjectType("objective_attack_player", "Objective")
{
  Condition("TRUE");
  Action()
  {
    ExecuteScript("attack1", "squad.move.tagtoregion")
    {
      Op("%.tag", "=", "enemy_units");
      Op("%.region", "=", "goal");
    }
  }
}

"ExecuteScript" is a command that will execute a pre-made script. "attack1" is the unique name of this instance of the script (you can name it whatever you want, as long as it's unique from any other ExecuteScript commands in the rest of your mission). "squad.move.tagtoregion" is a pre-made script, and is one of many that were created while designing the game. However, the "squad.move.tagtoregion" script is not yet loaded into memory. So we'll have to #include it just like we do with our custom text files. To do this, add this line to your strategic.cfg file:

#include "squad_move_tagtoregion.cfg"

Now, the squad.move.tagtoregion script calls for two bits of info: the tag source, and the region destination (%.tag, %.region). So this script is telling the tag "enemy_units" to move to the region "goal". Now when you load your map, the enemy troops should now run towards the goal area and engage the player's units should they encounter each other. This will happen immdiately when starting the mission.

Now we need the condition that will make the player get the Defeat screen if all their units get destroyed. Open objective_start.cfg. In the Action scope of "objective_start_player", add the line:

    NewObjective("objective_player_defeat");

The entire objective should now look like this:

CreateObjectType("objective_start_player", "Objective")
{
  Condition("TRUE");
  Action()
  {
    NewObjective("objective_player_at_goal");
    NewObjective("objective_player_defeat");
  }
}

Now open objectives_player.cfg and add the "objective_player_defeat" objective:

CreateObjectType("objective_player_defeat", "Objective")
{
  Condition("TagCount")
  {
    Tag("players_units")
    {
      Operator("==");
      Amount(0);
    }
  }
  Action()
  {
    Lose();
  }
}

"TagCount" is a condition type that can test how many objects of a certain tag there is in the world at a given time. TagCount calls for which tag to test, then has Operator & Amount variables. The operator "==" means "equal to", or "is"; So it's asking "Is the amount of objects in the Tag "players_units" zero?" Lose(); is the script command to give the Defeat screen.

Try the mission in the game. Allow the enemy to kill all your units, you should get the Defeat screen.

This concludes the creation of the tutorial map! You should now have a mission that you can win and lose.