All of the scripting
commands used to make the EE2 scenarios can be found in this document.
Immediately below is a model for an .ies script which you will write and attach
to a map to make a scenario. To make an .ies file simply rename any text file
extension (.txt) to .ies. Copy the sample script below into that file so you
can have a format to follow. Once you are ready to test your script
put it in your "My Documents\Empire Earth II\scripts" folder. Then go into the map
editor, load up your map and go to
Two sample scripts and scenario files are included. They are named:
Boston.scn
Boston.ies
ScriptExampleTutorial1.scn
ScriptExampleTutorial1.ies
As the scripting system is a development tool, it is not completely stable. It is recommended that after you load and compile your script through the mission properties dialog, you save your scenario and restart the game.
// SAMPLE.ies
// Author: YOU
// Copyright what, when.
// All rules are for the WORLD entity. This is where you declare the //objectives of the scenario
RULES FOR WORLD
SCENARIO
//Below is the objective's name, which you'll refer to later in the
//script when you want to check if it's been conmpleted yet.
OBJECTIVE InterpTutorial1_Objective1
//the "name" is what appears on the objectives screen
name = "Find a place to build a city"
//the "desc" is what appears as verbose mission text when you hover
//your mouse over the objective name.
desc = "This is an example of a typical objective"
//the "type" is whether it is a primary, secondary or lose condition
type = kScenarioObjectiveType_Primary
//"starthidden" should be 1 if you want it to be invisible to the
//player at game start. You'll have to reveal it later.
starthidden = 1
//"targetlocation" can also be "targetarea" or "targetterritory" or //"targetunit" - this is where the mission flag will appear on the full
//screen map.
targetlocation1x= 44
targetlocation1y= 58
END_OBJECTIVE
// Now here's one nicely put together.
OBJECTIVE InterpTutorial1_Objective2name = "Move your citizens to the rocks"
desc = "Order your citizens to move by right clicking"
type = kScenarioObjectiveType_Primary
starthidden = 1
targetarea1 = "areaRock"
END_OBJECTIVE
//the following stuff is what appears in the scenario info box that
//appears after the mission loads.
name = "MyScenarioName"
brief = "Welcome to my scenario...\n\nYou can close this window by pressing the 'Close' button."
hints = ". Close this window by clicking the close button.\n\n. If you are ever unsure what to do, hit 'Alt - o' to open the objectives screen.\n\n. Tab will allow you to switch between the Full Screen map and the normal view.\n\n. You can remove units by pressing the delete key.
historicalInfo = "It all started when."
END_SCENARIO
// Definitions section
DEFINITIONS
// Here's where you name everything that you will later call in
// the script (groups, units, areas, etc.)
// CONSTANTS
constant int cScoutCost
// OBJECTIVES
constant string OBJ_FIND_CITY_CENTER
constant string OBJ_MOVE_TO_ROCK
//PLAYERS
constant int HUMAN_PLAYER
// TERRITORIES
constant string TERRITORY_TENOCHTITLAN
// UNITS
constant string UNIT_BOLT_TREE
constant string UNIT_CITY_CENTER
// AREAS
constant string AREA_ROCK
constant string AREA_APPROACH
// GROUPS
constant string GROUP_CITIZENS
constant string GROUP_CITY_CENTER
// ATTRIBUTES
constant string ATTRIBUTE_CITIZEN
constant string ATTRIBUTE_CITY_CENTER
// TYPES
constant string TYPE_CITIZEN_FEMALE
constant string TYPE_CITIZEN_MALE
constant string TYPE_SCOUT
constant string TYPE_CONSTRUCTION_SITE
constant int PHASE_INITIAL
constant int PHASE_MISSION_OBJECTIVES_1
constant int PHASE_MISSION_OBJECTIVES_2
// VARIABLES
int hCurrVoiceOverHandle // The handle to the VO.
float fDelay // The delay at start of each rule
int iWoodNeeded // Amount of wood needed to build city
int iStoneNeeded // Amount of stone needed to build city
// The Phase of the scenario
cHotInt iScenarioPhase
END_DEFINITIONS
// Initialization section
INITIALIZATION
//You can do most anything you'd like in this section to set the
//scene for when the scenario starts. Anything set here is
//evaluated while the mission loads.
// CONSTANTS
cScoutCost = 30;
// OBJECTIVES
OBJ_FIND_CITY_CENTER ="InterpTutorial1_Objective1";
OBJ_INFORMATION ="InterpTutorial1_Objective2";
//PLAYERS
HUMAN_PLAYER =1;
// TERRITORIES
TERRITORY_TENOCHTITLAN ="Tenochtitlan";
// UNITS
UNIT_BOLT_TREE = "unitBoltTree";
UNIT_CITY_CENTER = "unitCinematicCityCenter";
// AREAS
AREA_ROCK = "areaRock";
AREA_APPROACH = "areaApproach";
// GROUPS
GROUP_CITIZENS = "groupCinematicCitizens";
GROUP_CITY_CENTER = "TheCity";
// ATTRIBUTES
ATTRIBUTE_CITIZEN = "Citizens";
ATTRIBUTE_CITY_CENTER ="CityCenters";
// TYPES
TYPE_CITIZEN_FEMALE ="CitizenF";
TYPE_CITIZEN_MALE = "CitizenM";
TYPE_SCOUT = "Scout";
TYPE_CONSTRUCTION_SITE ="ConstructionSite";
PHASE_INITIAL = 0;
PHASE_MISSION_OBJECTIVES_1= 1;
PHASE_MISSION_OBJECTIVES_2= 2;
ChangeTerritoryCityName(TERRITORY_TENOCHTITLAN, "text_T1_Tenochtitlan");
//NO RESEARCH. NO GOING TO EPOCH 2
SetMaxEpochUI(1);
SetTechEnabled(HUMAN_PLAYER, "Main2", false);
SetTechEnabled(HUMAN_PLAYER, "Imperial1_1", false);
SetTechEnabled(HUMAN_PLAYER, "Imperial1_2", false);
SetTechEnabled(HUMAN_PLAYER, "Imperial1_3", false);
SetTechEnabled(HUMAN_PLAYER, "Imperial1_4", false);
SetTechEnabled(HUMAN_PLAYER, "Military1_1", false);
SetTechEnabled(HUMAN_PLAYER, "Military1_2", false);
SetTechEnabled(HUMAN_PLAYER, "Military1_3", false);
SetTechEnabled(HUMAN_PLAYER, "Military1_4", false);
SetTechEnabled(HUMAN_PLAYER, "Economic1_1", false);
SetTechEnabled(HUMAN_PLAYER, "Economic1_2", false);
SetTechEnabled(HUMAN_PLAYER, "Economic1_3", false);
SetTechEnabled(HUMAN_PLAYER, "Economic1_4", false);
// Disable some buildings
SetTechEnabled(HUMAN_PLAYER, "CityCenter", false);
SetTechEnabled(HUMAN_PLAYER, "Warehouse", false);
SetTechEnabled(HUMAN_PLAYER, "House", false);
SetTechEnabled(HUMAN_PLAYER, "Temple", false);
SetTechEnabled(HUMAN_PLAYER, "University", false);
SetTechEnabled(HUMAN_PLAYER, "Road", false);
SetTechEnabled(HUMAN_PLAYER, "Bridge", false);
SetTechEnabled(HUMAN_PLAYER, "Palisade", false);
SetTechEnabled(HUMAN_PLAYER, "Fortress", false);
SetTechEnabled(HUMAN_PLAYER, "Outpost", false);
SetTechEnabled(HUMAN_PLAYER, "Barracks", false);
SetTechEnabled(HUMAN_PLAYER, "Mill", false);
SetTechEnabled(HUMAN_PLAYER, "Dock", false);
SetTechEnabled(HUMAN_PLAYER, "Wall", false);
SetTechEnabled(HUMAN_PLAYER, "Stable", false);
SetTechEnabled(HUMAN_PLAYER, "Market", false);
// BALANCING
AI_SetBuildTimeFactor(HUMAN_PLAYER, 0.5);
// The calender shouldn't advance
PauseCalendar(true);
// Set the starting month to July
SetCurrentMonth(7);
// Set the time of day (military time)
SetCurrentTimeOfDay(15);
PauseWeatherSystem(true);
fDelay = 1; // Delay at start of rules
bResourceUpdate = false;
iWoodNeeded = 300;
iFoodNeeded = 300;
iStoneNeeded = 300;
iScenarioPhase = PHASE_INITIAL;
ResetFogOfWar(HUMAN_PLAYER);
StopAllScriptSounds();
ClearSubtitle();
ToggleStreamingMusic(false);
//If you're all fancy, you can play a .bik movie at the
//beginning of your scenario. Just drop it in the "Movies" folder //and then call it.
StartPlayingCinematic("CinematicEgypt3_Opening_1");
CreateNamedGroup(GROUP_CITIZENS);
AddUnitsByAttributeToGroup(GROUP_CITIZENS, ATTRIBUTE_CITIZEN, HUMAN_PLAYER, kPlayerMode_Self, NULL);
hProtectCitizens = AttachEffectToGroup(GROUP_CITIZENS, "PreventDeletion");
// initial camera, after cinematic
SetCameraDistanceFraction(1, false);
SetCameraHeading(90, false);
SetCameraLookAtArea("areaCameraStart", false);
SetCameraLookAtArea("areaCameraStart", true);
END_INITIALIZATION
////////////////////////////////////////////////////////////
//RUNS AFTER CINEMATIC, BEFORE OBJECTIVES OPEN
////////////////////////////////////////////////////////////
ACTION PreScenInfoPanelHook
SCRIPT WORLD
iScenarioPhase = PHASE_MISSION_OBJECTIVES_1;
//iScenarioPhase = PHASE_SCOUT; // mike2e
END_SCRIPT
END_ACTION
////////////////////////////////////////////////////////////
//RULES AND ACTIONS. THIS IS THE MAIN BODY OF YOUR SCRIPT
////////////////////////////////////////////////////////////
// Rule that happens only once
RULE HappensOnce ONESHOT
if ((GetNumConvertedUnitsFromPlayerOfType(3, 1, TYPE_CITIZEN_MALE) > 0)
)
then actionHappensOnce
END_RULE
// Action for rule that happens only once
ACTION actionHappensOnce
SCRIPT WORLD
DoDelay(fDelay);
STEP
DebugOutputString("Converted player three's citizen");
END_SCRIPT
END_ACTION
// Rule that happens every thirty seconds.
// NOTE: Rules are evaluated constantly unless you state otherwise.
//This can drastically slow down game performance, so it is strongly //recommended that most rules get evaluated less frequently. To do
//this, use the "PERIODICITY" parameter sampled below to state how //often you'd like a rule to get checked. The rule below gets checked
//every thirty seconds. Note that without the ONESHOT parameter (which //would come right before PERIODICITY if you wanted to use it), this
//rule will continue to evaluate itself even if it returns true. So, in
//the case below, player 1 will receive 500 gold every thirty seconds
//as long as he has 3 or more territories. If it was a ONESHOT rule, it //would happen the FIRST time the player has three or more territories
//and then never happen again. As a final note about using PERIODICITY, //you must make sure you set and use a bool for each rule that uses //PERIODICITY as in the example below. Failure to do so will result in
//a rule that just won't fire.
RULE HappensEvery30 PERIODICITY 30
if ( !bHappens30 &&
(GetNumTerritoriesForPlayer(1) >= 3)
)
then actionHappensEvery30
END_RULE
// Action for rule that happens every thirty seconds
ACTION actionHappensEvery30
SCRIPT WORLD
DebugOutputString("Candy for you!");
bHappens30 = true;
AddPlayerResource(1, kResourceType_Gold, 500);
DoDelay(1);
STEP
bHappens30 = false;
END_SCRIPT
END_ACTION
// EOF
__________ ______ ____ __________ ______ ____ __________
SCRIPT VARIABLES:
Scripts use so-called hot-variables, the scripting system monitors these variables and re-evaluates rules that depend on them when the value changes.
cHotInt
cHotFloat
SCRIPT COMMANDS:
// void DoDelay(float in_fSeconds)
// Wait for fSeconds before STEPping the script.
// example usage:
// Execute Something(), wait 3.5 seconds, then
// execute SomethingElse()
...
Something();
DoDelay(3.5);
STEP
SomethingElse();
...
Game Actions
// void SetUnitDisplayName(const char *in_szUnitNameInScript,
const char *in_szTextDatabaseEntry);
// set (localized) display name for a named unit
// in_szUnitNameInScript must be a valid named unit (script name)
// in_szTextDatabaseEntry must be a valid text database entry
// (the contents of which will become the displayed name)
example usage:
if you have a unit named "Jesus" in the scripting unit name
table and a text database entry named "tx_scenUnitName_Jesus"
exists, then you could do this:
SetUnitDisplayName("Jesus", "tx_scenUnitName_Jesus");
// void CreateUnitAtLocation(int in_iPlayerID,
// const char *in_szTypeName,
// bool in_bSpecialForces, float in_fXLoc, float in_fYLoc,
// float in_fAngle)
// void CreateNamedUnitAtLocation(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,
// bool in_bSpecialForces, float in_fXLoc, float in_fYLoc,
// float in_fAngle)
// void CreateGroupedUnitAtLocation(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,// bool in_bSpecialForces, float in_fXLoc, float in_fYLoc,
// float in_fAngle)
// Creates a in_iPlayerID-owned unit of type in_szTypeName as close as
// possible to (in_fXLoc, in_fYLoc), facing direction in_fAngle. If
// in_bSpecialForces is true, it will mark this unit as special forces.
// The CreateNamedUnitAtLocation variant will additionally name the
// unit in_szUnitName, and the CreateGroupedUnitAtLocation variant will
// add the unit to the in_szGroupName group.
// example usage:
//Give AI player 3 a few light infantry guys and stick
//them in the "Disposable" group. Just let the AI use
//them as it wishes - don't make them special forces.
CreateGroupedUnitAtLocation(3, "LightInfantry",
"Disposable", false, 96, 96, 0);
CreateGroupedUnitAtLocation(3, "LightInfantry",
"Disposable", false, 96, 96, 0);
CreateGroupedUnitAtLocation(3, "LightInfantry",
"Disposable", false, 96, 96, 0);
//Give AI player 2 a male citizen named "JamesBond".
//Make him special forces so the AI won't touch him.
CreateNamedUnitAtLocation(2, "CitizenM", "JamesBond",
true, 32, 32, 0)
//Give the human player an anonymous bomber.
CreateUnitAtLocation(1, "Bomber", false, 64, 64, 0);
// void SetUnitPlacementAngle(float in_fAngle)
// Sets the unit placement angle for the following 'Create*InArea'
// calls. Maintains the same angle for the entire STEP, at which
// point, the default angle (0, or east) comes back.
// void CreateUnitInArea(int in_iPlayerID,
// const char *in_szTypeName,
// bool in_bSpecialForces, const char *in_szAreaName)
// void CreateNamedUnitInArea(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,
// bool in_bSpecialForces, const char *in_szAreaName)
// void CreateGroupedUnitInArea(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,
// bool in_bSpecialForces, const char *in_szAreaName)
// These work exactly the same as the Create*UnitAtLocation commands// above, except they take the name of an area instead of a pair of
// coordinates and an angle. Right now it just places them as close
// to the center as possible, and search out in a 'ring' pattern
// like the AtLocation commands do.
// example usage:
SetUnitPlacementAngle(1.57f); // face north, buddy
CreateNamedUnitInArea(2, "CitizenM", "Gatekeeper",
true, "OutsideCityGate");
// void CreateUnitInTerritory(int in_iPlayerID,
// const char* in_szTypeName, bool in_bSpecialForces,
// const char* in_szTerritoryName)
// void CreateNamedUnitInTerritory(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,
// bool in_bSpecialForces, const char *in_szTerritoryName)
// void CreateGroupedUnitInTerritory(int in_iPlayerID,
// const char *in_szTypeName, const char *in_szUnitName,
// bool in_bSpecialForces, const char *in_szTerritoryName)
// These commands are similar to the above area commands. Instead
// of using an area name, however, they take a name of a territory,
// and use the approximate center of the territory as the location
// when creating the unit.
// NOTE: Test these commands to make sure the location used matches
// your expectations. The center of the territory may not be where
// you think it is, and it might be better for you to create an area
// or use an X,Y coordinate instead of using the territory.
// CreateUnitInUnit(int in_iPlayerID, const char* in_szTypeName,
// bool in_bSpecialForces, const char* in_szTargetUnit)
// CreateNamedUnitInUnit(int in_iPlayerID, const char* in_szTypeName,
// const char* in_szUnitName, bool in_bSpecialForces,
// const char* in_szTargetUnit)
// CreateGroupedUnitInUnit(int in_iPlayerID, const char* in_szTypeName,
// const char* in_szGroupName, bool in_bSpecialForces,
// const char* in_szTargetUnit)
// These work like CreateUnitAtLocation and the related commands,
// except for the last parameter in each command. The last parameter
// is the name of an existing unit that can garrison other units. The
// new uits will be garrisoned in the specified unit when they are// created.
CreateNamedUnitInUnit(2, "CitizenM", "Gatekeeper",
true, "Transport01");
// void GenerateAIBuildManagers(const char* in_szCapitolName)
// tell the AI to auto-generate build managers for all city centers on // the map, the specified capitol will use the default build list,
// all others will use the buildlists from buildListRegistry_NewCity
// void PausePlayerAI(int in_iPlayerID, bool bPaused)
// Disable/enable strategic AI of computer player// example usage:
//Pause AI player 2 until some condition is met.
PausePlayerAI(2, true);
...
//Unpause player 2, now that the human player's ready.
PausePlayerAI(2, false);
// void SetAIInstantRallying(int in_iPlayerID, bool
in_bShouldInstantRally)
// set instant rallying for this AI - this makes it NOT try to pull its
troops together before attacking really just a hack for if you're
giving it way too many units that it can't rally them
// void AI_ChangePersonality(int in_iPlayerID,
// const char *in_szFileName)
// Load the specified Aip file for the given playerID
// example usage:
AI_ChangePersonality(playerID, "bully.aip");
// void AI_SetAttackFactor(int in_iPlayerID, float in_fFactor)
Set a multiplier on how much damage this player does,
this is after all global game and difficulty settings
are applied. Set to less than 1 to do less damage than normal,
greater than 1 to do more damage than normal.
// void AI_SetBuildTimeFactor(int in_iPlayerID, float in_fFactor)
// A multiplier on how long it takes to build units and buildings,
// applied after global and difficulty settings, set to less than
// 1.0 to take LESS time to build than normal.
// void AI_SetBuildCostFactor(int in_iPlayerID, float in_fFactor)
// A multiplier on how much things cost, applied after global and
// difficulty settings, set to < 1.0 to make things cost LESS than
// normal, or greater to cost more (and handicap the player)
// create a specific battalion to do stuff
void AI_CreateBattalion(int in_iPlayerID,
const char* in_szMyUnitGroupName,
const char *in_szEnemyUnitGroupName,
const char* in_szTerritoryName,
eTaskType in_eTaskType)
// in_szMyUnitGroupName is the name of the group of units that will be
performing the task.
// in_szEnemyUnitGroupName is the name of the target
units, so if you are attacking an army or base, these are those
units, though if you are defending a base, these will be your
buildings
// in_szTerritoryName is used INSTEAD of in_szEnemyUnitGroupName for
capture territory tasks
// Valid task types are:
// kTaskType_AttackArmy, kTaskType_AttackBase, kTaskType_DefendBase
// or kTaskType_CaptureTerritory
// One other option is kTaskType_StartCity, which is the only
// NON-MILITARY action possible, give it citizens ONLY or
// badness will follow
// Note: for capture territory, you CAN give it citizens in the selection, and it'll use them right. If you don't, it'll look for any citizens not on special forces and snag some of them.
// void SetPlayerToCinematicOnly(int in_PlayerID,
// bool in_bCinematicOnly)
// Change a player to be cinematic only or not. Cinematic only players// do not show up in the Diplomacy screen, end game stats, and other
// in-game UI elements that normally list players.
// NOTE: You can set a player to be cinematic-only in the scenario
// editor. You can even make a cinematic-only player, and use that
// player for scripted events during the game. It is probably
// better to use the scenario editor, and make the player
// cinematic-only or not for the entire game.
// example:
// Player 5 was used for some barbarian hordes which
// did not represent a cohesive civilization and shouldn't show
// up in the end game stats. So make them disappear.
SetPlayerToCinematicOnly(5, true);
// void SetPlayerResource(int in_iPlayerID, eResourceType in_eResType,
// int in_iAmount)
Change player's resource amount to x
// Set the amount of resource for the specified type. NB: If you have
// a rule testing GetAmountOfResourcesCollected(), it will NOT keep
// track of resources added by this call! It only keeps track of
// resources actually gathered by the player.
// example usage:
//Thieves have broken into your treasury!
SetPlayerResource(1, kResourceType_Gold, 0);
// void AddPlayerResource(int in_iPlayerID, eResourceType in_eResType,
// int in_iAmountToAdd)
// add extra amount of the specified resource type. NB: If you have
// a rule testing GetAmountOfResourcesCollected(), it will NOT keep
// track of resources added by this call! It only keeps track of
// resources actually gathered by the player.
// example usage:
//After the player completes a game event that establishes
//positive
diplomatic relations with
//Nigerian ambassador send him/her a gift of uranium.
AddPlayerResource(1, kResourceType_Uranium, 500);
// void RemovePlayerResource(int in_iPlayerID,
// eResourceType in_eResType, int in_iAmountToRemove)
// remove some amount of the specified resource type
// If the player has less than in_iAmountToRemove, it will only
// take away as much as he has, so if the script is doing a thing where
// it needs to know whether he has enough to pay for something, you'll
// have to check with GetPlayerResource() first!
// example usage:
//The termites are horrible this time of year..
RemovePlayerResource(1, kResourceType_Wood, 250);
// void Script_LiftShroudForPlayer(int in_iPlayerID)
// Lifts the shroud for player in_iPlayerID. This is irreversible so
// only do it if you mean it. This function call is a stopgap measure
// until we get shroud-painting into the scenario editor.
// example usage:
//You'd want to put this in the INITIALIZATION section of
//a script for a scenario where you want the player to
//be able to see the entire terrain.
LiftShroudForPlayer(1)
// void ToggleFogOfWar(bool in_bFogOn)
// Turns the fog of war on and off for a map. Pass in true if you want
// fog of war on, and false if you want it off.
// Example:
// To turn the fog off for a map right at the beginning, stick
// this in the INITIALIZATION section of the script.
ToggleFogOfWar(false);
// void ResetFogOfWar(int in_iPlayerID)
// Resets the fog of war for the specified player. It will set the
// shroud to be as if they player has not explored beyond what his
// units let him see right now// Example:
// After the cinematic, make this call to clean up anything that
// might have been revealed.
ResetFogOfWar(1);
// void CarveShroudCircle(int in_iPlayerID, float in_fX, float in_fY,
// int in_iRadius)
// carve a circular hole in in_iPlayerID's shroud. If in_iPlayerID is
// 0, will carve for all players.
// example usage:
// Let player 1 see a circle of radius 5 at 32, 32.
CarveShroudCircle(1, 32, 32, 5);
// void CarveShroudArea(int in_iPlayerID, const char *in_szAreaName)
// carve a named-area-shaped hole in in_iPlayerID's shroud. If
// in_iPlayerID is 0, will carve for all players.
// example usage:
// Let player 1 see the whole field
CarveShroudArea(1, "BattleField");
// void CarveShroudOverTerritory(int in_iPlayerID,// void PlaceFlare(float in_fX, float in_fY, int in_iRadius,
// int in_iPlayerID, float in_fDuration)
// Puts a flare of radius in_iRadius down at location (in_fX, in_fY)
// for player in_iPlayerID. If in_fDuration is > 0, the flare will
// automatically terminate after in_fDuration seconds. If in_fDuration
// is <= 0, the flare will last until you call FlushFlares() on the
// same player ID.
// example usage:
// Let player 1 see (units included) a circle of radius 5 at
// 32, 32 for 30 seconds.
PlaceFlare(32, 32, 5, 1, 30);
// void FlushFlares(int in_iPlayerID)
// Flushes all flares created by PlaceFlare() that had a permanent
// duration (i.e. the ones that were given a finite duration will still
// burn).
// example usage:
FlushFlares();
// void FlareMiniMap(int in_iPlayerID, float in_fX, float in_fY)
// Play a flare on the mini map and full-screen map at the specified
// X, Y location. The flare is shown to in_iPlayerID. Flares
// started at the same time will actually start with five-second delays
// between them. (This is built into the flare system to prevent too
// many flares from happening at once.)
// example usage:
// Show the player where he needs to attack, assuming the enemy
// fortress is located at 125,60
FlareMiniMap(1, 125, 60);
// void FlareMiniMapForDuration(int in_iPlayerID, float in_fX,
// float in_fY, float in_fDuration
// Play a flare on the mini map and full-screen map at the specified
// X, Y location. The flare is shown to in_iPlayerID. The flare will
// last for the designated duration.
// example usage:
// There's a KMart at location 125, 60, and they have a blue
// light special on tanks for the next 60 seconds. Get them
// before they're gone!
FlareMiniMapForDuration
// void AlertPlayer()
// Just plays a sound to tell the player to pay attention. Can be
// coupled with a minimap flare for an audio and visual cue.
// example:
// Just bring the player's attention to this location.
FlareMiniMap(1, 20, 43);
AlertPlayer();
// void SetPopCapPerCityCenterForPlayer(int in_iPlayerID,
// int in_iPopCap)
// Set the amount of population that player in_iPlayerID is allowed
// for each city center to be in_iPopCap.
// Human player has 2 city centers, let's let him have a max of
// 40 population:
SetPopCapPerCityCenterForPlayer(1, 20);
// void SetMaxPopCapacity(int in_iPlayerID, int in_iNewMaxPopCap)
// Set the max pop capacity for the specified player. City centers and
// houses grant so much population capacity to a player. This sets
// the maximum capacity that the player can get from those buildings
// and similar bonuses. You can use this to place a hard limit on the
// number of units that a player can have in a scenario.
// For performance and balance reasons, limit the computer
// player to 500 pop capacity
SetMaxPopCapacity(3, 500);
// void SetTechEnabled(int in_iPlayerID, const char *in_szTechName,
// bool in_bEnabled)
// Enable or disable a player's ability to research a given tech.
// example usage:
//Use this in some crazy atheist campaign, I guess
SetTechEnabled(1, "Priest", false);
// void AdvancePlayerEpoch(int in_iPlayerID, int in_iEpoch)
// Advance player in_iPlayerID to epoch in_iEpoch. This will fail
// (and assert) if you attempt to advance a player backwards.
// example usage:
// player 1 found the crashed alien spacecraft
// and stole its technology, so advance him up
// to the atomic epoch
AdvancePlayerEpoch(1, 12);
// void AwardTech(int in_iPlayerID, const char* in_szTechName)
// Award the named tech to the specified player. The tech name
// comes from run\db\techtree\dbtechtreenode.csv. Each row of
// this file lists a different node. The leftmost column contains
// the name of each node.
// example usage:
// Grant player 1 the third military tech in epoch 1
AwardTech(1, "Military1_3");
// void CallNamedEventHandler(const char *in_szEventHandlerName,
// const char *in_szArgument)
// Manually call a registered NAMED_EVENT_HANDLER with argument.
// NAMED_EVENT_HANDLERS are the things that you bind keys to in
// your hotkeys.cfg.
// example usage:
//Pretend this is the tutorial and I'm showing you how
//to use the pip.
CallNamedEventHandler("PipSwap", "");
// void WinScenario()
End scenario (with victory/failure message)
// Sets the local player as having won the scenario. This will trigger
// the end of the scenario, but only if there's a 'Script Says So'
// victory condition set up for the scenario!
// example usage:
//You win!
WinScenario();
// void LoseScenario()
End scenario (with victory/failure message)
// Sets the local player as having lost the scenario. This will
// trigger the end of the scenario, but only if there's a 'Script Says
// So' victory condition set up for the scenario!
// example usage:
//You lose, man.
LoseScenario();
// bool HasPlayerResearchedTech(int in_iPlayerID,
const char* in_szTechName)
// Checks to see if the specified player has researched
// the named technology. The technology name comes from
// dbtechtreenode.csv.
// example usage:
// Has the player researched fire, yet?
RULE HasPlayerDiscoveredFire
If(HasPlayerResearchedTech(1, "Main1_1"))
Then TellPlayerToBuildNewBuildings
END_RULE
// void GiveAttackBasePreference(int in_iPlayerID,
// const char *in_szAreaName, float in_priorityBoost)
// When playing with the strategic AI turned on, pass in
// the name of an area and a priority boost to make the player
// with id in_iPlayerID prefer attack targets in that area. The
// priority boost should be in the same scale as the
// AttackBase task priority from the AIP, so if that priority
// is 10, the priorityboost should be passed in as maybe 3
// or 4 to give a slight preference to that area
// example usage:
GiveAttackBasePreference(2, "DangerousArea", 3.0);
// void GiveCaptureTerritoryPreference (int in_iPlayerID,
// const char *in_szTerritoryName, float in_priorityBoost)
// When playing with the strategic AI turned on, pass in
// the name of a territory and a priority boost to make the player
// with id in_iPlayerID prefer to capture that territory. The
// priority boost should be in the same scale as the
// DefendBase task priority from the AIP, so if that priority
// is 10, the priorityboost should be passed in as maybe 3
// or 4 to give a slight preference to that area
// example usage:
GiveCaptureTerritoryPreference (2, "
// void GiveDefendBasePreference(int in_iPlayerID,
// const char *in_szAreaName, float in_priorityBoost)
// When playing with the strategic AI turned on, pass in
// the name of an area and a priority boost to make the player
// with id in_iPlayerID prefer to defend in that area. The
// priority boost should be in the same scale as the
// DefendBase task priority from the AIP, so if that priority
// is 10, the priorityboost should be passed in as maybe 3
// or 4 to give a slight preference to that area
// example usage:
GiveDefendBasePreference(2, "HomeArea", 3.0);
// void GiveAttackArmyPreference(int in_iPlayerID,
// const char* in_szTypeName, float in_priorityBoost)
// Gives the Strategic AI a preference to attack armies with units of
// this type in them. The priority boost should be in the same scale
// as the AttackArmy task priority from the AIP, so if that priority
// is 10, the priorityboost should be passed in as maybe 3
// or 4 to give a slight preference to that area
// example usage:
GiveAttackArmyPreference(2, "TradeCart", 3.0);
All the effects that can be attached to units and players are
located in the ddfs in $/run/db/AreaEffects/. The special per-scenario
effects can be added to dbareaeffects_scenario.ddf, and there is some helpful documentation in there as to how to craft them.
// int AttachEffectToUnit(const char *in_szUnitName,
// const char *in_szEffectName)
// Attaches the effect named in_szEffectName to the named
// unit in_szUnitName. You can hold on to the effect ID
// returned for later cancellation.
// Give this guy the loyalty effect that is usually
// a leader power
AttachEffectToUnit("JimJones", "Loyalty");
// int AttachEffectToGroup(const char *in_szGroupName,
// const char *in_szEffectName)
// Attaches the effect named in_szEffectName to EACH unit
// in the group in_szGroupName. You can hold on to the
// effect ID returned for later cancellation.
DEFINITIONS
int iFatID;
// Make everyone in this group a little slow
iFatID = AttachEffectToGroup("BrunosCustomers", "Fatness");
// Until the winter's over
CancelEffect(iFatID);
// int AttachEffectToPlayer(int in_iPlayerID,
// const char *in_szEffectName)
// Attaches the effect named in_szEffectName to player
// in_iPlayerID. You can hold on to the effect ID
// returned for later cancellation.
// Make all player's units immune to conversion
// for the rest of the scenario.
AttachEffectToPlayer(1, "Fanaticism");
// int AttachEffectToPlayerAtLocation(int in_iPlayerID,
// const char *in_szEffectName,
// float in_fX,
// float in_fY)
// Attaches the effect named in_szEffectName to player
// in_iPlayerID, and sets it to be located at the
// specified X,Y location. This allows you to create
// certain area effects that are not on a particular unit,
// but will only affect a certain area. These effects, when
// created, will effect a certain radius around their location.
// Damage all units that get to close to the Devil's playpen.
// Note that you need to create the appropriate area effect
// to do this.
AttachEffectToPlayerAtLocation(1, "DamageUnitsWithin5Tiles",
// void CancelEffect(int in_iEffectID)
// Cancels an effect previously started with one of the AttachEffect// calls. See AttachEffectToGroup for an example.
// int GetOwningPlayerForTerritory(const char* in_szTerritoryName)
// Get the player ID of the specified territory.
// Returns -1 if the territory is unclaimed.
If(GetOwningPlayerForTerritory("France") == 1)
Then CongratulationsYouTookOverFrance// void ChangeTerritoryOwner(const char* in_szTerritoryName,
int in_iNewPlayer)
// Change the ownership of a territory to a new player.
//Let's go conquer
ChangeTerritoryOwner("Mexico", 1);
void ChangeTerritoryCityName(const char* in_szTerritoryName,
const char* in_szCityName)
Change the city name for a particular territory. The city name is the name assigned to any city center that gets built in this territory after this command is called. This command does not rename any city centers already in the territory. in_szCityName may be NULL or an empty string. In this case, any city centers built in the territory will get their name randomly from an appropriate list of city names. (Depending on civilization.) If in_szCityName is not NULL or an empty string, then it must be the name of a text db entry. This is to help enforce localization and to prevent typos.
Example:
// Why would anybody in their right mind want to name any city
// in our glorious state anything other than Cambridge?
// NOTE: tx_ms_cityname_Cambridge may not be a real text db
// entry. :)
ChangeTerritoryCityName("Massachusetts",
"tx_ms_cityname_Cambridge");
// int GetNumTerritoriesForPlayer(int in_PlayerID)
// Find out how many territories the specified player controls.
// If a player needs to conquer three territories as a
// victory condition, use this check.
If(GetNumTerritoriesForPlayer(1) >= 3)
Then MarkTerritoryObjectiveComplete
bool DidPlayerTributeTerritoryToOwner(const char* in_szTerritoryName,
int in_iPreviousOwner)
Query to find out if the named territory was tributed to the current owner by the specified player. Returns true if it was, and false otherwise.
The commands in this section can be used to query or manipulate the economy parameters for a player. All of these commands require a player and a resource type. Do not use gold as a resource type for any of these commands. It will result in an assert. Gold is never traded, all other resources are traded, and gold is used as the currency.
int GetCurrentBuyPrice(int in_iPlayer, eResourceType in_eType)
int GetCurrentSellPrice(int in_iPlayer, eResourceType in_eType)
For a player, get the current price to buy or sell a particular resource type.int GetCurrentInflationRate(int in_iPlayer, eResourceType in_eType)
int GetCurrentDeflationRate(int in_iPlayer, eResourceType in_eType)
For a player, get the current inflation or deflation rate of a particular resource. When a player buys a resource, the buy and sell price for that resource increases by the inflation rate. When a player sells a resource, the buy and sell price decrease by the inflation rate.
int GetCurrentMaxBuyPrice(int in_iPlayer, eResourceType in_eType)
int GetCurrentMinSellPrice(int in_iPlayer, eResourceType in_eType)
For a player, get the current maximum buy price or minimum sell price for a particular resource. When buying a resource, the buy and sell price of the resource increase by the inflation rate once for each purchase. There is a maximum buy price that cannot be exceeded, however, and it is found via GetCurrentMaxBuyPrice. Similarly, prices decrease when selling a resource. You can find the minimum selling price with GetCurrentMinSellPrice.
void SetBuyPrice(int in_iPlayer, eResourceType in_eType, int in_iValue)
void SetSellPrice(int in_iPlayer, eResourceType in_eType, int in_iValue)
For a player, set the buy or sell price of a particular resource to the specified value. This sets the price right now. The price will still increase or decrease with each sale according to the inflation or deflation rate.
NOTE: If you adjust either the buy price, or the sale price, you probably also want to adjust the other. Otherwise, you might inadvertently create a situation in which the sell price is higher than the buy price.
Example:
// Call this during the initialization phase of a script to make
// food cheap to buy to begin with for the player.
// This will make food cost 40 gold to buy, and allow the player
// to sell for 20.
SetBuyPrice(1, kResourceType_Food, 40);
SetSellPrice(1, kResourceType_Food, 20);
void SetInflationRate(int in_iPlayer, eResourceType in_eType,
int in_iValue)
void SetDeflationRate(int in_iPlayer, eResourceType in_eType,
int in_iValue)
For a player, set the inflation or deflation rate for a particular resource type. Inflation controls the amount that the buy and sell price go up when the player buys. Deflation controls the amount that the buy and sell price go down when the player sells. These should both be greater than or equal to zero. (Just for reference, the current default inflation and deflation rates are five.)
NOTE: The inflation and deflation rates should probably be the same value so that the buy and sell prices go up and down at the same rate. It could potentially lead to problems (like the sell price getting higher than the buy price) if you don't keep these the same for a particular resource for a particular player.
Example:
// Make the economy in wood very stable. A value of 1 will mean
// little change when buying or selling.
SetInflationRate(1, kResourceType_Wood, 1);
SetDeflationRate(1, kResourceType_Wood, 1);
void SetMaxBuyPrice(int in_iPlayer, eResourceType in_eType,
int in_iValue)
void SetMinSellPrice(int in_iPlayer, eResourceType in_eType,
int in_iValue)
For a player, set the max buy price, or the min sell price for a particular resource type. Inflation and deflation cause the prices to rise and fall as a player buys and sells. There are caps, though, and this lets you set those caps. I think the current default is something like a max buy price of 900, and a min sell price of 20.
NOTE: These can be set independently, but the max buy price should always be higher than the min sell price.
Example:
// Set a low ceiling for the price of stone. This will mean
// stone will get a little more expensive than the start value
// of 100, but it won't keep climbing forever.
SetMaxBuyPrice(1, kResourceType_Stone, 150);
// void StartPlayingCinematic(const char *in_szCinematicName)
// Starts playing a cinematic.
// example usage:
StartPlayingCinematic("OpeningCredits");
// void DoDelayUntilCinematicTime(float in_fMark, cIEScript *pIEScript)
// Delays the STEPping of the script until the currently playing
// cinematic has reached in_fMark seconds.
// example usage:
DoDelayUntilCinematicTime(5.0);
STEP
PrintSubtitle("Lead Programmer: Rex Bradford");
DoDelayUntilCinematicTime(7.5);
STEP
PrintSubtitle("Script Interface Programmer: Ben Morse");
// void DoDelayUntilCinematicFinished(cIEScript *pIEScript)
// Delays the STEPping of the script until the currently playing
// cinematic has finished.
// example usage:
DoDelayUntilCinematicFinished();
STEP
// Clean up
ClearSubtitle();
// void SetCinematicTime(float in_fTime)
// Sets the cinematic time to in_fTime. You can use this to skip// backwards in a cinematic or ffw towards the end. Be careful! Only
// use this when a cinematic is actually playing!
// example usage:
DEFINITIONSbool bStartLoopingCinematic
bool bStopLoopingCinematic
END_DEFINITIONS
RULE StartLoopingCinematic
if (bStartLoopingCinematic && ALWAYS_EVALUATE)
then StartLoopingCinematic
END_RULE
ACTION StartLoopingCinematic
SCRIPT WORLD
// Don't start twice
bStartLoopingCinematic = false;
// Assume that someone else started
the cinematic, and set
// bStartLoopingCinematic to true. We would put all the
// cinematic control code in here -
...
// Then, when we're about to hit the end of the cinematic:
// If nothing has set bStopLoopingCinematic, just jump back
// to the beginning!
SetCinematicTime(0);
if (!bStopLoopingCinematic) bStartLoopingCinematic = true;
END_SCRIPT
END_ACTION
// void PrintSubtitle(const char *in_szMessage)
Show a subtitle message during a cutscene. If there's already a
// message in the subtitle bar, clears it first.
// example usage:
PrintSubtitle("A long time ago, in a galaxy far, far away...");
// void ClearSubtitle()
Clears the subtitle bar.
// example usage:
// They've read that line long enough, let's leave it blank for a
// while
ClearSubtitle();
// void PrintFormattedSubtitle()
// Prints the formatted message started with StartFormat() to the
// subtitle bar.
// example usage:
StartFormat("tx_t1_grocerylist");
// remember, I hate menthols
FormatString("ITEM", "tx_t1_cigarettes");
PrintFormattedSubtitle();
// @NOTE objectives are no longer addressed by number, you use
// names instead.
// ============ .ddf SETUP ===========
// each objective is now defined in its own block outside of the
// scenario definition for each scenario. The objective definitions
// must come before the scenario definition, and must have unique names
// across all scenarios (hence, a suggested naming convention of
// "American1_Objective1" or "American1_ObjPrimary1" etc.)
// In the scenario definition, in the objectives = [ ... part,
// all objectives you wish to include must be referenced by name.
// These objectives will be read in as is when the scenario first
// starts
// a typical objective definition will look something like this:
// Objective Tutorial1_Objective1
// note that there are separate name and description fields; the name
// should be pretty short, whereas the description can be as long as
// you want.
// the type file can be Primary, Secondary, or Lose
// startHidden can be 0 (to start unlocked) or 1 (to start hidden)
// optionally, you can specify target locations, named target units,
// named target areas, and named target territories from the .ddf,
// inside the objective definition for a particular objective
// target locations look like this:
// Objective Tutorial1_Objective1
//
// ]
// }
// target named units look like this:
// Objective Tutorial1_Objective1
// target areas and target territories are predictably similar,
// only using the field names targetAreas and targetTerritories
// @IMPORTANT target locations must specify valid locations on the map
// @IMPORTANT target named units, areas, etc. must specify valid
// named entities which have been named at load, ie you set the names
// in the editor rather than in the script. If you wish to target
// named entities which you name in script, you will have to use
// one of the lovely script functions for that purpose
// ============ OVERVIEW ===========
// when a scenario starts, all the objectives for that scenario
// will be loaded, and all that aren't supposed to start hidden are
// unlocked. The first not-hidden primary objective will appear
// in the scenario objective dialog box, which is the best thing
// ever and shows you the description of the objective, and if the
// objective has any target locations, units, etc. allows you
// to cycle through those locations in the world, and also allows
// you to jump to the objectives pane on the fullmap and hilite
// the objective which is in the dialog
// each objective is always in exactly one of four states:
// 1.) hidden (aka locked, aka inactive)
// 2.) unlocked (aka active, aka shown)
// 3.) completed
// 4.) failed
// the allowable transitions are depicted below
// PRIMARY/SECONDARY:
<==> completed
// hidden <==> unlocked
==> failed
// LOSE CONDITIONS:
// hidden <==> unlocked ==> failed
// @NOTE please note that currently, you are not allowed to mark
// an objective as hidden once you have completed or failed it
// all state transitions are specified by the designer in the script
// when an objective becomes unlocked, the scenario objective dialog
// will automatically open (or, if open, its current contents will
// be overridden by) the newly unlocked objective
// when an objective is completed or failed, it will be marked thusly
// on the fullmap objectives screen, but currently there are no
// other automatic notifications in the UI
// ============ DIALOG BOX ===========
// it is also worth noting that the tutorial dialog box has
// gone away, and the scenario objective dialog box has replaced
// it. There is a separate script function CreateDialogBox()
// which will open the scenario objective dialog to display
// text of your choosing, rather than the text for an objective
// @NOTE if the dialog is already open (eg displaying a newly
// unlocked objective) opening the dialog will overwite the
// contents of the dialog
// @NOTE you must specify a title for the dialog box
// (if you leave it as NULL, a default will be used, but it
// is something stupid like "Script Update!")
// @NOTE you can no longer call RemoveDialogBox(); it stays
// around until the user closes it, no matter how hard you try
// ============
// dialog box
// void CreateDialogBox(const char *in_szTitle,
const char* in_szDisplayText,
bool in_bPauseGame)
// show text in the scenario objective dialog box
// @NOTE this uses the scenario objective dialog box, so it will
// overwrite the current contents of the dialog box
// in_szTitle is title text entry in the text database
// (or NULL for default title)
// in_szDisplayText is text entry in the text database
// if in_bPauseGame is specified, this will pause the game
// example usage:
CreateDialogBox("tx_mydialog_title", "tx_mydialog_description"
true);
// void CreateObjectiveDialogBox(const char *in_szObjectiveName,
bool in_bPauseGame)
// open scenario objective dialog box for the specified objective
// (or, if the scenario objective dialog box is already open, either
// for displaying text ala CreateDialogBox() or for displaying another
// objective, it will overwrite the current contents of the dialog)
// in_szObjectiveName must specify a valid objective
// if in_bPauseGame is specified, this will pause the game
// example usage:
CreateObjectiveDialogBox ("Tutorial1_Objective1", false);
// bool IsObjectiveDialogBoxOpen()
// query whether or not the objective dialog box is open
// @NOTE because the same dialog box is used for both CreateDialogBox()
// and CreateObjectiveDialogBox(), this will return true if the dialog
// box is open for either of those purposes
// example usage:
RULE Example ONESHOT
if (IsObjectiveDialogBoxOpen()
)
then
...
END_RULE
// void SetAllowObjectiveDialogInEncyclopedia(bool in_bAllow)
// set to allow/disallow objective dialog box in the encyclopedia
// @HACK HACK this is just a tutorial hack, please don't use this if
// you don't have to. You should call this before opening the
// objective dialog box on the encyclopedia screen
// example usage:
SetAllowObjectiveDialogInEncyclopedia(true);
// query the state of individual objectives
// bool IsObjectiveCompleted(const char *in_szObjectiveName)
// returns true if objective in_iObjectiveIndex has been completed.
// in_szObjectiveName must specify a valid objective
// bool IsObjectiveFailed(const char *in_szObjectiveName)
// Returns true if the objective has been failed.
// in_szObjectiveName must specify a valid objective
// bool IsObjectiveUnlocked(const char *in_szObjectiveName)
// returns true if objective in_iObjectiveIndex has been unlocked.
// in_szObjectiveName must specify a valid objective
// example usage:
RULE Example ONESHOT
if (IsObjectiveCompleted("Tutorial1_Objective1") &&
!IsObjectiveUnlocked("Tutorial1_Objective2")
then
...
END_RULE
// query the state all objectives
// bool AllPrimaryObjectivesCompleted()
// returns true if ALL primary objectives have been completed
// bool Script_AllSecondaryObjectivesCompleted()
// returns true if ALL secondary objectives have been completed
// bool Script_AnyPrimaryObjectivesFailed()
// returns true if ANY primary objectives have been failed
// bool Script_AnyLoseConditionsFailed()
// returns true if ANY lose conditions have been failed
// example usage:
if (AllPrimaryObjectivesCompleted
then
...
END_RULE
// change objective state
// void SetObjectiveUnlocked(const char *in_szObjectiveName)
// unlock (ie. activate, un-hide, show, whatever) this objective
// in_szObjectiveName must specify a valid objective
// @NOTE you can only unlock hidden objectives
// void SetObjectiveLocked(const char *in_szObjectiveName)
// lock (ie. inactivate, hide, whatever) this objective
// in_szObjectiveName must specify a valid objective
// @NOTE you can only lock unlocked (not completed or failed)
// objectives
// void SetObjectiveCompleted(const char *in_szObjectiveName)
// Mark the objective in_iObjectiveIndex as completed.
// in_szObjectiveName must specify a valid objective
// @NOTE you can only mark unlocked, unfailed objectives as completed
// void SetObjectiveNotCompleted(const char *in_szObjectiveName)
// Mark the objective in_iObjectiveIndex as NOT completed, after having
// in_szObjectiveName must specify a valid objective
// @NOTE you can only mark completed objectives as not completed
// @NOTE you cannot mark lose conditions as completed
// void SetObjectiveFailed(const char *in_szObjectiveName)
// Mark the objective as failed
// in_szObjectiveName must specify a valid objective
// @NOTE you can only mark unlocked, not completed objectives as failed
// example usage:
SetObjectiveCompleted("Tutorial1_Objective1");
// misc changes to objectives
// void ChangeObjectiveDescription(const char *in_szObjectiveName,
const char *in_szDescriptionText)
// change the objective description text
// in_szObjectiveName must specify a valid objective
// in_szDescriptionText must specify a valid text database entry
// example usage:
ChangeObjectiveDescription ("Tutorial1_Objective1",
"text_scen_tut1_explanation2");
// void ObjectiveClearAllTargets(const char *in_szObjectiveName)
// clear all targets (locations, units, areas, and territories) for
// this objective
// in_szObjectiveName must specify a valid objective
// example usage:
ObjectiveClearAllTargets ("Tutorial1_Objective1");
// edit target locations for an objective
// void ObjectiveSetTargetLocation(const char *in_szObjectiveName,
float in_fX, float in_fY)
// set to target a single location
// in_szObjectiveName must specify a valid objective
// (in_fY, in_fX) must specify a valid map location
// example usage:
ObjectiveSetTargetLocation ("Tutorial1_Objective1", 10, 15);
// void ObjectiveAddTargetLocation(const char *in_szObjectiveName,
float in_fX, float in_fY)
// add a target location
// in_szObjectiveName must specify a valid objective
// (in_fY, in_fX) must specify a valid map location
// example usage:
ObjectiveSetTargetLocation ("Tutorial1_Objective1", 10, 15);
// bool ObjectiveRemoveTargetLocation(const char *in_szObjectiveName,
float in_fX, float in_fY)
// remove a target location
// in_szObjectiveName must specify a valid objective
// (in_fY, in_fX) must specify a valid map location
// returns true if the location was removed, false if not found
// example usage:
ObjectiveRemoveTargetLocation ("Tutorial1_Objective1", 10, 15);
// void ObjectiveClearTargetLocations(const char *in_szObjectiveName)
// remove all target locations
// in_szObjectiveName must specify a valid objective
// example usage:
ObjectiveClearTargetLocations ("Tutorial1_Objective1");
// edit target units for an objective
// void ObjectiveSetTargetUnit(const char *in_szObjectiveName,
const char *in_szUnitName)
// set to target a single named unit
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named unit
// example usage:
ObjectiveSetTargetUnit ("Tutorial1_Objective1", "Jesus");
// void ObjectiveAddTargetUnit(const char *in_szObjectiveName,
const char *in_szUnitName)
// add a target named unit
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named unit
// example usage:
ObjectiveAddTargetUnit ("Tutorial1_Objective1", "Jesus");
// bool ObjectiveRemoveTargetUnit(const char *in_szObjectiveName,
const char *in_szUnitName)
// remove a target named unit
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named unit
// returns true if the unit was removed, false if not found
// example usage:
ObjectiveRemoveTargetUnit ("Tutorial1_Objective1", "Jesus");
// void ObjectiveClearTargetUnits(const char *in_szObjectiveName)
// remove all target named units
// in_szObjectiveName must specify a valid objective
// example usage:
ObjectiveClearTargetUnits ("Tutorial1_Objective1");
// edit target areas for an objective
// void ObjectiveSetTargetArea(const char *in_szObjectiveName,
const char *in_szAreaName)
// set to target a single named area
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named area
// example usage:
ObjectiveSetTargetArea ("Tutorial1_Objective1", "
// void ObjectiveAddTargetArea(const char *in_szObjectiveName,
const char *in_szAreaName)
// add a target named area
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named area
// example usage:
ObjectiveAddTargetArea ("Tutorial1_Objective1", "
// bool ObjectiveRemoveTargetArea(const char *in_szObjectiveName,
const char *in_szAreaName)
// remove a target named area
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named area
// returns true if the area was removed, false if not found
// example usage:
ObjectiveRemoveTargetArea ("Tutorial1_Objective1", "
// void ObjectiveClearTargetAreas(const char *in_szObjectiveName)
// remove all target named areas
// in_szObjectiveName must specify a valid objective
// example usage:
ObjectiveClearTargetAreas ("Tutorial1_Objective1");
// edit target territories for an objective
// void ObjectiveSetTargetTerritory(const char *in_szObjectiveName,
const char *in_szTerritoryName)
// set to target a single named territory
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named territory
// example usage:
ObjectiveSetTargetTerritory ("Tutorial1_Objective1",
"FieryInferno");
// void ObjectiveAddTargetTerritory(const char *in_szObjectiveName,
const char *in_szTerritoryName)
// add a target named territory
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named territory
// example usage:
ObjectiveAddTargetTerritory ("Tutorial1_Objective1",
"FieryInferno");
// bool ObjectiveRemoveTargetTerritory(const char *in_szObjectiveName,
// const char *in_szTerritoryName)
// remove a target named territory
// in_szObjectiveName must specify a valid objective
// in_szUnitName must specify a valid named territory
// returns true if the territory was removed, false if not found
// example usage:
ObjectiveRemoveTargetTerritory ("Tutorial1_Objective1",
"FieryInferno");
// void ObjectiveClearTargetTerritories(const char *in_szObjectiveName)
// remove all target named territories
// in_szObjectiveName must specify a valid objective
// example usage:
ObjectiveClearTargetAreas ("Tutorial1_Objective1");
// @NOTE all of these work with widget names. Generally speaking,
// widget names in the game are not always unique (although they
// usually are). Furthermore, all of these assume that not only
// are the names unique on a particular screen, they must be unique
// across both the game and fullmap screens (and options screen, for
// that matter, not that you should try to access widgets in the
// options screens, but the names of the ones in game you access
// must not also be names in the options screen)
// You will probably encounter occasional cases where
// your script does not run correctly when trying to access a
// particular widget, in which case it may be that the widget does
// not have a unique name. The only real way to solve this problem
// is to involve a programmer and get the names reworked. Also,
// because the widget you want to access may not even exist when
// you invoke the script call, there is currently no great way of
// debugging this stuff if you enter an incorrect widget name
// if this becomes a persistent problem, we can probably work something
// out
// @HINT an easy way to determine the name of a widget:
// hit Ctrl+TAB to open the debug console, then type in
// ToggleWidgetUnderMouse
// this puts the UI into a widget debugging mode that lets you inspect
// the widget under the mouse, among other things, telling you its name
// enter the command again to turn the mode back off
// widget flashing
// void FlashWidgetUntilClicked(const char *in_szWidgetName,
bool in_bStopFlashingIfHotkeyActivated)
// flash the specified widget until it gets clicked
// in_szWidgetName must specify a valid sprite widget on either the
// main game screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// if in_bStopFlashingIfHotkeyActivated is true, the widget will also
// stop flashing if its hotkey is triggered
// example usage:
// this flashes the widget named "game_bestWidgetEver" until it is
// clicked or until its hotkey is activated
FlashWidgetUntilClicked("game_bestWidgetEver", true);
// void FlashWidgetForTime(const char *in_szWidgetName,
float in_fTimeInSeconds)
// flash the specified widget for a period of time
// in_szWidgetName must specify a valid sprite widget on either the
// main game screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// in_fTimeInSeconds must be a time value greater than zero
// example usage:
// this flashes the widget named "game_bestWidgetEver" for 3 seconds
FlashWidgetForTime("game_bestWidgetEver", 3);
// void FlashWidgetUntilStopped(const char *in_szWidgetName)
// flash the specified widget until the script stops it again
// in_szWidgetName must specify a valid sprite widget on either the
// main game screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// void StopFlashingWidget(const char *in_szWidgetName)
// stop a widget from flashing
// in_szWidgetName must specify a valid sprite widget on either the
// main game screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// example usage:
// this flashes the widget named "game_bestWidgetEver" until the
// script event which stops it from flashing
FlashWidgetUntilStopped("game_bestWidgetEver");
...
StopFlashingWidget("game_bestWidgetEver");
// widget selection tracking
// void AddWidgetListenForSelection(const char *in_szWidgetName,
bool in_bCountHotkeyActivationAsSelection)
// add the specified widget to the list of those for which we log
// selection activity
// in_szWidgetName must specify a valid widget on either the main game
// screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// if in_bCountHotkeyActivationAsSelection is true, when the hotkey for
// the widget is triggered that will also increment the selection count
// void AddWidgetListenForSelectionWithEventAndArg(
// const char *in_szWidgetName,
// const char *in_szEventName,
// const char *in_szEventArg)
// add the specified widget to the list of those for which we log
// selection activity
// in_szWidgetName must specify a valid widget on either the main game
// screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// you must also specify both an event name and an argument for the
// event. the arg need not be the entire argument string, but rather
// the arg specified must be contained in the arg string of the desired
// event in order to count as a selection
// void RemoveWidgetListenForSelection(const char *in_szWidgetName)
// remove the specified widget from the list of those for which we log
// selection activity
// in_szWidgetName must specify a valid widget on either the main game
// screen or the fullmap
// for this to function correctly, the widget name must be unique
// across both screens
// @NOTE this will fail silently if the widget was not in the list
// already
// bool HasWidgetBeenSelected(const char *in_szWidgetName)
// query the selection activity of the specified widget
// returns true if the widget has been selected since it was added to
// the selection logging list (see AddWidgetListenForSelection()),
// otherwise returns false
// in_szWidgetName must specify a valid widget on either the main game
// screen or the fullmap, and it must be one we are listening for
// selection activity for
// example usage:
// this adds the widget named "game_bestWidgetEver" to the selection
// list, then at some other script event queries if it has been
// selected (including hotkey selection), and if so stops listening for
// selection
AddWidgetListenForSelection("game_bestWidgetEver", true);
RULE BestRuleEver ONESHOT
if (HasWidgetBeenSelected("game_bestWidgetEver")
then
RemoveWidgetListenForSelection("game_bestWidgetEver'');
// do some other stuff too...
END_RULE
// int GetWidgetSelectionCount(const char *in_szWidgetName
// query the selection activity of the specified widget
// returns the number of times the widget has been selected since it
// was added to the selection logging list (see
// AddWidgetListenForSelection())
// in_szWidgetName must specify a valid widget on either the main game
// example usage:
// this adds the widget named "game_bestWidgetEver" to the selection
// list, then at some other script event queries if it has been// selected at least 3 times (excluding hotkey selection), and if so
// stops listening for selection
AddWidgetListenForSelection("game_bestWidgetEver", true);
RULE BestRuleEver ONESHOT
if (GetWidgetSelectionCount("game_bestWidgetEver") >= 3
then
RemoveWidgetListenForSelection("game_bestWidgetEver'');
// do some other stuff too...
bool SelectUnit(const char *in_szUnitName)
// Adds a unit to the current selection for giving an order to.
// Returns true so it can be used in Rules.
// example usage:
//Select the unit that I created in the
//CreateUnitAtLocation example above
SelectUnit("JamesBond");
bool SelectGroup(const char *in_szGroupName)
// Adds the units in the group in_szGroupName to the current selection
// for giving an order to.
// Returns true so it can be used in Rules.
// example usage:
//Pretend I created a group of all my available citizens,
//and now I'm going to select them and tell them to
//kill JamesBond!
SelectGroup("AvailableCitizens");
AttackWithSelection("JamesBond");
bool SelectGroupForPlayer(const char* in_szGroupName,
int in_iPlayerID)
// Select all units in the group that belong to the specified player.
// This is good if you have a group that will be around for a while
// and some of the units in the group might be converted by another
// player. Converting a unit does not remove it from a group, and if
// you try to select a group that has units belonging to multiple
// players, it will cause a crash.
// This command will work fine for a group with units that all
// belong to the same player, so you can just always use this command
// if you want to be safe.
// Returns true so it can be used in Rules.
// Select units that may have been converted by the human player.
SelectGroupForPlayer("WeakMindedFools", 2);
bool ClearSelection()
// Clears the current selection manually. There really isn't a reason
// you should need to use this, as all the operations that work on
// selections clear the selection when they're done, but it's provided
// in case something weird pops up.
// Returns true so it can be used in Rules.
// example usage:
ClearSelection();
You will notice that all the group manipulation functions are boolean. They always return true, for ease of insertion into a rule. Obviously, this is computationally expensive, and you should mitigate it by having a PERIODICITY parameter and bool variable that you check first.
This is what the whole deal would look like:
DEFINITIONS
bool bWhatever
END_DEFINITIONS
INITIALIZATION
bwhatever = FALSE
END_INITIALIZATION
RULE ONESHOT PERIODICITY 3
if (!bWhatever &&
CreateNamedGroup("DudesOnMyLawn") &&
AddUnitsByAttributeToGroup("DudesOnMyLawn", "MobileUnits", 2,
kPlayerMode_Enemies, "MyLawn") &&
(NumUnitsInGroup("DudesOnMyLawn") > 0) )
then CallTheCops
END_RULE
// bool CreateNamedGroup(const char *in_szGroupName)
Define objects as a group
// Creates a group named in_szGroupName. If one already exists, this
// clears it out.
// example usage:
CreateNamedGroup("DudesOnMyLawn");
// bool AddUnitToGroup(const char *in_szGroupName,
// const char *in_szUnitName)
// bool RemoveUnitFromGroup(const char *in_szGroupName,
// const char *in_szUnitName)
// Adds/Removes the unit named in_szUnitName to the group
// in_szGroupName.
// example usage:
AddUnitToGroup("Spies", "JamesBond");
// bool AddGroupToGroup(const char *in_szGroupTo,
// const char *in_szGroupFrom)
// bool RemoveGroupFromGroup(const char *in_szGroupTo,
// const char *in_szGroupFrom)
// Adds/Removes all the units in in_szGroupFrom to the group
// in_szGroupTo.
// example usage:
//copy the units from the three special battalions into
//the 'final strike' wave
AddGroupToGroup("FinalStrike", "SpecialBattalion1");
AddGroupToGroup("FinalStrike", "SpecialBattalion2");
AddGroupToGroup("FinalStrike", "SpecialBattalion3");
//but remove the wounded guys that we selected earlier
//because they can't come along, or something
RemoveGroupFromGroup("FinalStrike", "Wounded");
RemoveGarrisonedUnitsFromGroup("TroopsToMove");
// Removes all units which are garrisoned from the group. Use this before any kind of SelectGroup(); a script error comes up if you try to Select() a garrisoned unit.
// bool AddUnitsByAttributeToGroup(const char *in_szGroupName,
// const char *in_szAttributeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// bool RemoveUnitsByAttributeFromGroup(const char *in_szGroupName,
// const char *in_szAttributeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// Adds all units that meet the criteria specified in
// in_szAttributeName to in_szGroupName. If in_szAreaName is not NULL,
// this further constrains the added units to ones that are in the
// specified area only.
// example usage:
//This will add all mobile units that belong to players that are
//enemies of player 2 to the group "DudesOnMyLawn".
AddUnitsByAttributeToGroup("DudesOnMyLawn",
"MobileUnits", 2, kPlayerMode_Enemies, "MyLawn")
//But pretend for some reason we want to allow animals from
//player 5 in. Note that since DudesOnMyLawn already only has
//units in the MyLawn area in it right now, we don't need to
//specify an area for this remove step.
RemoveUnitsByAttributeFromGroup("DudesOnMyLawn",
"Animals", 5, kPlayerMode_Self, NULL)
// bool AddUnitsByTypeToGroup(const char *in_szGroupName,
// const char *in_szUnitTypeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// bool RemoveUnitsByTypeFromGroup(const char *in_szGroupName,
// const char * in_szUnitTypeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// Adds all units OF THE SPECIFIC UNIT TYPE (not UnitTypeAttribute!)
// in_szUnitTypeName that match the in_iPlayerID and in_iPlayerMode to
// in_szGroupName. If in_szAreaName is not NULL, this further
// constrains the added units to ones that are in the specified area
// only.
// example usage:
//This will add all MALE citizens that belong to player 1
//to the group "Homies".
AddUnitsByTypeToGroup("Homies", "CitizenM",
1, kPlayerMode_Self, NULL);
// bool AddDeadUnitsByAttributeToGroup(const char *in_szGroupName,
const char *in_szAttributeName, int in_iPlayerID,// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// bool AddDeadUnitsByTypeToGroup(const char *in_szGroupName,
// const char *in_szUnitTypeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// Same as the above but for dead units. Note that rules checking for
// dead units should be evaluated at every 2-3 seconds,
// otherwise there's a chance that the dead unit might be removed from
// the world before the rule gets a chance to fire.
// example usage:
// This fires when any unit from player 1 matching the attribute
// "NavalUnits" dies in the area named "InternationalWaters".
RULE ShipDiesInInternationalWaters ONESHOT
if (CreateNamedGroup("DeadInternationalShips") &&
AddDeadUnitsByTypeToGroup("DeadInternationalShips", "NavalUnits",
1, kPlayerMode_Self,
"InternationalWaters") &&
NumUnitsInGroup("DeadInternationalShips") > 0)
then AShipWasKilledInInternationalWaters
END_RULE
// bool AddUnitsInCityToGroup(const char* in_szGroupName,
// const char* in_szAttributeName,
// int in_iPlayerID,
// ePlayerMode in_ePlayerMode,
// const char* in_szCityName)
// Add units within the city to the specified group. It examines all
// units within the area of the city. Any that match the criteria
// of in_szAttributeName and the player information are added to the
// specified group. in_szCityName is the name of a CityCenter unit
// that is the center of the city that you'd like to select.
// RemoveUnitsInCityFromGroup() works the same way, but removes those
// units from the group.
// This adds all mobile units in
// 1 to the group "Urbanites".
AddUnitsInCityToGroup("Urbanites",
"
// But we don't want any civilians in our group, so remove them
// from the group.
RemoveUnitsInCityFromGroup("Urbanites ",
"Citizens", 1, kPlayerMode_Self, NULL)
// bool AddUnitsByAttributeToGroupFromTerritory
// const char *in_szGroupName, const char *in_szAttributeName,
// int in_iPlayerID, ePlayerMode in_ePlayerMode,
// const char *in_szTerritoryName)
// bool RemoveUnitsByAttributeFromGroupFromTerritory
// const char *in_szGroupName, const char *in_szAttributeName,
// int in_iPlayerID, ePlayerMode in_ePlayerMode,
// const char *in_ szTerritoryName)
// Adds or removes all units that meet the criteria specified in
// in_szAttributeName to in_szGroupName as long as they are in the
// specified territory.
// example usage:
//This will add all mobile units that belong to players that are
//enemies of player 2 to the group "DudesOnMyLawn".
AddUnitsByAttributeToGroupFromTerritory ("DudesOnMyLawn",
"MobileUnits", 2, kPlayerMode_Enemies, "MyLawn")
//But pretend for some reason we want to allow animals from
//player 5 in.
RemoveUnitsByAttributeFromGroupFromTerritory ("DudesOnMyLawn",
"Animals", 5, kPlayerMode_Self, "MyLawn")
// bool AddUnitsByTypeToGroupFromTerritory(const char *in_szGroupName,
// const char *in_szUnitTypeName, int in_iPlayerID,
// ePlayerMode in_ePlayerMode, const char *in_szAreaName)
// bool RemoveUnitsByTypeFromGroupFromTerritory
// const char *in_szGroupName, const char * in_szUnitTypeName,
// int in_iPlayerID, ePlayerMode in_ePlayerMode,
// const char *in_szAreaName)
// Adds all units OF THE SPECIFIC UNIT TYPE (not UnitTypeAttribute!)
// in_szUnitTypeName that match the in_iPlayerID and in_iPlayerMode to
// in_szGroupName as long as they are in the specified territory.
// example usage:
//This will add all MALE citizens that belong to player 1
//to the group "Homies", if they are in the territory "ThaHood".
AddUnitsByTypeToGroupFromTerritory ("Homies", "CitizenM",
1, kPlayerMode_Self, "ThaHood"
// bool AddUnitsByAttributeInLOSToGroup(int in_iPlayerWhoSeesID,
// const char* in_szGroupName, const char* in_AttributeName,
// int in_iPlayerWhoControlsID)
// bool AddUnitsByTypeInLOSToGroup(int in_iPlayerWhoSeesID,
// const char* in_szGroupName, const char* in_AttributeName,
// int in_iPlayerWhoControlsID)
// bool RemoveUnitsByAttributeInLOSFromGroup(int in_iPlayerWhoSeesID,
// const char* in_szGroupName, const char* in_AttributeName,
// int in_iPlayerWhoControlsID)
// bool RemoveUnitsByTypeInLOSFromGroup(int in_iPlayerWhoSeesID,
// const char* in_szGroupName, const char* in_AttributeName,
// int in_iPlayerWhoControlsID)
// These functions are all similar. They all either add or remove
// units to a group depending on whether they can be seen by a
// specified player.
// in_iPlayerWhoSeesID is the ID of the player whose LOS we care
// about. Units will only be added to or subtracted from a group
// if in_iPlayerWhoSeesID can see them.
// in_iPlayerWhoControlsID is the ID of the player that owns the units
// to be added or removed. Only units belonging to
// in_iPlayerWhoControlsID will be added to or removed from the group.
// The other two parameters are pretty straightforward. One is the
// the name of the group in question. The other is the name of the
// attribute or type that will be used to get a more fine selection of
// units.
// example:
// This is something I know some of you are waiting for. You
// want to count the total number of units seen by an AI player,
// and do something when there are too many. Player 1 is the
// human player, player 2 is the AI that the human is trying to
// hide his army from. The computer attacks when it knows the
// human has an army of size 10 or more.
RULE ruleLookForMilitary ONESHOT
if(iEverySecond
&& AddUnitsByAttributeInLOSToGroup(2, "HumanArmy",
"MilitaryUnits", 1)
&& NumUnitsInGroup("HumanArmy") >= 10)
then actionLookForMilitary
END_RULE
// bool GroupHasLOSToAnyoneInGroup(const char *in_szWatchers,
// const char *in_szTargets)
// returns true iff anyone in the group in_szWatchers can see anyone in
// in_szTargets. This is crazy slow. You don't want to do this that
// often.
// This fires when any unit from player 1 matching the attribute
// "NavalUnits" dies in the LOS of any "Dock"-type unit from
// player 2.
RULE DocksSeeDeadPeople ONESHOT
if (CreateNamedGroup("MyDeadShips") &&
AddDeadUnitsByTypeToGroup("MyDeadShips", "NavalUnits", 1, kPlayerMode_Self, NULL) &&
CreateNamedGroup("EnemyDocks") &&
AddUnitsByTypeToGroup("EnemyDocks", "Dock", 2, kPlayerMode_Self, NULL) &&
GroupHasLOSToAnyoneInGroup("EnemyDocks", "MyDeadShips"))
then TheySawYourShipDie
END_RULE
// bool PlayerHasLOSToAnyoneInGroup(int in_iPlayerID,
// const char *in_szGroupName)
// returns true if player in_iPlayerID can see anyone
// in the group in_szGroupName.
// example usage:
// If player(x) has LOS to group(y) - anybody
if (PlayerHasLOSToAnyoneInGroup(x, "y") )
// If player(x) has LOS to any unit owned by player(y)
if (CreateGroup("dudes") &&
AddUnitsByAttributeToGroup("dudes", "Anything", y,
kPlayerMode_Self, NULL) &&
PlayerHasLOSToAnyoneInGroup(x, "dudes") )
// If player(x) has LOS to named building\unit
if (CreateGroup("dudes") &&
AddUnitToGroup("dudes", "named_unit") &&
PlayerHasLOSToAnyoneInGroup(x, "dudes") )
// bool UnitHasLOSToAnyoneInGroup(const char *in_szUnitName,
// const char *in_szGroupName)
// returns true if unit in_szUnitName can see anyone in the
// group in_szGroupName.
// example usage:
// If named building\unit has LOS to player(x)
if (CreateGroup("dudes") &&
AddUnitsByAttributeToGroup("dudes", "Anything", x,
kPlayerMode_Self, NULL) &&
UnitHasLOSToAnyoneInGroup("named_unit", "dudes") )
// bool NamedUnitIsInArea(const char *in_szUnitName,
// const char *in_szAreaName)
// bool NamedUnitIsInTerritory(const char *in_szUnitName,
// const char *in_szTerritoryName)
// Returns true iff the unit named in_szUnitName is in in_szAreaName,
// or in in_szTerritoryName, depending on the command used.
// example usage:
//trigger when bond walks into the trap
if (NamedUnitIsInArea("JamesBond", "HiddenSpikePit") ...
// bool AnyoneFromGroupIsInArea(const char *in_szGroupName,
// const char *in_szAreaName)
// bool AnyoneFromGroupIsInTerritory(const char *in_szGroupName,
// const char *in_szTerritoryName)
// Returns true iff ONE OR MORE units from in_szGroupName are in
// in_szTerritoryName. Will return false if in_szGroupName is empty, // or doesn't exist!
// example usage:
//If any of the recon droids get on your lawn, you're toast
if (AnyoneFromGroupIsInArea("ReconDroids", "SecretBase") ...
// bool EveryoneFromGroupIsInArea(const char *in_szGroupName,
// const char *in_szAreaName)
// bool EveryoneFromGroupIsInTerritory(const char *in_szGroupName,
// const char *in_szTerritoryName)
// Returns true iff EVERY SINGLE unit from in_szGroupName is in
// in_szTerritoryName. Will return false if in_szGroupName is empty, // or doesn't exist!
// example usage:
//If you can fight the enemy dudes back to the border, you win
if (EveryoneFromGroupIsInArea("BadDudes", "BehindBorder") ...
// void NameRandomUnitInGroup(const char *in_szGroupName,
// const char *in_szUnitName)
// Picks a random unit in in_szGroupName and names it in_szUnitName.
// Does nothing if const char *in_szGroupName doesn't exist or is
// empty.
// example usage:
NameRandomUnitInGroup("Barbarians", "FocusBarbarian");
// now we can start the cinematic that focuses on FocusBarbarian
// void AwardCrown(int in_iPlayerID, eCrownType whichCrown)
// this will award the crown in_eCrownType to player in_iPlayerID.
// example usage:
// the player just did something that earns him the
// economic crown
AwardCrown(1, kCrownType_Economic);
// void AddCrownPowerForAllPlayers(eCrownType in_eCrownType,
const char* in_szPowerName)
// void RemoveCrownPowerForAllPlayers(eCrownType in_eCrownType,
const char* in_szPowerName)
// void AddCrownPowerForOnePlayer(int in_iPlayerID,
eCrownType in_eCrownType, const char* in_szPowerName)
// void RemoveCrownPowerForOnePlayer(int in_iPlayerID,
eCrownType in_eCrownType, const char* in_szPowerName)
// These all modify the powers that are available to players when
// they win a particular crown. In each case, you specify the
// crown type that is to be changed, and the name of the power
// that is to be added or removed. (For single player modifications
// you also need the ID of the player to be affected.) These
// changes affect both human players and AI players.
// For reference, the default powers available for each crown are
// listed in run/db/Simulation/dbcrowns.ddf. In each crown
// definition, there is an EffectList, with the names of the area
// effects. The area effects, themselves, are defined in
// run/db/AreaEffects/dbareaeffects_crown.ddf. You could create your
// own specialized effects for scenarios. I'd recommend using the
// existing crown effects as templates.
// Example:
// If for some reason you wanted everyone to have the Infantry
// Doctrine power when they won the economic crown instead
// of the military crown, here's what you'd do:
RemoveCrownPowerForAllPlayers(kCrownType_Military,
"InfantryDoctrine");
AddCrownPowerForAllPlayers(kCrownType_Economic,
"InfantryDoctrine");
// void LimitPlayerToOneCrownPower(int in_iPlayerID,
// eCrownType in_eCrownType, const char* in_szPowerName)
// This command is very similar to the above crown power commands.
// This command adjusts the available powers for a particular player
// so that only one power is available when they win the crown. This
// can be used to force an AI player to use a particular power.
// Example:
// Force a computer player to use the Infantry Doctrine power.
LimitPlayerToOneCrownPower(2, kCrownType_Military,
"InfantryDoctrine");
AwardCrown(2, kCrownType_Military);
// void SetControlGroupFromGroup(const char *in_szGroupName,
// int in_iPlayerID, int in_iControlGroupNumber)
// Adds the group named in_szGroupName to one of in_iPlayerID's control
// groups. in_iControlGroupNumber must be between 0 and 9 inclusive.
// example usage:
// Put all my male citizens in control group zero
CreateNamedGroup("CitzM");AddUnitsByTypeToGroup("CitzM", "CitizenM", 1,
kPlayerMode_Self, NULL);
SetControlGroupFromGroup("CitzM", 1, 0);
// void AddToControlGroupFromGroup(const char *in_szGroupName,
// int in_iPlayerID, int in_iControlGroupNumber)
// Adds the group named in_szGroupName to one of in_iPlayerID's control
// groups. in_iControlGroupNumber must be between 0 and 9 inclusive.
// example usage:
// Actually, put all the female citizens in there too
CreateNamedGroup("CitzF");
AddUnitsByTypeToGroup("CitzF", "CitizenF", 1,
kPlayerMode_Self, NULL);
AddToControlGroupFromGroup("CitzF", 1, 0);
// void ClearControlGroup(int in_iPlayerID, int in_iControlGroupNumber)
// Clears one of in_iPlayerID's control groups.
// in_iControlGroupNumber must be between 0 and 9 inclusive.
// example usage:
// Okay I'm bored with all you citizens
ClearControlGroup(1, 0);
// void AddToGroupFromControlGroup(int in_iControlGroupNumber,
// int in_iPlayerID, const char *in_szGroupName)
// Adds the contents of one of in_iPlayerID's control groups to the
// group in_szGroupName. in_iControlGroupNumber must be between 0 and
// 9 inclusive.
// example usage:
// Make the player pay for using control groups!
AddToGroupFromControlGroup(0, 1, "Player1ControlGroup0");
SelectGroup("Player1ControlGroup0");
KillSelection();
// void LookAtControlGroup(int in_iPlayerID,
// int in_iControlGroupNumber)
// Move the camera to look at the centroid of in_iPlayerID's control
// group. in_iControlGroupNumber must be between 0 and 9 inclusive.
// example usage:
PrintMessage("Check out what control group zero is doing!");
LookAtControlGroup(1, 0);
// bool ControlGroupHasUnits(int in_iPlayerID,
// int in_iControlGroupNumber)
// See if the specified player currently has any units assigned to the
// specified control group.
// example
// If the player one has assigned units to control group one.
if(ControlGroupHasUnits(1, 1))
then DoSomething
example AddAirMissionWayPoint("airport1", kAirMission_Strike, 0, 20, 30)
example AddAirMissionWayPoint("airport1", kAirMission_Strike, 0, "bombingArea")
example CancelAirMission ("airport1", kAirMission_Strike, 0)
example AssignAirplaneToMission ("airport1", kAirMission_Strike, 0, "bomber2")
// void MoveSelection(float fX, float fY)
// Give a move goal to the units in the current selection. After
// giving the move goal, this flushes the current selection.
// example usage:
SelectUnit("AmbassadorToPlayer1");
//Send the ambassador to the city gates
MoveSelection(10, 10);
// void MoveSelectionToArea(const char *in_szAreaName)
// void MoveSelectionToTerritory(const char *in_szTerritoryName)
// Give a move goal to the units in the current selection to move to
// the center of the given area or territory. After giving the move
// goal, this flushes the current selection.
// NOTE: Test the territory command to make sure the location used
// matches your expectations. The center of the territory may not be
// where you think it is, and it might be better for you to create an
// area or use an X,Y coordinate instead of using the territory.
// example usage:
SelectUnit("Ben");
//It's 6:00 and guess where I'm going
MoveSelectionToArea("
// void InstantMoveSelection(float fX, float fY, int iMaxDistance)
// Instantly move the current selection to the specified coordinates.
// Units are placed one at a time as close as possible to the
// desired location, but no further than iMaxDistance away. Units
// that cannot be moved because there is no valid place for them will
// not be moved. A warning will be displayed when a unit cannot be
// moved.
SelectUnit("Bob");
// Warp Bob instantly to this spot. But leave a little bit of
// flexibility by setting the iMaxDistance to 1, in case
// there's a tree or other unit already in that location.
InstantMoveSelection(20, 20, 1);
// void InstantMoveSelectionToArea(const char* in_szAreaName,
int iMaxDistance)
// Instantly move the current selection to the center of the specified // area. Units are placed one at a time as close as possible to the
// desired location, but no further than iMaxDistance away. Units
// that cannot be moved because there is no valid place for them will
// not be moved. A warning will be displayed when a unit cannot be
// moved.
SelectGroup("BobAndFriends");
// Party at Bob's! Better leave a large iMaxDistance because
// Bob has a lot of friends, and we want them all to fit.
InstantMoveSelectionToArea("BobsHouse", 3);
// void PatrolWithSelection(const char *in_szPoint1,
const char *in_szPoint2, const char *in_szPoint3,
const char *in_szPoint4, const char *in_szPoint5,
const char *in_szPoint6, const char *in_szPoint7,
const char *in_szPoint8)
// Set the selected units on patrol to eight areas in order. If you
// want less patrol points, simply put in NULL for the later areas.
// Clears the selection.
// example usage:
SelectUnit("PatrolGuy");
PatrolWithSelection("PatrolArea1", "PatrolArea2",
"BreakRoom", "PatrolArea3", "BreakRoom",
NULL, NULL, NULL)
// void SetSelectionFormation(const char *in_szFormationName)
// Puts the selection in the formation named in_szFormationName.
SelectGroup("CosbyKids");
SelectUnit("FatAlbert");
SetSelectionFormation("Wedge");
// Note that SetSelectionFormation() doesn't clear the selection,
// so I can immediately follow it with:
MoveSelectionToArea("Wherever");
// if I didn't move them, I'd have to do a ClearSelection().
// void AttackAreaWithSelection(const char *in_szAreaName)
// Give an attack area goal to the currently selected units, targeted
// at the area named in_szAttackee. This is only for units with area
// attacks (projectiles, etc.), not for telling the selection to kill
// everyone in a given area. After giving the goal, this flushes the
// current selection.
// example usage:
SelectGroup("Bombers");
AttackAreaWithSelection("
// void MoveSelectionWithAttack(float fX, float fY,
bool in_bGroupAttack)
// void MoveSelectionToAreaWithAttack(const char *in_szAreaName,
bool in_bGroupAttack)
// void MoveSelectionToTerritoryWithAttack(
const char *in_szTerritoryName, bool in_bGroupAttack)
// These do the same as the "MoveSelection" commands, but they will
// attack enemy units on the way there. If in_bGroupAttack is true,
// they will attack in formation. If in_bGroupAttack is false, then
// only dudes who are set to agressive stance will peel off and attack
// individually while the rest continue on.
// example usage:
SelectUnit("JackieChan");
MoveSelectionToAreaWithAttack("TheBronx", false);
// void AttackWithSelection(const char *in_szAttackee)
// Give an attack goal to the currently selected units, targeted at the
// unit/group named in_szAttackee. After giving the goal, this flushes
// the current selection.
// example usage:
//If we've detected someone coming in, shoot them!
SelectUnit("FrontGateCannon");
AttackWithSelection("DudesOnMyLawn");
// void AttackGroupWithSelection(const char *in_szTargetGroupName)
// force the currently selected units to attack the group named
// in_szAttackee.
// This flushes the current selection.
// example usage:
SelectUnit("Grandma");
AttackGroupWithSelection("Ruffians");
// void SetSelectionStance(eStanceType in_eStance)
// set the stance of units in the current selection to in_eStance.
// This flushes the current selection.
// example usage:
// Set my dudes agressive, so if they see someone, they'll
// kill him
SetSelectionStance(kStanceType_Aggressive);
// void SearchAndDestroyWithSelection()
// Assign a search-and-destroy tactical goal to the current selection.
// This flushes the current selection.
// example usage:
SelectUnit("HansBlix");
SearchAndDestroyWithSelection();
// void SearchAndDestroyWallsWithSelection()
// Assign a search-and-destroy tactical goal to the current selection.
// The units will ONLY target walls. WALLS ONLY NO MATTER WHAT
// This flushes the current selection.
// example usage:
SelectUnit("HansBlixen");SearchAndDestroyWallsWithSelection();
// void GatherFromNamedUnitWithSelection(const char *in_szUnitName)
// make the selected units gather from the NAMED resource pile,
// in_szUnitName.
// I don't know what the hell this means but hey
SelectUnit("BrerRabbit");
GatherFromNamedUnitWithSelection("BramblePatch")
// void GuardWithSelection(const char* in_szUnitToGuard)
// Instruct the current selection to guard the named unit. It's the
// same as giving a guard command in the game.
// Guard the president from those evil terrists.
SelectGroup("SecretService");
GuardWithSelection("ThePresident");
// void StopSelection()
// Just send a stop command to the selection. This clears the
// selection.
// Just stop.
StopSelection();
// void CaptureWithSelection(const char *in_szTarget)
//force the currently selected units to capture the unit/group named
//in_szTarget. This flushes the current selection.
// example usage:
SelectUnit("ChechenRebels");
// I am obviously running out of examples here
CaptureWithSelection("RussianOperaHouse");
// void ExploreWithSelection()
// Assign an exploration tactical goal to the current selection.
// This flushes the current selection.
// example usage:
SelectUnit("Lewis");
SelectUnit("Clark");
ExploreWithSelection();
// bool IsUnitExploring(const char* in_szUnitName)
// Checks to see if the named unit currently has an explore goal.
// Example usage:
RULE
If(IsUnitExploring("Magellan"))
Then CrewMutinies
END_RULE
// bool IsAnyoneInGroupExploring(const char* in_szGroupName)
// Checks to see any unit in the named group currently has an
// explore goal.
// Example usage:
RULE
If(IsAnyoneInGroupExploring ("Vikings"))
Then Pillage
END_RULE
bool IsUnitPatrolling(const char* in_szUnitName)
bool IsAnyoneInGroupPatrolling(const char* in_szGroupName)
Check to see if a particular unit, or if any unit in a group, currently has a patrol goal.
// void Script_GarrisonSelection(const char *in_szContainerName)
// Garrison selection into in_szContainerName.
// example usage:
//hide...
SelectUnit("DickCheney");
GarrisonSelection("UndisclosedLocation");
// void Script_UngarrisonSelection()
// Ungarrison selected container.
//...and unhide.
SelectUnit("UndisclosedLocation");
UngarrisonSelection();
// bool IsUnitGarrisoned(const char* in_szUnitName)
// Check if the specified unit is garrisoned in anything at all.
// Move Bob to the battlefield, so long as he's not hiding
// somewhere.
If(!IsUnitGarrisoned("Bob"))
// int GetNumGarrisoned(const char *in_szGroupName)
// Count the number of units in the group named in_szGroupName
// that are garrisoned.
RULE
// if more than 5 citizens belonging to player 1 are garrisoned,
// do something. NOTE!! This DOES NOT WORK if you try to add units
// in an area. Garrisoned units do NOT SHOW UP in areas.
if( CreateNamedGroup("CitizenGroup") &&
AddUnitsByTypeToGroup("CitizenGroup", "Citizen", 1,
kPlayerMode_Self, NULL) &&
GetNumGarrisoned("CitizenGroup") > 5 )
then HouseParty
END_RULE
// int CountUnitsGarrisonedInUnit(const char* in_szUnitName)
// Given the name of a unit that can hold other units
// (transport, fortress, etc), count the number of units that are
// garrisoned in that unit.
// Example:
// If the transport has enough people, then it's time to
// sail to the new world
RULE
if(CountUnitsGarrisonedInUnit("TheMayflower"))
then SailToTheNewWorld
END_RULE
// int CountUnitsGarrisonedInGroup(const char* in_szGroup)
// Counts all of the units garrisoned in the group. It examines each
// unit in the group. If the unit has the garrison ability, it adds
// the amount of units it presently contains to the total. The command
// ignores any units in the group that do not have the garrison ability.
// example:
// See if the player has garrisoned any citizens in his
// wearhouses
RULE
If(CountUnitsGarrisonedInGroup("Warehouses"))
Then PatPlayerOnTheBack
END_RULE
// void KillSelection()
// Kill/remove object/group
// example usage:
SelectGroup("DudesOnMyLawn");
// Pretend they died instantaneously of my poisonous lawn
// treatment chemicals..?
KillSelection();
// void RemoveSelection()
// Kill/remove object/group
// example usage:
SelectGroup("GuysOnEdgeOfMap");
// Pretend they got away from the feds and are effectively
// out-of-the-world, now.
RemoveSelection();
// void HealUnit(const char *in_szUnitName)
// void HealGroup(const char *in_szGroupName)
// Restore object/group's health
// example usage:
HealGroup("SuperSoldiers");
// void DamageUnit(const char *in_szUnitName, float in_fAmount)
// void DamageGroup(const char *in_szGroupName, float in_fAmount)
// Instantly cause in_fAmount damage to the specified unit or group.
// This CAN kill a unit.
// example usage:
// Cause damage to a particular city center.
DamageUnit("ComputerCityCenter", 500);
// void SetUnitOwnedBy(const char *in_szUnitName,
int in_iPlayerID)
// void SetGroupOwnedBy(const char *in_szGroupName,
int in_iPlayerID)
// Change ownership of object/group to player x
// example usage:
//He's defecting to the human player's side!
SetUnitOwnedBy("DoubleAgent", 1);
// void SetUnitSpecialForces(const char *in_szUnitName,
bool in_bSpecial)
// void SetGroupSpecialForces(const char *in_szGroupName,
bool in_bSpecial)
// Set Scripted Unit - "Special Forces"
// Marks/Clears the selected units as 'special forces', so that
// the strategic AI won't touch them.
// example usage:
//For a while, keep him out of the eyes of the strategic AI so
//it doesn't accidentally send him to gather firewood while we're
//trying to get him to infiltrate the enemy city
SetUnitSpecialForces("JamesBond", true);
// void SetResourcesGatheredTypeAndAmount(eResourceType in_resourceType
int in_iAmount)
// For the selected unit(s), this function forces the unit to carry
// the type and amount of resources specified. The amount is
// restricted by the unit's carry limit, so if a citizen can only
// carry 15 pieces of food, and you try to tell it to carry 200
// pieces of food, it will only end up carrying 15 pieces of food.
// The list of resources that you can specify for this function can
// be found in DbResourceDefs.h. Look for eResourceType.
// This function does NOT change the goal of the affected units.
// This forces Bob to carry lots of gold.
SelectUnit("Bob");
SetResourcesGatheredTypeAndAmount(kResourceType_Gold, 15)
// void SetResourcesGatheredAmount(int in_iAmount)
// For the selected unit(s), this function forces the unit to carry
// the amount of resources specified. This does not change they type
// of resources that the unit is carrying. The amount is
// restricted by the unit's carry limit, so if a citizen can only
// carry 15 pieces of food, and you try to tell it to carry 200
// pieces of food, it will only end up carrying 15 pieces of food.
// If the unit was not previously carrying any resources, the
// unit will end up carrying food in the amount specified.
// This function does NOT change the goal of the affected units.
// This forces Bob to drop whatever he's carrying.
SelectUnit("Bob");
SetResourcesGatheredAmount(0);
// bool IsSelectionInsideCity(const char* in_szCityName, bool in_bAll)
// Check the current selection, and determine if it is within the
// specified city. in_szCityName is the name of the CityCenter unit
// that the city is built around. in_bAll determines whether the
// entire selection is required to be in the city, or if only part of
// the selection needs to be in the city. If in_bAll is true, then
// the command only returns true if all of the units in the selection
// are within the area of the city. If in_bAll is false, then the
// command will return true if one or more of the units in the
// selection are within the area of the city.
// Make sure everyone is at Bob's city before we start the
// party.
SelectGroup("BobsFriends");
if(IsSelectionInsideCity("BobsCityCenter", true))
// NOTE there is no PartyInTheStreets() command. Really.
// Don't try it, it won't work.
// void UseSpecialPowerSelf(const char* in_szSpecialPower)
// void UseSpecialPowerTarget(const char* in_szSpecialPower,
const char* in_szTargetUnitName)
// void UseSpecialPowerLocation(const char* in_szSpecialPower,
float in_fX, float in_fY)
// These commands instruct the current selection to use the specified
// special power. The commands look at each unit in the selection, and
// see if the unit is capable of using the special power. If it is,
// it be instructed to use the special power. Using these commands is
// essentially the same as using a special power button on the
// UnitStats panel in the game. As such, it only makes sense to use
// powers that show up there.
// in_szSpecialPower is the name of the AreaEffect that coordinates the
// power. AreaEffects can be found in run\db\AreaEffects, but in order
// to be used in this command, they must also be attached to units
// through the SpecialPower ability. (Leaders have these powers, for
// example)
// Some powers instantly affect the unit that has the power, or an area
// around the unit. For these powers, use UseSpecialPowerSelf.
// Some powers affect a specific target unit. For these powers, use
// UseSpecialPowerTarget.
// Some powers affect the area around a location. For those powers,
// use UseSpecialPowerLocation.
// You will receive a warning if you use the wrong command to activate
// an effect.
// Make the military leader Napoleon hustle his troops to battle.
// But first, ensure that he is at full power.
SelectUnit("Napoleon");
RechargePowerReserve();
SelectUnit("Napoleon");
UseSpecialPowerSelf("FireAndManeuver");
// void UseSpecialPowerOnTargetInArea(const char* in_szPowerName,
const char* in_szAreaName)
// Chooses a random, valid target from all units in the area named
// in_szAreaName. All units in the current selection are then ordered
// to use the named special power on the chosen target.
// NOTE: The power specified should be one that expects a single unit// as a target.
// Make James Bond poison a building in
SelectUnit("JamesFreakinBond");
RechargePowerReserve();
SelectUnit("JamesFreakinBond");
UseSpecialPowerOnTargetInArea("TozicSpill", "// void UseSpecialPowerOnTargetInGroup(const char* in_szPowerName,
const char* in_szGroupName)
// Chooses a random, valid target from all units in the group named
// in_ szGroupName. All units in the current selection are then
// ordered to use the named special power on the chosen target.
// NOTE: The power specified should be one that expects a single unit
// as a target.
// Make James Bond poison a warehouse in
SelectUnit("JamesFreakinBond");
RechargePowerReserve();
SelectUnit("JamesFreakinBond");
UseSpecialPowerOnTargetInGroup("TozicSpill",
"WarehousesInBerlin");
// void RechargePowerReserve()
// Forces all units in the current selection to regain all power in
// their power reserves.
// Force a priest to regain his power so he can convert more
// units.
SelectUnit("FatherBob");
RechargePowerReserve();
// bool HasPlayerUsedSpecialPowerRecently(int in_iWhichPlayer,
eEffectType in_whichEffect, float in_fTimePeriod)
// See if any unit belonging to the specified player has used a power
// of the specified effect type within the time period prior to when
// the command was called. If a unit has used the power, then the
// command returns true, otherwise it returns false. See the enum
// section below for an abbreviated list of the effect types that
// might be used. I'm not including the comprehensive list of effect // types because it is quite long, and I haven't tested them all. And // most of them probably won't even be used for this command anyway.
// Example:
// This sees if an AI has sabotaged something recently. If the
// AI succeeds, then the player loses the scenario.
RULE ONESHOT
if (HasPlayerUsedSpecialPowerRecently(1, kEffectType_Sabotage, 1)
&& iEverySecond)
then OhNoTerroristsGotInYouLose
END_RULE
// int NumTimesPlayerUsedRegionPower(int in_iPlayerID)
// Get the number of times that the player has used his region power.
// example usage:
RULE ONESHOT
If(NumTimesPlayerUsedRegionPower(1) >=1)
Then PatPlayerOnTheBack
END_RULE
bool IsEffectOfTypeOnSelection(eEffectType in_whichEffect,
bool in_bAll)
Query to find out if a subeffect of the specified type is affecting one or more unit in the selection. Call this after selecting one or more units. This command will clear the selection. If in_bAll is true, all selected units must have the effect for the command to return true. If in_bAll is false, only one unit in the selection must have the effect for the command to return true.
Example:
// Check to see if any Player 1 cities have been sabotaged.
// Assume that the group "Player1Cities" is up to date.
RULE CheckForSabotage ONESHOT
if (SelectGroup("Player1Citites")
&& IsEffectOfTypeOnSelection(kEffectType_Sabotage, false)
)
then FixSabotagedCities
END_RULE
// The following commands are used for using the script to order units
// in the game to construct walls or roads at predetermined locations.
// There is a specific sequence of steps that needs to be followed when
// doing this construction, as laid out in the example.
// CAUTION: Check your walls and roads in game! There might be gaps
// or irregularities that you don't like, so make sure the command
// is doing exactly what you expect it to.
// void StartBuildWall(int in_iPlayerID, float in_fX, float in_fY,
const char* in_szWallBaseType);
// void StartBuildRoad(int in_iPlayerID, float in_fX, float in_fY,
const char* in_szRoadBaseType);
// These commands are used to start building a wall or road. The
// player ID is the player to whom the roads or walls will belong. X
// and Y are the coordinates of the start location. The string is the
// name of a basetype. For walls, it should be "Palisade" or "Wall".
// For roads, it should presently be "Road1_Piece".
// You must call SelectionBuildConnectable after StartBuildWall or
// StartBuildRoad and in the same step, or you will get an error.
// void AddConnectableWaypoint(float in_fX, float in_fY)
// This adds a waypoint to a road or wall that you have already started
// with one of the above commands. Use this command for each corner in
// your road/wall and for the final end position. The waypoint is
// added at the specified X,Y location.
// This command may produce errors if you try to add a waypoint that
// is not valid. Invalid waypoints are those that would create
// segments at bad angles.
// Do not call AddConnectableWayPoint without calling StartBuildWall
// or StartBuildRoad first in the same step, or you will get an error.
// void SelectionBuildConnectable()
// Order the current selection to build the wall/road most recently
// started by the above functions. The selected units should probably
// belong to the same player that you specified in the start function.
// Do not call SelectionBuildConnectable without calling StartBuildWall
// or StartBuildRoad first in the same step, or you will get an error.
// Example of building a
wall:
// This is how you would go about building a wall. This wall will have
// three main segments and stretch from position 10,10 to 15,15 to
// 20,15 to 25,10. It would essentially look like this:
______
/ \
/ \
// Aggregate the information about the wall that we want to build
StartBuildWall(1, 10, 10);
AddConnectableWaypoint(15, 15);
AddConnectableWaypoint(20, 15);
AddConnectableWaypoint(25, 10);
// Select the some citizens to build the wall.
SelectGroup("Masons");
// And order the citizens to build the above wall.
SelectionBuildConnectable();
// When the last call executes, foundations will be placed for
// wall that was laid out, and the selected citizens will go and
// start to build it.
// void BlinkSelectionCircles(float in_fDuration)
// Blink the selection circles (or squares for buildings) for the
// specified duration. The selection circle will blink on and off
// regardless of whether the unit is selected or not.
// example usage:
// Blink napoleon for ten seconds so the player knows who he is:
SelectUnit("Napoleon");
BlinkSelectionCircles(10);
Internationalized Message Formatting
// void StartFormat(const char *in_szTextDBEntry)
// Starts a formatted message. You must either PrintFormattedMessage()
// or PrintFormattedSubtitle() by the end of the STEP.
// example usage:
// use this particular token for the message we're about to send.
// in the DB, it looks like:
// "%PNAME%, the %CIV% king, demands %AMT% %RES% from you,
// on penalty of %PENALTY!%!"
StartFormat("tx_ex_kingdemands");
// void FormatPlayerName(const char *in_szArgument, int in_iPlayerID)
// Formats in_szArgument to the name of player in_iPlayerID.
// example usage:
// The player name of player 2:
FormatPlayerName("PNAME", 2);
// void FormatPlayerCiv(const char *in_szArgument, int in_iPlayerID)
// Formats in_szArgument to the civilization of player in_iPlayerID.
// example usage:
// His civilization:
FormatPlayerCiv("CIV", 2);
// void FormatInt(const char *in_szArgument, int in_iValue)
// Formats in_szArgument to a given integer value.
// example usage:
// Let's say he wants 100 gold
FormatInt("AMT", 100);
// void FormatFloat(const char *in_szArgument, float in_fValue)
// Formats in_szArgument to a given floating-point value.
// example usage:
// We could also say he wants 100.0 gold, I guess:
FormatFloat("AMT", 100);
// void FormatEnum(const char *in_szArgument,
const char *in_szEnumName, int in_iValue)
// Formats in_szArgument to the descriptive name of a given
// enumeration. For instance, for 'Gold', you'd pass in "eResourceType"
// and kResourceType_Gold. For 'Military', you'd pass in "eCrownType"
// and kCrownType_Military.
// example usage:
// But he definitely wants gold, yeah.
FormatEnum("RES", "eResourceType", kResourceType_Gold);
// void FormatString(const char *in_szArgument,
const char *in_szTextDBEntry)
// Format in_szArgument to another string from the text DB.
// example usage:
// Let's be nice for the little kids in the audience
if (iDifficultyLevel > 1)
FormatString("PENALTY", "death");
else
FormatString("PENALTY", "tickling");
void PrintMessage(const char *in_szMessage)
// prints a message to the screen. Currently just using the network
// chat widget. in_szMessage is the lookup for an internationalized
// message in the text DB.
// example usage:
PrintMessage("tx_k1_castleunderattack");
void PrintMessageFromPlayer(const char* in_szMessage, int in_iPlayerID)
// Prints a chat message to the screen, and makes it appear as if it were a chat sent by the specified player.
// Send a custom taunt to the player.
PrintMessageFromPlayer( "tx_somecustomtaunt", PLAYER_ID );
void PrintFormattedMessage()
// Prints the formatted message started with StartFormat() to the
// main message window.
// example usage:
StartFormat("tx_t1_grocerylist");
// don't forget these
FormatString("ITEM", "tx_t1_nicotinepatch");
PrintFormattedMessage();
void PrintFormattedMissionStatusString (int in_iStringID)
// Prints the formatted message into a status string which may be shown
// and hidden at a later time. This command otherwise behaves like
// PrintFormattedMessage, and must follow a call to StartFormat.
// When shown, the string is persistent and will remain on screen
// until hidden. This is unline messages, which disappear after a
// time. See the section "Create and update a status string" below
// for an example of use.
void ClearMessage()
// Clears the message window.
// example usage:
// All that stuff I printed about how every civilization in
// history is attacking us simultaneously is probably obscuring
// the battlefield a bit, so why don't I -
ClearMessage();
void ShowMissionTimerWidget(int in_iTimerID, bool in_bShow)
// see the "Mission Timer" section above.
virtual void Script_SetVisualStateOnUnit(const char *in_szUnitName, const char *in_szVisualStateName, float in_fStateLoopTime, EVisualLoopType in_eLoopType)
// Set state(visual) on a unit.
// example usage:
//Look busy, even if you're not
SetVisualStateOnUnit("OverworkedPeasant", "Harvesting",
0, eVISUAL_LOOP)
void SetCameraLookAt(float in_fX, float in_fY, bool in_bPIP)
// Move the game camera to look at location in_fX, in_fY.
// if in_bPIP is true, sets the pip camera instead of the main camera.
// Make the main camera look at the settlers in the southwest
SetCameraLookAt(10, 10, false);
void SetCameraLookAtArea(const char *in_szAreaName, bool in_bPIP)
// Move the game camera to look at area in_szAreaName.
// if in_bPIP is true, sets the pip camera instead of the main camera.
// Show the settlement area in the PIP
SetCameraLookAtArea("Settlement", true);
void SetCameraHeading(float in_fAngle, bool in_bPIP)
// Set the camera's heading to in_fAngle (where in_fAngle is between
// 0 and 360). 0 is facing east, 90 is facing north, 180 is facing
// west, and 270 is facing south.
// if in_bPIP is true, sets the pip camera instead of the main camera.
// Show the settlement from the west facing east so we
// can see the sunrise or something
SetCameraHeading(0, true);
void SetCameraDistanceFraction(float in_fFraction, bool in_bPIP)
// set the camera distance fraction. 0 is the minimum distance, 1 is
// the maximum zoom-out.
// if in_bPIP is true, sets the pip camera instead of the main camera.
// example usage:
// zoom all the way out to start
SetCameraDistanceFraction(1, false);
void DebugOutputString(const char *in_szDebugString)
// Place a string in the debug buffer.
// example usage:
DebugOutputString("At the DebugOutputString() call");
void ClearDebugBuffer()
// Clear the debug buffer.
// example usage:
ClearDebugBuffer();
void PIPSetBookmarkLocation(int in_iPlayerID, int in_iBookmark,
float in_fX, float in_fY, float in_fDistance)
// set the specified bookmark of the specified player to a location
// requirements:
// in_iPlayerID must specify a valid player
// in_iBookmark must be a valid bookmark number (1-6)
// in_fX, in_fY must specify a valid map location
// in_fDistance is the camera distance (0.0 to 1.0;
0.0 is most zoomed in, 1.0 is most zoomed out)
// example usage:
// set player 1's first bookmark to be the SW corner,
// at the closest-to-the-ground camera angle
PIPSetBookmarkLocation(1, 1, 0, 0, 0.0);
void PIPSetBookmarkUnit(int in_iPlayerID, int in_iBookmark, const char *in_szUnitName, float in_fDistance)
// set the specified bookmark of the specified player to a unit
// requirements:
// in_iPlayerID must specify a valid player
// in_iBookmark must be a valid bookmark number (1-6)
// in_szUnitName must refer to a valid named unit
// in_fDistance is the camera distance (0.0 to 1.0;
0.0 is most zoomed in, 1.0 is most zoomed out)
// example usage:
// Or we could look at this guy. max zoom out, please.
PIPSetBookmarkUnit(1, 1, "Fabio", 1.0);
// void PIPViewBookmark(int in_iBookmark)
// view the specified bookmark of the current player
// will have no effect if the bookmark is not set
// @NOTE viewing a specific bookmark will turn off cycling mode, so
// you should call PIPViewBookmark() BEFORE you call PIPCycleMode()
// requirements:
// in_iBookmark must be a valid bookmark number (1-6)
// example usage:
// So what's Fabio up to today?
PIPViewBookmark(1);
// void PIPCycleMode(bool in_bCycle)
// turn on/off PIP cycle mode
// @NOTE viewing a specific bookmark will turn off cycling mode, so
// you should call PIPViewBookmark() BEFORE you call PIPCycleMode()
// example usage:
// you want the PIP to cycle:
PIPCycleMode(true);
// you don't want the PIP to cycle:
PIPCycleMode(false);
// rock on!
// void PIPEnable(bool in_bEnable)
// turn PIP window on/off
// @NOTE current implementation changes the actual game setting for
// PIP on/off; this may not be desirable...
// example usage:
// turn PIP window on:
PIPEnable(true);
// turn PIP window off:
PIPEnable(false);
// bool IsUnitBookMarked(const char* in_szUnitName)
// See if the specified unit is bookmarked by the PIP.
// example:
// Smile! You're on our hidden camera. Although, this
// might give the wrong idea. This function will return
// true if the unit is bookmarked on any pip button,
// even if the pip is currently viewing something else.
RULE
If(IsUnitBookMarked("Exhibitionist"))
Then DoSomethingNaughty
END_RULE
// bool IsUnitSelectedUI(const char* in_szUnitName)
// bool IsGroupSelectedUI(const char* in_szGroupName)
// Check if a particular unit or group is in the current UI
// selection. For the group function, all units in the
// group must be selected for it to return true.
// example:
// You could be really, really mean to the player:
RULE
If(IsUnitSelectedByPlayer("Bob"));
Then RemoveBobFromGame
END_RULE
// bool IsWidgetVisible(const char* in_szWidgetName)
// Check to see if a particular UI element is visible.
// Can be used to see which parts of the UI are in use.
// Speak to a programmer to determine the appropriate
// widget name for your purposes.
// Example:
// See if the player is looking at the citizen manager:
if(IsWidgetVisible("fullmap_citizenmanager"))
then DoSomething
void SetWarPlanDeleteEnabled(bool in_bEnabled)
void SetWarPlanCopyEnabled(bool in_bEnabled)
void SetWarPlanSendToAlliesEnabled(bool in_bEnabled)
These commands enable or disable specific widgets on the warplan manager. When the widget is disabled, it will be grayed out. The player will not be able to click on it, nor will the hotkey function. The widgets may still be flashed when disabled.
// bool ShowMonthWidget(bool in_bShow)
// Show or hide the widget that displays the current month
// in text form.
// Example:
// Show the widget that displays the current month
ShowMonthWidget(true)
// Hide the widget that displays the current month
ShowMonthWidget(false)
// bool IsUserPlacingType(const char* in_szUnitTypeName)
// Is the user presently using the mouse to place a unit of the
// specified type name. Returns true if she is, false if
// she isn't.
// Example:
// For a tutorial, play some VO when the user starts to place a
// city center.
RULE isPlacingCityCenter
if(IsUserPlacingType("CityCenter"))
then PlayTutorialVO
END_RULE
// bool HasTextBeenTyped( const char *in_szText)
// Check and see if the specified text has been typed into
// the chat box during the current game. Note that this check
// is case insensitive. Therefore if you are checking for "BAR"
// and "bar" had been typed into the chat box, true would be
// returned.
// Example:
// is steve rocking?
if( HasTextBeenTyped("steve is rocking") )
then playSomeRockingMusic
// void SuppressTerritoryMessages(bool in_bSuppressMessages)
// Call this function and pass true to stop all messages normally
// generated when territories change ownership. Call it and pass
// false to allow messages to happen again.
// Call this in the initialization section of a script
// to disable territory messages for the whole game.
SuppressTerritoryMessages(true);
void ShowMissionStatusString(int in_iStringID, bool in_bShow)
Shows or hides the string specified by the ID. Does not change the contents of the string, which you need to set with PrintFormattedMissionStatusString. See the section "Create and update a status string" below for an example.
// void SetAIDiplomacyEnabled(int in_iPlayerID, bool bEnabled)
// Toggles on/off AI diplomacy, if shut off, AI will never send/accept
// alliances on its own, everything must be scripted. If on, it'll use
// its own ideas about what to accept. When using the UNDOCUMENTED script command StartAllianceProposal, you need to disable diplomacy of the AI with this command.
// example usage:
// let AI 2 deal with the player, we don't want to script him
SetAIDiplomacyEnabled(2, true)
// void SetAIWarplansEnabled (int in_iPlayerID, bool in_bEnabled)
// Toggles on/off AI warplan responsiveness, if shut off, AI will never // respond to warplans on its own, everything must be scripted. If on,
// it'll use its own ideas about what to accept
// example usage:
// let AI 2 deal with the player, we don't want to script him
SetAIWarplansEnabled (2, true)
// void SetAITauntsEnabled(bool bEnabled)
// Toggle on/off AI taunting - this is global, NOT on a per AI basisthe system defaults to OFF
// turn on taunt system for all AIs
SetAITauntsEnabled(true);
// void ForceSurrenderOffer(int in_iPlayerAI, int in_iPlayerHuman)
// force the AI in_iPlayerAI to surrender to in_iPlayerHuman
// YOU HAVE TO ENABLE STRATEGIC LEVEL DIPLOMACY FOR THIS PLAYER, OR YOU
// WILL GET A WEIRD CRASH WITH A NON OBVIOUS ERROR MESSAGE:
// DO THIS FIRST: SetAIDiplomacyEnabled()
// eDiplomaticState GetDiplomaticState(int in_iFromPlayer,
int in_iToPlayer)
// Get the diplomatic stance of in_iFromPlayer towards in_iToPlayer.
// It will be either kDiplomaticState_Hostile,
// kDiplomaticState_Neutral, or kDiplomaticState_Allied.
// example usage:
//If you're gonna be a dork about it...
if (GetDiplomaticState(1, 2) == kDiplomaticState_Hostile ...
// void SetDiplomaticState(int in_iFromPlayer, int in_iToPlayer,
eDiplomaticState in_eState)
// Set the diplomatic stance of in_iFromPlayer towards in_iToPlayer.
// It MUST be either kDiplomaticState_Hostile or
// kDiplomaticState_Neutral - to create alliances, you need to call
// EnterAllianceProposal/AcceptWaitingProposal or ForceAlliance.
// For those calls, you don't need a SetDiplomaticState call, just
// the alliance call.
// example usage:
//... then _I'M_ gonna be a dork about it too!
SetDiplomaticState(2, 1, kDiplomaticState_Hostile)
// bool IsDiplomaticStateLocked(int in_iPlayer1ID, int in_iPlayer2ID)
// Query whether the diplomatic state between in_iPlayer1ID and
// in_iPlayer2ID is locked.
// example usage:
//have we locked the state?
if (IsDiplomaticStateLocked(1, 2) ...
// void LockDiplomaticState(int in_iPlayer1ID, int in_iPlayer2ID)
// void UnlockDiplomaticState(int in_iPlayer1ID, int in_iPlayer2ID)
// Lock or unlock the diplomatic state between in_iPlayer1ID and
// in_iPlayer2ID. This locks/unlocks in BOTH directions - you
// can't lock the way player 1 feels about player 2 but leave
// player 2 unlocked in the way he feels about player 1.
// example usage:
//Keep these guys fighting
SetDiplomaticState(2, 3, kDiplomaticState_Hostile);
SetDiplomaticState(3, 2, kDiplomaticState_Hostile);
LockDiplomaticState(2, 3);
// void EnterAllianceProposal(int in_iPlayer1ID, int in_iPlayer2ID,
eAllianceDuration in_eDuration, float in_fLength,
eAllianceLOSState in_eLOS,
eAllianceBorderPerm in_eBorderPermission,
eAllianceResRight in_eResourceRight)
// Makes in_iFromPlayer propose an alliance to in_iToPlayer with the
// specified parameters. If in_eDuration is kAllianceDuration_Timed,
// then in_fLength is the length (in seconds) of the alliance.
// Otherwise, just send in a 0 or whatever, it doesn't matter.
// example usage:
//friends 4-ever (well, actually, for 45 seconds)
EnterAllianceProposal (2, 3, kAllianceDuration_Timed, 45,
kAllianceLOSState_Full, kAllianceBorderPerm_Full,
kAllianceResRight_Full)
// void ForceAlliance(int in_iPlayer1ID, int in_iPlayer2ID,
eAllianceDuration in_eDuration, float in_fLength,
eAllianceLOSState in_eLOS,
eAllianceBorderPerm in_eBorderPermission,
eAllianceResRight in_eResourceRight)
// Forces in_iFromPlayer into an alliance with in_iToPlayer with the
// specified parameters. If in_eDuration is kAllianceDuration_Timed,
// then in_fLength is the length (in seconds) of the alliance.
// Otherwise, just send in a 0 or whatever, it doesn't matter.
// For this calls, you don't need a SetDiplomaticState call, just
// the alliance call.
// example usage:
//behind the scenes, have 2 and 3 ally so it's harder for the
//player to take them down
ForceAlliance (2, 3, kAllianceDuration_UntilWar, 0,
kAllianceLOSState_Full, kAllianceBorderPerm_Full,
kAllianceResRight_Full)
// bool IsAllianceProposalWaiting(int in_iPlayer1ID, int in_iPlayer2ID)
// float GetWaitingProposalTimeElapsed (int in_iFromPlayer,
int in_iToPlayer)
---===And===---
// eAllianceDuration GetWaitingProposalDurationType(int in_iFromPlayer,
int in_iToPlayer)
// float GetWaitingProposalDuration (int in_iFromPlayer,
int in_iToPlayer)
// eAllianceLOSState Script_GetWaitingProposalLOSState
(int in_iFromPlayer, int in_iToPlayer)
// eAllianceBorderPerm GetWaitingProposalBorderPermission
(int in_iFromPlayer, int in_iToPlayer)
// bool WaitingProposalAllowsMiningOf(int in_iFromPlayer,
int in_iToPlayer, eResourceType in_eResourceType)
// int WaitingProposalTariffPercentage(int in_iFromPlayer,
int in_iToPlayer, eResourceType in_eResourceType)
// int GetWaitingProposalTribute(int in_iPlayerFromID,
int in_iPlayerToID, eResourceType in_eResourceType)
// ---===And===---
// void AcceptWaitingProposal(int in_iFromPlayer, int in_iToPlayer)
// void RejectWaitingProposal(int in_iFromPlayer, int in_iToPlayer)
// These functions all work together to allow you to script whether the
// AI will accept or reject an alliance that the player is proposing.
// What you'll generally want is a structure consisting of a rule
// that checks whether a proposal is waiting from another player,
// whether it's been waiting an appropriate length of time, then fires
// an action that contains an if statement that will either
// accept or reject the proposal. The whole thing looks like this:
RULE HumanPlayerOffers
//Every second, check to see if there's a proposal waiting from 1 to 2,
//and whether it's been waiting at least 15 seconds (so we don't look
//like a robot).
if (IsAllianceProposalWaiting(1, 2) &&
GetWaitingProposalTimeElapsed(1,2) >= 15)
then CheckProposal
END_RULE
ACTION CheckProposal
SCRIPT WORLD
// Only accept an until-war (or at least 30-sec) proposal
// that has full LOS, civilian or full border permission,
// and allows tariff-free mining of gold. Also, the sum
// of all tribute offered in the proposal must be at least
// zero (which means they can't offer a proposal in which
// they take something from us).
if (
(
GetWaitingProposalDurationType(1,2)
kAllianceDuration_UntilWar ||
GetWaitingProposalDurationType(1,2)
kAllianceDuration_Timed &&
GetWaitingProposalDuration(1,2) >= 30
) &&
GetWaitingProposalLOSState(1, 2) ==
kAllianceLOSState_Full &&
(
GetWaitingProposalBorderPermission(1,2) ==
kAllianceBorderPerm_Full ||
GetWaitingProposalBorderPermission(1,2) ==
kAllianceBorderPerm_Civilian
) &&
WaitingProposalAllowsMiningOf(1, 2,
kResourceType_Gold) &&
WaitingProposalTariffPercentage(1, 2,
kResourceType_Gold) == 0 &&
GetWaitingProposalTribute(1, 2,
kResourceType_AllNaturalResource) >= 0
)
AcceptWaitingProposal(1, 2);
else
RejectWaitingProposal(1, 2);
END_SCRIPT
END_ACTION
// void TributeResource(int in_iPlayerFromID, int in_iPlayerToID,
eResourceType in_eResourceType, int in_iAmount)
// Make in_iPlayerFromID give in_iAmount of in_eResourceType to
// in_iPlayerToID in tribute.
// example usage:
//hey, watch me give 10 gold to the human player
TributeResource(2, 1, kResourceType_Gold, 10);
If you want to examine a proposal that the player has sent to an AI, and you want the AI to send a counter-proposal if it does not meet certain standards, here's what to do:
RULE HumanPlayerOffers
//Every second, check to see if there's a proposal waiting from 1 to 2,
//and whether it's been waiting at least 15 seconds (so we don't look
//like a robot).
if (IsAllianceProposalWaiting(1, 2) &&
GetWaitingProposalTimeElapsed(1,2) >= 15)
then CheckProposal
END_RULE
ACTION CheckProposal
SCRIPT WORLD
// This starts to verify the proposal. It also starts
// working on a possible counter-offer.
if(StartVerifyAllianceProposal(1,2)
// These check various propertied of the player's
// proposal:
//
&& VerifyProposalDurationNotLongerThan(
kAllianceDuration_Timed
//&& VerifyProposalLOS(kAllianceLOSState_Full
//
&& VerifyProposalBorderPermissions(
kAllianceBorderPerm_Full
//
// less
&& VerifyProposalResourceRightsNotMoreThan(15)
// Player must be willing to tribute at least 400
// gold
&& VerifyProposalTributeResource(
kResourceType_Gold, 400)
// Finish verifying the proposal. If any of the// above conditions were not met, then this command
// will return false, and it will automatically send
// a counter-proposal to the first player.
&& FinishVerifyAllianceProposal())
// If all of the above commands returned true, then the
// proposal sent by player 1 meets the requirements of
// player 2, and it's OK to accept the proposal.
END_SCRIPT
END_ACTION
Here are the detailed command descriptions:
bool StartVerifyAllianceProposal(int in_iPlayer1ID, int in_iPlayer2ID)
Starts verifying the contents of a proposal sent from player 1 to player 2. If there is no such pending proposal, it returns false. Otherwise, it returns true. This command starts the verification process, and starts to put together a possible counter-offer that player 2 may wish to send to player 1.
The following verify commands share similar properties. They all must be called after StartVerifyAllianceProposal and before FinishVerifyAllianceProposal. Each command checks an aspect of the proposal that you started to examine with StartVerifyAllianceProposal. If the proposal does not meet the parameters in one of these commands, then the command will cause for a counter-proposal to be sent when FinishVerifyAllianceProposal is called. Each command returns false if there was an operational problem. (ie: if they are called before StartVerifyAllianceProposal) Normally, each command should return true, even if the proposal does not meet the specified parameters.
bool VerifyProposalDurationNotLongerThan(
eAllianceDuration in_eDurationType, float in_fDuration)
This command checks to make sure that a proposed alliance will not last longer than a specified duration. Pass in the type of duration (kAllianceDuration_UntilWar or kAllianceDuration_Timed) and the duration in seconds. The duration in seconds is ignored for UntilWarIsDeclared. UntilWarIsDeclared alliances are considered to last longer than Timed alliances for the purposes of this command.
bool VerifyProposalDurationNotShorterThan(
eAllianceDuration in_eDurationType, float in_fDuration)
This command checks to make sure that a proposed alliance will last at least a specified duration. Pass in the type of duration (kAllianceDuration_UntilWar or kAllianceDuration_Timed) and the duration in seconds. The duration in seconds is ignored for UntilWarIsDeclared. UntilWarIsDeclared alliances are considered to last longer than Timed alliances for the purposes of this command.
bool VerifyProposalLOS(eAllianceLOSState in_eLOS)
Checks to make sure that the proposed alliance will have a particular LOS state.
bool VerifyProposalBorderPermissions(
eAllianceBorderPermissions in_eBorderPermissions)
Checks to make sure that the proposed alliance will have a particular border permission.
bool VerifyProposalResourceRightsNotMoreThan(
int in_iPercent)
Check to make sure that the resource rights are less than or equal to the specified value.
bool VerifyProposalResourceRightsNotLessThan(
int in_iPercent)
Check to make sure that the resource rights are greater than or equal to the specified value.
bool VerifyProposalTributeResource( eResourceType in_eType,
int in_iAmount)
Check to make sure that the player who proposed the alliance is tributing at least a certain amount of a specified resource.
bool VerifyProposalTributeTerritory(
const char* in_szTerritoryName)
Check to make sure that the player who proposed the alliance is tributing the specified territory. This command will generate an error if the player does not currently control the territory.
bool FinishVerifyAllianceProposal()/ ** ** ** ** * War Plans ** ** ************/
// bool IsAnyWarplanSentFromPlayerToPlayer(int in_iPlayerSendID,
int in_iPlayerReceiveID)
// returns true if sending player has sent a warplan to receiving
// player, otherwise will return false
// requirements:
the player Ids must be distinct, valid, non-world player Ids
// bugs:
1.) if a plan has been deleted, it will not cause this function
to return true
2.) if, at the time of sending a warplan, the current player
was not involved in the warplan (sender or receiver),
that warplan will not cause this function to return true
// example usage:
RULE PlanSent ONESHOT
if( IsAnyWarplanSentFromPlayerToPlayer(1, 2) ...
bool AcceptPendingPlanFromPlayer(int in_iSendingPlayer,
int in_iReceivingPlayer)
Forces the receiving player to accept a pending warplan that was sent by the sending player. If there is any pending warplan that was sent by the sending player, then the receiving player will accept it. Returns true if it accepts a warplan, and false otherwise. Note that the receiving player needs to have an AI, or the command will throw an error.
// Set up a rule so that Player 2 will accept a war plan sent by player
// 1. But only check every thirty seconds. You can do whatever you
// want when this rule fires, but the AI should already be acting on
// the warplan as soon as the command returns true.
RULE AcceptPlan ONESHOT
If(AcceptPendingPlanFromPlayer(1, 2)
)
then Whatever
END_RULE
/ ** ** ** ** * Weather ** ** ************/
// int GetCurrentMonth()
// Returns the current month in the range 1 (January) to 12 (December).
// example usage:
RULE MerryChristmas ONESHOT
if (GetCurrentMonth() == 12 ...
// int GetCurrentSeason()
// Returns the current season in the range 0-3:
0 = Summer
1 = Fall
2 = Winter
3 = Spring
// example usage:
// void SetCurrentMonth(int in_iMonth)
// Sets the current month. 1=January, 12=December.
// example usage:
//can't really wait for christmas (i like the snow)
SetCurrentMonth(12);
// void SetCurrentTimeOfDay(int in_iHour)
// Sets the current time of day. 0 = 12:00 (midnight),
// 23 = 11:00 PM. (changes lighting settings).
// example usage:
//all slanty lighting
SetCurrentTimeOfDay(19);
// void SetSecondsPerYear(float in_fSecPerYear)
// Sets the 'relative time' speed of the calendar. It will
// take in_fSecPerYear seconds for a year to elapse, so if you
// set it to 12, it will take 1 seconds for a month to pass by.
// Lower numbers make time go faster.
// example usage:
SetSecondsPerYear(1200); //default
// void PauseCalendar(bool in_bPause)
// PauseCalendar(true) causes the calendar to stop advancing.
// PauseCalendar(false) causes the calendar to start advancing again.
// example usage:
//having set up the scenario weather we don't want it
//changing until they advance to the 'summer' part of
//the script
PauseCalendar(true);
// void PauseCalendarAtMonth(int in_iWhichMonth)
// This command tells the calendar to pause when it next gets to the
// start of the specified month. The range of months is 1 (January)
// to 12 (December). If you are in the middle of month 5, for example,
// and you call PauseCalendarAtMonth(5), it will pause the NEXT time
// you get to the start of month 5.
// We've started some rain in a temperate map, and we want
// the calendar to stop before it gets to the snowy season
// and starts changing the terrain texture to be snow. So
// tell the calendar to pause once we get to September.
PauseCalendarAtMonth(9);
// void PauseWeatherSystem(bool in_bPause)
// Pause and unpause the automatic weather system. This is independent
// of the calendar. Pausing the automatic weather system stops the
// game engine from generating new weather events and changing the
// weather. You must pause the automatic system before changing the
// weather state with script calls. Passing true for in_bPause
// pauses the system, and passing false unpauses the system.
// When you unpause the system, the game will automatically revert
// to the state it had before you paused it.
// See ChangeToWeather for an example
// void ChangeToWeather(enum eWeatherState in_whichWeather,
float in_fTransitionTime)
// Change to the specified weather state. eWeatherState is an
// enumeration of the different possible weather conditions. (See
// enums below.) These conditions include normal, light rain, heavy
// rain, light snow, heavy snow, light dust and heavy dust. When this
// command is called, it causes the game to change to the specified
// state. This can change lighting, the skybox, the fog and
// atmospheric particle effects. It may also have gameplay effects,
// like limiting line of sight and damaging units. Certain elements
// can take time to transition to the new state, light lighting and
// fog. These will gradually change over the number of seconds
// specified by in_fTransitionTime. I recommend about 2-3 seconds.
// Please feel free to bug Matt Corthell for assistance with this.
// NOTE: Make sure you call PauseWeatherSystem before changing the
// weather state.
// In this example, we decide to start a rain storm. We will
// transition to the storm over two seconds.
PauseWeatherSystem(true);
ChangeToWeather(kWeatherState_RainHv, 2);
// void StartLightningBolt()
// Starts an ambient lightning flash and thunderbolt. This is
// pretty straightforward. It fires a single bolt when you want it to.
// void StartLightningBoltAtLocation(float in_fX, float in_fY)
// Starts a lightning bolt that will strike the ground at the specified
// x,y location.
StartLightningBoltAtLocation(5, 10);
// void StartLightningBoltHitUnit(const char* in_szTargetUnitName,
float in_fDamageAmount)
// Starts a lightning bolt that will strike the specified unit, and
// deal the specified damage to the unit.
// Don't golf in the rain.
StartLightningBoltHitUnit("TigerWoods", 100);
// Changes to the specified skybox. This causes the current skybox to
// fade to the specified skybox over the specified period of seconds.
// The weather system should be paused before using this command.
// ( PauseWeatherSystem(true) )
// Skyboxes are defined in db\terrain\climate.ddf.
void ChangeToSkybox(const char* in_szSkyboxName,
float in_fTransitionTime);
// int RandomIntBetween(int in_iLow, int in_iHigh)
// Get a random integer number between in_iLow and in_iHigh, inclusive.
// i.e.: RandomIntBetween(3,5) will give you either 3, 4, or 5.
// example usage:
//Send one of the AIs randomly after the player.
SetDiplomaticState(RandomIntBetween(2, 4), 1,
kDiplomaticState_Hostile);
// float RandomFloatBetween(float in_fLow, float in_fHigh)
// Get a random floating-point number between in_fLow and in_fHigh,
// inclusive. i.e.: RandomFloatBetween(3,5) can give you 3, 3.2, 4.96,
// or 5.
//Wait between 9 and 15 seconds to respond to the invasion..
DoDelay(RandomFloatBetween(9, 15));
STEP
...
// bool IsMissionTimerExpired(int in_iTimerID)
// See "Mission Timers" section.
// float GetDistanceFromUnitToPoint(const char *in_szUnitName,
float in_fX, float in_fY)
// Get the distance between a unit and a point.
// example usage:
//trigger when he gets near the southwest corner of the map
if ((GetDistanceFromUnitToPoint("JamesBond", 0, 0) < 3) ...
// float GetDistanceFromUnitToUnit(const char *in_szUnit1Name,
const char *in_szUnit2Name)
// Get the distance between two named units.
// example usage:
if ((GetDistanceFromUnitToUnit("GuyA", "GuyB") < 2) ...
// float GetMinDistanceFromUnitToGroup(const char *in_szUnitName,
const char *in_szGroupName)
// Get the distance between a unit and the _closest_ member of a group.
// example usage:
//trigger as soon as JB is close enough for ANY of the
//scouts to spot him.
if ((GetMinDistanceFromUnitToGroup("JamesBond", "Scouts") < 5) ...
// float GetMaxDistanceFromUnitToGroup(const char *in_szUnitName,
const char *in_szGroupName)
// Get the distance between a unit and the _furthest_ member of a
// group.
// example usage:
//trigger once ALL the scouts are close enough
//to be affected by the sleeping gas in the cufflink
//or whatever
if ((GetMaxDistanceFromUnitToGroup("JamesBond", "Scouts") < 5) ...
// bool DoesWallCoverGap(int in_iPlayerID, const char* in_szAreaA,
const char* in_szAreaB, int in_iMaxUnits)
// Given two areas, this function will check to see if the specified
// player has a continuous wall that exists in both areas. By making
// two very small areas, you can use this to check if a player has
// built a wall to span from one point to another. (The center points
// of the two areas.)
// in_iMaxUnits is a limiter that restricts the size of the wall. A
// player could construct a wall that technically connects the two
// areas, but it could be long and windy. If you give in_iMaxUnits a
// positive value, then it will reject all walls that are longer than
// the specified value. Note that the number is the count of units,
// not tiles. You may need to experiment to find the appropriate value
// for each case. If you don't care about the length of the wall, set
// in_iMaxUnits to -1, and the function will return true for any
// wall, regardless of length.
// NOTE: This could be a kind of expensive command. I'd recommend
// doing this no more frequently than once per second. If you can do
// it less than that, it's probably better.
// Example:
// See if the player has constructed a (mostly) straight wall
// between two points.
If(DoesWallCoverGap(1, "WallEndA", "WallEndB", -1)). . .
// bool DoesRoadCoverGap(int in_iPlayerID, const char* in_szAreaA,
const char* in_szAreaB, int in_iMaxUnits)
// This works just like the wall function above, but checks for road
// connectivity instead.
// NOTE: This might not work for bridges. Yell at me (Matt) if you
// need this to work for bridges.
// bool DoesRoadConnectTerritories(int in_iPlayerID,
const char* in_szTerritoryA, const char* in_szTerritoryB,
int in_iMaxUnits)
// Test to see if there is a road belonging to a player that connects
// Territory A to Territory B. If there is, the function will return
// true, otherwise false. You can specify a maximum number of units
// that are allowed in the chain if you want the road to be near to a
// straight line. Please test any values that you use for this,
// however. Specify -1 for the max units if the road can be any length.
// NOTE: Be aware that, for this function in particular, the length
of the road might or might not include sections of the road
inside the territories. So, for example, if Territory A has 100
connected road units, and there are ten other road units that
connect it to Territory B, the length of the road when a positive
connection to Territory B is found could be 110, or it could be
11.
Also, if there are two separate roads that connect the two
territories, there is no guarantee that you'll get one over the
other.
// Example:
// As soon as
//
// the road is.
RULE ONESHOT
If(DoesRoadConnectTerritories(1, "
Then SendDutchTrader
END_RULE
// bool DoesUnitExist(const char *in_szUnitName)
If object exists
// If in_szUnitName does not exist (was never named) or is dead, this
// will return false. Otherwise it returns true.
// example usage:
RULE ONESHOT
if (!DoesUnitExist("JamesBond")
then JBHasBeenAssassinated
END_RULE
// eUnitGoalType GetUnitGoalType(const char *in_szUnitName)
If object has state: attacking/moving/harvesting
// example usage:
RULE ONESHOT
if ((GetUnitGoalType("JoeBob") != kGoalType_GatherResource)
then GetBackToWork
END_RULE
// float GetUnitHealth(const char *in_szUnitName)
If object's health = %x
// example usage:
RULE ONESHOT
if ((GetUnitHealth("JamesBond") < 0.50)
then SendInReinforcements
END_RULE
// int GetPlayerResource(int in_iPlayerID, eResourceType in_eResType)
// Get the amount of resource of the specified type. This returns
// the CURRENT amount of resources that the player has. If you want
// to know how much resources the player has collected in total, see
// GetAmountOfResourcesCollected().
// example usage:
RULE ONESHOT
if ((GetPlayerResource(1, kResourceType_Food) < 25)
then OfferFoodForPeace
END_RULE
// int GetAmountOfGoldFromTrade(int in_iPlayerID)
// Determine how much gold the specified player has earned through
// trade. It counts gold earned when your trade carts visit your
// markets and also from when other players' trade carts visit your
// markets.
RULE ONESHOT
if ((GetAmountOfGoldFromTrade (1) > 100)
then YouAreATradingMagnate
END_RULE
// float GetPlayerCrownScore(int in_iPlayerID,
eCrownType in_eCrownType)
// Get a player's current score for a particular crown.
// float GetPlayerCrownThreshold(int in_iPlayerID,
eCrownType in_eCrownType)
// Get the threshold score a player needs to achieve
// to win the crown
RULE ONESHOT
If(GetPlayerCrownScore(1, kCrownType_Economic) /
GetPlayerCrownThreshold(1, kCrownType_Economic) > 0.5)
Then TellPlayerOneHesHalfwayToTheEconomicCrown
END_RULE
// void AdjustPlayerCrownScore(int in_iPlayerID,
eCrownType in_eCrownType, float in_fAdjustment)
// Add or subtract a number to the players score for a particular
// crown.
// Give the player 100 more points in the economic crown
void AdjustPlayerCrownScore(1, kCrownType_Economic, 100);
// int PlayerWhoHasCrown(eCrownType in_eCrownType)
// returns the ID of the player who has the crown in_eCrownType. If
// nobody has the crown yet, returns -1.
// example usage:
RULE ONESHOT
if (PlayerWhoHasCrown(kCrownType_Military) == 1)
then WooHooWeAreNumberOne
END_RULE
// bool HasPlayerEarnedCrown(int in_iPlayerID,
eCrownType in_eCrownType)
// Returns true if the specified player has ever owned the specified
// crown.
RULE ONESHOT
if (HasPlayerEarnedCrown (1, kCrownType_Military))
then IAmAStrategistGod
END_RULE
void SetAllowLeaderForCrown(int in_iPlayerID, eCrownType in_eCrownType,
bool m_bMayBuild)
Set whether a particular player may be awarded a leader when he wins a particular type of crown. This does not remove or affect existing leader units. This does not prevent the script from creating leaders.
Example:
// Put this in the initialization portion of your script
// if you want to prevent the player from getting any leaders
// when a crown is won over the course of a scenario.
SetAllowLeaderForCrown(1, kCrownType_Military, false);
SetAllowLeaderForCrown(1, kCrownType_Imperial, false);
SetAllowLeaderForCrown(1, kCrownType_Economic, false);
// int GetAmountOfTribute(int in_iPlayerFromID, int in_iPlayerToID,
eResourceType in_eResourceType)
// Get amount of resource type in_eResourceType that in_iPlayerFromID
// has tributed to player in_iPlayerToID. Asking for
// kResourceType_AllNaturalResource gets the total amount of all
// resources tributed.
// example usage:
RULE PayUp
if (GetAmountOfTribute(2, 1, kResourceType_Gold) >= 200)
then ThatsAboutRightSeeYouNextWeekPunk
END_RULE
// int GetOwningPlayerID(const char *in_szUnitName)
If player owns object(s)
// Get the ID of the player that owns unit in_szUnitName. If
// in_szUnitName does not exist or is dead, this will return -1.
// example usage:
RULE ONESHOT
if (((GetOwningPlayerID("Rocky") == GetOwningPlayerID("Bullwinkle"))
then TogetherAtLast
END_RULE
// bool IsGroupOwnedBy(const char *in_szGroupName, int in_iPlayerID)
// Returns true if and only if in_szGroupName exists, is non-empty,
// and everyone in it is owned by in_iPlayerID. If it hasn't been
// created or if it's empty, it'll return false.
// example usage:
if (IsGroupOwnedBy("Escapees", 1) ...
// int GetGroupOwnerID(const char *in_szGroupName)
// If EVERY unit in in_szGroupName is owned by a single player, will
// return that player's ID. If in_szGroupName is empty or has mixed
// ownership, will return -1.
// example usage:
RULE PlayerConquers ONESHOT
if ( (GetGroupOwnerID("BuildingsToCapture") == 1))
then YouCapturedAllTheBuildingsFromThatGroupThatAreStillAlive
END_RULE
// float GetElapsedGameTime()
If time elapsed = x
// example usage:
RULE ONESHOT
if ((GetElapsedGameTime() > 30 * 60))
then InformPlayerAboutTheDangersOfEyeStrain
END_RULE
// bool PlayerInGame(int in_iPlayerID)
If player is alive/dead A player is "dead" if he has no more
important units. Important units include units that can attack,
build, or produce, and specifically exclude ammo and construction
sites.
This is supposed to allow designers to approximate Conquest
victories through scripting.
// example usage:
RULE ONESHOT
if (!PlayerInGame(3))
then MournTheLossOfOurBelovedPlayer3
END_RULE
// bool PlayerHasResearchedTech(int in_iPlayerID,
const char *in_szTechName)
// Check whether a player has researched a specific technology or not.
// Returns true after the player has FINISHED researching the tech.
// example usage:
RULE ONESHOT
//NB: Main1_1 is fire
if (PlayerHasResearchedTech(1, "Main1_1")
then InvitePlayer1OverForABarbecue
END_RULE
// int GetPlayerEpoch(int in_iPlayerID)
// Check what epoch a player is currently in.
// example usage:
RULE ONESHOT
if ((GetPlayerEpoch(1) > GetPlayerEpoch(2)
then SuckUpToPlayer1
END_RULE
bool DoesPlayerHaveEnoughTechsToAdvance(int in_iPlayerID)
Returns true if the specified player has researched enough techs in the current epoch to allow advancement to the next epoch. Returns false otherwise.
Example:
// In the tutorial, after telling the player to research a few
// techs, give him a new goal to advance to the next epoch, or
// something.
RULE ONESHOT
if(DoesPlayerHaveEnoughTechsToAdvance(1))
then GiveGoalToAdvance
END_RULE
// int NumUnitsInGroup(const char *in_szGroupName)
// Returns the number of units in the group named in_szGroupName.
// Useful for, say, periodically building up a group of enemy units in
// some area, then checking to see if that group is empty or not.
// NOTE: This number will include dead units that are still "rotting".
// Use NumUnitsInGroupNotDead to ensure that you only get live units.
// example usage:
RULE ONESHOT
if (NumUnitsInGroup("DudesOnMyLawn") > 0)
then CallTheCops
END_RULE
// int NumUnitsInGroupNotDead(const char* in_szGroupName)
// Returns the number of units in the group that are not dead.
// Units that are in a group that are dead and rotting are normally
// included in the count of that group. That is not the case when
// using this function, however.
RULE ONESHOT
if (NumUnitsInGroup("MyEnemies") == 0)
then ICanStopFighting
END_RULE
// int GetNumPlayers()
// Get the number of players in the game.
// example usage:
RULE ONESHOT
if ((GetNumPlayers() == 2))
then SwitchToSeriouslyAgressiveAIP
END_RULE
// bool IsPlayerAttackingInArea( int in_iAttackerID,
int in_iTargetID,
const char* in_szArea)
// in_iAttackerID is the ID of a player. (The attacker.)
// in_iTargetID is the ID of a player. (The target.)
// in_szArea is the name of an area. (The area.)
// The function checks to see if the attacker has any units that are
// attacking units that belong to the target, where both the attacking
// unit and target unit are in the area. If this condition is true,
// then the function returns true. If the attacking unit is in the
// area, and the target unit is not in the area, then the function
// returns false. Similarly, if the defender is in the area, and the
// attacker is not, the function returns true.
// The function does not care if any units belonging to the target
// are attacking units belonging to the attacker. The function only
// checks aggression in one direction.
// The function takes into account conversions and captures in
// progress.
// If the human player starts to attack player 2 near Bob's home,
// then the computer wants to produce a lot of defenders.
RULE ONESHOT
if (IsPlayerAttackingInArea(1, 2, "BobsHome")
then ProduceLotsOfDefendingUnits
END_RULE
// int GetLandTradeRoutesBetweenPlayers(int in_iPlayerA, int
in_iPlayerB)
// int GetSeaTradeRoutesBetweenPlayers(int in_iPlayerA, int
in_iPlayerB)
// int GetAllTradeRoutesBetweenPlayers(int in_iPlayerA, int
in_iPlayerB)
// These functions count and return the number of active trade routes
// that Player A has with Player B. For the purposes of this function,
// a trade route is defined as a trading unit (trade card, merchant
// ship, etc.) that belongs to Player A, and is currently engaged in
// trading with a building belonging to Player B. Units belonging to
// Player B do not count toward this number, even if they are trading
// with Player A.
// This does not count past trade routes. So if Player A had 5 trade
// carts that were trading, and they all get killed, then he has no
// active routes.
// The variations on the functions restrict the search to land or sea
// trade routes, or allow for a general search that includes all trade
// routes.
// If the player establishes ten trade routes, then give him a
// bonus.
RULE ONESHOT
if (GetLandTradeRoutesBetweenPlayers(1, 2) >= 10
then GivePlayer1LotsOfMoney
END_RULE
// int GetAllTradeRoutesForPlayer(int in_iPlayer)
// Count the total number of active trade routes that the specified
// player currently has. A trade route is a single trade unit (trade
// cart, merchant ship, etc.) that is actively trading with another
// player.
// If the player establishes a hundred total trade routes, then
// they must have a frickin' monopoly. Sue them.
RULE ONESHOT
if (GetAllTradeRoutesForPlayer (1) >= 100
then BringAnAntiTrustSuit
END_RULE
// bool HavePlayersTradedRecently(int in_iPlayerA,
int in_iPlayerB,
float in_fTimePeriod)
// Checks to see if Player A has traded with Player B within the
// specified time period. Returns true if a trade unit from A
// has visited and completed a trade transaction with a building
// belonging to B within the given time.
// This rule can be used to watch for when the human player
// first completes a trade with AI player 2. iEverySecond
// is a cPeriodicInt set to evaluate every second. This
// rule will evaluate every second, and check to see if
// Player 1 has traded with Player 2 within the past second.
RULE ONESHOT
if (HavePlayersTradedRecently (1, 2, 1)
then RewardPlayer
END_RULE
// Is this player weaker than every other player in the game -
requiredRatio specifies how many times weaker
this player needs to be, to be considered weakest
bool IsWeakestPlayer(int in_iPlayer, float in_fRequiredRatio);
// is this player stronger than every other player in the game -
requiredRatio specifies how many times stronger
this player needs to be, to be considered strongest
bool IsStrongestPlayer(int in_iPlayer, float in_fRequiredRatio);
// does this player have less resources than everyone else -
requiredRatio specifies how many times less
this player needs have, to be considered having the least
bool HasLeastResources(int in_iPlayer, float in_fRequiredRatio);
// These next 2 are for switching aips in skirmish games// we're in a late epoch game, is our enemy using tons of planes?
bool EnemiesArePlaneHappy(int in_iPlayer)
// has our enemy stopped with the planes?
bool EnemiesHaveForsakenPlanes(int in_iPlayer)
// Get the population count for the specified player. This is not
// necessarily the number of units that the player has, as some units
// may count as two or more in the population, and others might not
// count at all. This should be the number that is displayed in
// the UI, however.
int GetPlayerPopulation(int in_iPlayer);
// float GetPercentOfMapExploredByPlayer(int in_iPlayerID)
// Get the percent of map explored by the specified player. Returns// the percent as a floating value between 0 and 1. 0.0 = 0%,
// 0.5 = 50%, 1.0 = 100%, etc.
// example:
See how much the player has explored. If the player has
// been adventurous and seen half the map, reward her.
RULE ONESHOT
if (GetPercentOfMapExploredByPlayer >= 0.5
then RewardPlayer
END_RULE
bool IsPlayerHumanControlled(int in_iPlayerID)
Test to see if the specified player is human-controlled. Returns true if she is. Note that observer players are not human controlled, and will return false if this command is called on them.
void SetRollCreditsAfterScenario(bool in_bRollCredits)
Set whether or not the game should jump to the EE2 credits after the player has finished viewing the end-game statistics.
If number of player's units killed = x
// example usage:
// int GetNumDeadUnits(int in_iFromPlayerID)
// int GetNumDeadUnitsOfType(int in_iFromPlayerID,
const char *in_szUnitTypeName)
// int GetNumDeadUnitsByAttribute(int in_iFromPlayerID,
const char *in_szAttributeName)
If number of player's units of a specific type killed = x
// example usage:
// This will fire when 15 units of any type from player 1 have died.
if ((GetNumDeadUnits(1) >= 15) ...
// This will fire when 4 male citizens from player 3 have died.
if ((GetNumDeadUnitsOfType(3, ("CitizenM")) >= 4) ...
// This will fire when 15 units with building ability from player
// 2 have died.
if ((GetNumDeadUnitsByAttribute(2, ("Builders")) >= 15) ...
// int GetNumConvertedAwayUnitsOfType(int in_iFromPlayerID,
const char *in_szUnitTypeName)
// int GetNumConvertedAwayUnitsByAttribute(int in_iFromPlayerID,
const char *in_szAttributeName)
// Gets the number of units of a type/attribute that in_iToPlayerID has
// lost to conversion.
// example usage:
// This will fire as soon as player 3 loses a mobile unit.
if ((GetNumConvertedAwayUnitsByAttribute(3, "MobileUnits") > 0)
...
// This will fire as soon as player 1 loses a female citizen.
if ((GetNumConvertedAwayUnitsOfType(1, "CitizenF") > 0) ...
// int GetNumConvertedUnitsOfType(int in_iToPlayerID,
const char *in_szUnitTypeName)
// int GetNumConvertedUnitsByAttribute(int in_iToPlayerID,
const char *in_szAttributeName)
// Gets the number of units of a type/attribute that in_iToPlayerID has
// converted, from all sources.
// example usage:
// This will fire as soon as player 3 converts a mobile unit.
if ((GetNumConvertedUnitsByAttribute(3, "MobileUnits") > 0)
...
// This will fire as soon as player 1 converts a female citizen.
if ((GetNumConvertedUnitsOfType(1, "CitizenF") > 0) ...
// int GetNumConvertedUnitsFromPlayerOfType(int in_iFromPlayerID,
int in_iToPlayerID, const char *in_szUnitTypeName)
// int GetNumConvertedUnitsFromPlayerByAttribute(int in_iFromPlayerID,
int in_iToPlayerID, const char *in_szAttributeName)
// example usage:
// This will fire as soon as player 3 converts one of player 1's mobile
// units.
if ((GetNumConvertedUnitsFromPlayerByAttribute(1, 3, "MobileUnits")
> 0) ...
// This will fire as soon as player 1 converts one of player 2's
// female citizens.
if ((GetNumConvertedUnitsFromPlayerOfType(2, 1, "CitizenF") > 0) ...
// int GetNumKilledUnitsOfType(int in_iToPlayerID,
const char *in_szUnitTypeName)
// int GetNumKilledUnitsByAttribute(int in_iToPlayerID,
const char *in_szAttributeName)
// int GetNumKilledUnitsFromPlayerOfType(int in_iFromPlayerID,
int in_iKillingPlayerID, const char *in_szUnitTypeName)
// int GetNumKilledUnitsFromPlayerByAttribute(int in_iFromPlayerID,
int in_iKillingPlayerID, const char *in_szAttributeName)
// example usage:
// This will fire when player 1 kills a female citizen for the first
// time.
if ((GetNumKilledUnitsOfType(1, "CitizenF") > 0) ...
// This will fire when player 1 kills a mobile unit for the first
// time.
if ((GetNumKilledUnitsByAttribute(1, "MobileUnits") > 0) ...
// This will fire as soon as player 3 sinks 2 of player 1's fishing
// ships.
if ((GetNumKilledUnitsFromPlayerOfType(1, 3, "FishingShip") >= 2) ...
// This will fire when player 2 kills 8 units with land RPS from
// player 4.
if ((GetNumKilledUnitsFromPlayerByAttribute(4, 2, "LandRPS")
>= 8) ...
// int GetNumProducedUnitsOfType(int in_iPlayerID,
const char *in_szUnitTypeName)
// int GetNumProducedUnitsByAttribute(int in_iPlayerID,
const char *in_szAttributeName)
// example usage:
// This will fire as soon as player 3 builds his first Temple.
if ((GetNumProducedUnitsOfType(3, "Temple") > 0) ...
// This will fire as soon as player 1 produces 20 naval units
// (units with either NavalDeep or NavalShallow movement types).
if ((GetNumProducedUnitsByAttribute(1, "Naval") >= 20) ...
// int GetAmountOfResourcesCollected(int in_iPlayerID,
eResourceType in_eType)
// Get the total amount of resource of the specified type
// that in_iPlayerID has collected over the course of the game.
// Note that this does NOT count resources given to the player
// by the script AddPlayerResource command, and it also does not
// count starting resources.
// example usage:
// As soon as Player 1 has collected 350 wood, complain about
// deforestation or something
if ((GetAmountOfResourcesCollected(1, kResourceType_Wood) >= 350) ...
// int GetNumCitizensGatheringResource(int in_iPlayerID,
eResourceType in_eType)
// Find out how many citizens belonging to the specified player are
// harvesting a particular resource
// Give the player some bonus for being such a basass
// lumber gatherer.
RULE
If(GetNumCitizensGatheringResource(1, kResourceTypeWood) > 50)
Then GivePlayerLumberjackCrown
END_RULE
//Play any sound file called by name. This function loads and unloads //the file upon start and completion. Should only be used for sounds
//used a few times, like a voice over. Returns a sound handle so the
//sound can be stopped pre-maturely.
Int PlayVoiceOver("American1_VO.wav");
// Plays the sound named in_szSoundSampleName in the audio DB, and returns a handle to it in case you want to stop it later.
int StartPlayingSound(const char *in_szSoundSampleName
// Stops a sounds previously started reference via file handle.
Void StopSound(int in_handle);
// Stops all sounds that were started within the script
void StopAllScriptSounds();
//Play a voice over, or any one time use sound accessed by real
//filename. This sound is loaded when this function is called
// and unloaded when it finishes. If you will be using a given
//sound multiple times, you should make a audio DB entry.
//Function returns the sound handle of the sound, which can be used
//to stop the sound. These sounds can also be stopped with stop all
//script sounds
int PlayVoiceOver(const char *in_filename);
//Same as PlayVoiceOver, but makes the sound loop indefinitely.
//You definitely want to save the sound handle for this one so you can
//stop it. These sounds can also be stopped with stop all script
//sounds
int PlayLoopingVoiceOver(const char *in_filename);
//Begins fading out the sound. The fade will last the given length of
//time. After the fade is complete the sound is stopped
void FadeOutSound(int in_handle, float in_length);
// bool IsSoundPlaying(int in_iNonce) = 0;
// Check and see if the sound indicated by the specified nonce is
// currently playing. (The nonce is the number that gets returned
// by script commands like PlayVoiceOver.)
//Turns on and off the streaming background music so voice overs and
// other sounds can be heard. True to turn on, false for off.
void ToggleStreamingMusic(bool in_enable);
THINGS YOU MIGHT WANT TO DO, AND HOW TO DO THEM:
* Set up a trigger that fires only once, right when the game starts
You'd have a rule like this:
RULE ONESHOT
if (true)
then <whatever>
END_RULE
* Increment counter(x), If counter(x) equals (y)
Counters are represented by cHotInts, in the scripting system. You create a counter named <name> by putting the following in your DEFINITIONS section:
cHotInt <name>
Then, you can set the counter in the INITIALIZATION section like so:
<name> = 0;
You can initialize it to any number you want. Then, you can perform mathematical operations on it inside ACTION sections. To increment it, you would do:
<name> = <name> + 1;
To decrement it:
<name> = <name> - 1;
You can copy the values of other counter variables as well:
<name> = <othername>;
Then, when you want to make a rule that depends on the value of a counter, it will look like this:
// Example: fire Bonk when counter Foo reaches 23
RULE
if (23 == Foo)
then Bonk
END_RULE
Note the TWO equals signs! = means assignment, == means test for equality.
* If player's unit count (specific unit type or total) = x
* If player(x) has total unit count of (x)
You do this, and most things of this form (unit counts of a type) by using Groups. In this case, you want to make up a group, put all the units of the type you're interested in into that group, and then test the group's size.
To fire a rule when a player 1's unit count of all types is EXACTLY x:
RULE ONESHOT
if (CreateNamedGroup("UCount") &&
AddUnitsByAttributeToGroup("UCount", "Anything", 1,
kPlayerMode_Self, NULL) &&
NumUnitsInGroup("Ucount") == x //doing == for EXACTLY x
)
then Whatever
END_RULE
In the above example, the "UCount" name is something I just made up for this rule. The only thing that matters is that it's not going to collide with something else. You could, if you wanted to, do something in the ACTION section that this rule fires, like SelectGroup("UCount") and then AttackWithSelection(), but for this example we're just counting the units.
"Anything" is the name of the attribute that we're using to select units to add to the group. The full set of named attributes is in $/run/db/dbunittypeattribute.uta. I could have chosen MobileUnits, or Citizens, to limit it to the count of units that matched those attributes.
The 1 is the player that we're talking about, and kPlayerMode_Self means that we're only considering units that belong to that player. These are the different player modes you can use:
kPlayerMode_Anybody, //all players (including the world player)
kPlayerMode_Self, //only units that belong to me.
kPlayerMode_Allies, //only units that belong to my allies
kPlayerMode_SelfAndAllies, //units that belong to me OR my allies
kPlayerMode_Enemies, //units that belong to my declared enemies
kPlayerMode_NonSelf, //enemies and allies, just not me
kPlayerMode_World, //the world player only (resources, animals)
kPlayerMode_NotTheWorld, //anybody who is not the world player
(For future reference, they're located in $/src/EE2/DbHdrs/DbUnitTypeAttributeDefs.h.)
* If quantity(x) units from player(x) enters trigger area(y)
* If player(x) has type of unit(y) in trigger area(z)
This is very much the same as the above, but theA ddUnitsByAttributeToGroup call needs an additional parameter, the name of the area. If you named an area "NearMyBase", and you wanted to trigger as soon as AT LEAST five citizens from player 2 were near your base:
RULE ONESHOT
if (CreateNamedGroup("Trespassers") &&
AddUnitsByAttributeToGroup("Trespassers", "Citizens", 2,
kPlayerMode_Self, "NearMyBase") &&
NumUnitsInGroup("Ucount") >= 5 //doing >= for AT LEAST five
)
then Whatever
END_RULE
To show off player modes, maybe you don't care about which specific player they're from, as long as they're enemies of player 1. Then you'd do this:
...
AddUnitsByAttributeToGroup("Trespassers", "Citizens", 1,
kPlayerMode_Enemies, "NearMyBase") &&
...
* An alternate way to see if named unit enters trigger area(x)
First, create a group, then add your named unit to it. Then, REMOVE all the units in the group that are in the trigger area. Then, if the group is empty, you know that the guy's in the area you're looking for. Make sense?
Here's an example:
RULE ONESHOT
if (CreateNamedGroup("JustJames") &&
AddUnitToGroup("JustJames", "JamesBond") &&
RemoveUnitsByAttributeFromGroup("JustJames", "Anything", 0,
kPlayerMode_Anyone, "NearMyBase") &&
NumUnitsInGroup("JustJames") == 0
)
then JamesBondIsNearMyBase
END_RULE
* If player(x) has killed count(y) units owned by player(z)
This case is handled by:
RULE ONESHOT
if (GetNumKilledUnitsFromPlayerByAttribute(z, x, "Anything") >= y
)
then HoorayForUs
END_RULE
* If player(x) destroys quantity(y) of unit type(z) owned by player(z1)
But note that you can be more selective by changing "Anything" to the name of another UnitTypeAttribute, such as MobileUnits (if you don't want to count building destruction):
RULE ONESHOT
if (GetNumKilledUnitsFromPlayerOfType(z1, x, "z") >= y
)
then WeAreTotallyTheBest
END_RULE
Also note that we do ">= y" rather than "== y", which would trigger when the killed count was exactly y. The reason why we do this is because in the super-rare occurrence that player x kills multiple units at the same time (or, maybe in the nuclear epoch, not so super-rare occurence), the kill count might jump past y without ever equalling it exactly. Therefore it's a lot more pragmatic to test with a > or a < in there somewhere.
* Find the name of a particular unit type for AddUnitsByTypeToGroup
There is no authoritative/centralized list of types, but if you search
for 'UnitType' at the start of the line in $/run/db/Units/*.ddf,
you'll find them. A handy way to do this in VC++ is:
1. go to "Find in Files" under the "Edit" menu
2. Make sure 'Regular Expression' is checked and 'Look in subfolders'
is _not_ checked
3. type '^UnitType' (make sure the ^ is there) into 'Find what:'
4. type '*.ddf' into 'In files/file types:'
5. type C:\EE2\run\db\Units into 'In folder:' (or wherever your
run/db/units directory is
6. hit enter
Of course, without VC++ this can be a little tricky, but the Unit Type names are actually quite easy to figure out. You can usually just use a unit's RPS class name (Frigate, Bomber, HeavyInfantry, LightInfantry, etc.) as it's type. Buildings are always their base type (barracks, workshops - even if its in an epoch with factories, warehouse, etc.) Note that some RPS families have some extra members. If you want Macemen through Objective Force Warriors, it's HeavyInfantry1. If you want Spearmen through Mini-Gunners, it's HeavyInfantry2. Heavy and Light Mounted2 are Helicopters and Heavy and Light Mounted3 are HERCs. Tanks are LightTank and HeavyTank. Finally, LightArtillery2 is the mobile AA unit.
* Use certain 'area' commands relative to the locations of units/groups
So, say you want to move the selection to a named unit called 'TargetUnit'. Instead of placing an area down in the editor where you think TargetUnit is going to be and giving a move order to that area, you can do:
MoveSelectionToArea("Unit:TargetUnit");
Likewise, if there's a group named TargetGroup that you want to move towards the middle of, do this:
MoveSelectionToArea("Group:TargetGroup");
The script interface sees the Unit: and Group: prefixes and does the right thing. This syntax works for the commands:
Create[Named,Grouped]UnitInArea (maybe good for group)
MoveSelectionToArea[WithAttack]
InstantMoveSelectionToArea
AttackAreaWithSelection
SetCameraLookArea
* Make a unit invincible
Do this:
AttachEffectToUnit("<unitname>", "Invincibility");
There used to be a SetUnitInvincible call, but it didn't work, and since this -does- work, it's much more preferable.
* Clean up after a cinematic before the objectives panel pops up
If you want to have some cleanup functions called before the initial cinematic ends, you can put them in a special ACTION called "PreScenInfoPanelHook". This ACTION section should only have one step, and can't use any delay functions (like DoDelay, or DoWaitUntilCinematicTime), since it all takes place at once. It should look like this:
ACTION PreScenInfoPanelHook
SCRIPT WORLD
SelectGroup("UnitsUsedOnlyForCinematic");
RemoveGroup();
END_SCRIPT
END_ACTION
This will be called immediately after the cinematic ends, but before the objectives panel comes up, so you can do it to remove things you don't want visible during that time.
* All text must use localized strings
A localized string is simply a call to a text database where your text lives. Having all text in an outside database makes it easier to troubleshoot and translate, should the mood strike you. All text that you wish to display in your scenario, either through messages you display through your script or custom display names you set in the editor, must be in the form of a string that can be found and edited in an external file in the text database.
To add an entry to the text db, you need to download and use an editing program like BabelPadT and make sure you save the file with the prefix "usertext" as in usertext_myscenario.utf8. Next, make a folder called "db" in your "EE2\Run" directory and drop the .utf8 file in a "Text" folder within the "db" folder. Next, start making up strings:
usertext_myscenario_beginning,"""In the beginning."""
usertext_myscenario_cornchips,"""there were plenty of corn chips."""
etc.
Make sure you end the file with a hard return, or else you'll likely get some kind of error.
Then, in your script, anytime you want to show some text, you call a the appropriate string:
PrintMessage("usertext_myscenario_beginning");
Or.
CreateDialogBox("usertext_myscenario_beginning", true);
Or you can create a custom display name in the editor by opening up the object properties panel and entering a string:
Display Name: usertext_unitname_BobTheMighty
Now that we've gotten past the simple example, I'm going to give you a
very complex one. This is for strings that have formatting commands in
them, when you want to print a message where the content depends on
values that aren't known until runtime. In this situation, we want to
print a message that depends on the name of a player, an amount
(ostensibly extracted from an alliance proposal), the name of a
particular enum (in this case, a resource), and another
designer-specified string that lives elsewhere in the text DB. We can
do this with a text DB entry that has argument strings in it.
Argument strings are basically small chunks of a message that you want
to substitute something else in for. They're represented by single
words, preferably in all caps, surrounded by % signs. (If you want to
use a % sign by itself in your string, use '\%', and if you want to
use a \ sign by itself, use '\\'.) The following example has four
formatting strings in it, each of which is replaced by a different
piece of data.
// in $/run/db/Text/dbtext_scenario_tutorial1.csv:
usertext_scenario_tutorial1_14 "%PLAYER% has offered you %AMOUNT% %RESOURCE% in exchange for
%AREA%!"
usertext_scenario_tutorial1_15 "Lawrence"
usertext_scenario_tutorial1_16 "North Andover"
// in your script:
StartFormat("usertext_scenario_tutorial1_14");
FormatPlayerName("PLAYER", 2);
FormatInt("AMOUNT", 100);
FormatEnum("RESOURCE", "eResourceType", kResourceType_Gold);
FormatString("AREA", "usertext_scenario_tutorial1_15");
PrintFormattedMessage();
In the end, it will come out looking like:
"King George has offered you 100 Gold in exchange for Lawrence!"
This assumes that player 2's name is King George, but you get the point.
* Create and update a status string
You can make persistent strings that remain on screen. The intent is so that players will have information about their progress toward a particular goal. An example of a good use would be if a player needed to capture three territories, you can display a string on screen that says something like "Captured 0 of 3 territories." When the player captured another territory, you can update it again to say 1 of 3, and so forth. Use of these strings builds upon localized strings as described above. You'll need to know how to do that in order to format these status strings.
I'll describe an example based on the capturing territories idea. First, you need to make sure you have a localized string defined in one of the .utf8 files. This is the only thing that needs to be done outside of the script. This is, of course, a template. And you will be able to, in script, replace the %CAPTUREDNUM% and %CAPTUREDREQ% portions of the string with data in the script.
text_G3_objectiveCapture_status,
"""Captured %CAPTUREDNUM% of %CAPTUREDREQ% territories"""
In the script, for each status string you need an integer which is used to hold an identifier for the string. The integer can be declared in the DEFINITIONS portion of the script, like so.
int statusObjectiveCapture
You need to create a new status string. This can be done in the INITIALIZATION portion of the script.
int statusObjectiveCapture = NewMissionStatusString();
The following section is the action in which the objective is given to the player. The script that I'm including will build the formatted string and put it into our status string. Afterward, we'll make another call to show the string. The command to show the string will make sure the string is automatically displayed on the screen.
ACTION GivePlayerCaptureObjective
SCRIPT_WORLD
// Include other script to enable the objective
. . .
//
// Start formatting the status string.
StartFormat("text_G3_objectiveCapture_status");
// Add the number of captured territories. I'm assuming
// you define this integer elsewhere, and that you are
// updating it. Note that the value of the integer RIGHT
// NOW is the value that gets inserted into the string.
// If the value of the integer changes later, the string
// will NOT be automatically updated.
FormatInt("CAPTUREDNUM", numTerritoriesCaptured);
// Add one more int for the number of required territoried
FormatInt("CAPTUREDREQ", numTerritoriedRequired);
// Finally, we 'print' the text specified in the
// StartFormat command into the status string that we
// created with NewMissionStatusString during
// initialization, including the variables we added with
// the format calls. Note that this does not cause the
// string to be displayed on string.
PrintFormattedMissionStatusString(statusObjectiveCapture);
// Now that we have initially formatted the string, we can
// show it to the user.
ShowMissionStatusString(statusObjectiveCapture, true);
END_SCRIPT
END_ACTION
Here's another action that gets called whenever the player captures a new territory. This action updates the string to reflect the progress of the player. Note that we can format and print a string without having to show the string again, because we already showed the string when the previous action ran.
ACTION UpdateCaptureObjective
SCRIPT_WORLD
// Include other script to do whatever
. . .
//
// Start formatting the status string.
StartFormat("text_G3_objectiveCapture_status");
// Again, the number of captured territories and
// and required territories are added. We assume that
// numTerritoriesCaptured has been updated already.
FormatInt("CAPTUREDNUM", numTerritoriesCaptured);
FormatInt("CAPTUREDREQ", numTerritoriedRequired);
// And print once again. This will update and change the
// displayed string, assuming that the string is already
// shown.
PrintFormattedMissionStatusString(statusObjectiveCapture);
END_SCRIPT
END_ACTION
And, finally, you should hide the string once it's no longer relevant to the player. When he's completed the objective, for example.
ShowMissionStatusString(statusObjectiveCapture, false);
GOOD PRACTICES TO FOLLOW:
* Use constants instead of strings in place
This is a good practice to follow to reduce the occurence of 'typo errors' (e.g., accidentally mistyping the name of a unit, group, or area). Instead of referring to areas/groups/units by name strings, make a constant out of that name string, and use that instead:
// old way:
RULE IsHirohitoDead ONESHOT
if (!DoesUnitExist("Hirohito")
then OhManHeDied
END_RULE
// new, slightly annoying way:
DEFINITIONS
constant HIROHITO "Hirohito"
END_DEFINITIONS
RULE IsHirohitoDead ONESHOT
if (!DoesUnitExist(HIROHITO)
then OhManHeDied
END_RULE
This has one major benefit: if you misspell the name of a constant,
you will get a compile error, instead of it mysteriously not working during testing.
// old way, no error (though you will get a message about
// Hirohito dying earlier than you would expect):
RULE IsHirohitoDead ONESHOT
if (!DoesUnitExist("Hirhito")
then OhManHeDied
END_RULE
// new way, now with compile-time error:
DEFINITIONS
constant HIROHITO "Hirohito"
END_DEFINITIONS
RULE IsHirohitoDead ONESHOT
if (!DoesUnitExist(HIOHITO)
then OhManHeDied
END_RULE
Of course, you are obligated to spell the name correctly in the DEFINITIONS section, but if you're using the same constant everywhere, it will be more likely to show up earlier if you misspell it there.
ENUM LISTS:
Some arguments to script commands are 'enums', which are enumerated values. They have very long descriptive names and are usually used to select one of a set of possibilities. You can tell an enum argument to a script command by the fact that its type starts with an 'e' (like ePlayerMode). Here are the list of possible enums that script interface calls take, and their possible values:
// the basic move type each terrain type can be classified into
ENUM eResourceType ;
// Player mode enumeration - each UnitTypeAttribute has a player mode,
// which is used to determine whether units are contained in the set
// described by a UnitTypeAttribute depending on their ownership. For
// a unit, its mode will be kPlayerMode_Self, which is the default for
// all UnitTypeAttributes.
ENUM ePlayerMode ;
//These are the four crown types.
ENUM eCrownType ;
// determine how out of range time is handled by an animator
enum EVisualLoopType
enum eDiplomaticState
enum eAllianceDuration
enum eAllianceLOSState
enum eAllianceBorderPerm
enum eAllianceResRight
enum eStanceType ;
// Enumeration of the different weather states. Normal is the default.
ENUM eWeatherState ;
// This is an enumeration of the different area effect types. Many
// special unit powers directly correspond to an effect type. You can // use this enum to see if a player has used a particular unit power.
// The enum shown here is not comprehensive. There are many more
// effect types. If you're looking for one and you don't see it here, // it most likely exists and is ready to use, but it might
// require a little bit of programming support first.
ENUM eEffectType ;
|