From f540dfd8af287bc1412aff00cb130bf67f8a3e0d Mon Sep 17 00:00:00 2001 From: askeladdk Date: Sun, 3 Feb 2019 14:29:36 +0100 Subject: [PATCH] Updated to version 2.0.3.9 with the fixes made by E1 Elite (thanks). --- AI.htm | 3090 ---------------------------------------- AssemblyInfo.cs | 2 +- README.md | 36 + ScriptType.cs | 112 +- TaskForce.cs | 69 +- TeamType.cs | 20 +- TriggerType.cs | 238 ++-- UseInfoBox.Designer.cs | 4 +- config/default.ini | 18 +- config/ra2.ini | 20 +- config/ts.ini | 31 +- config/yr.ini | 26 +- frmMainNew.Designer.cs | 43 +- frmMainNew.cs | 1939 ++++++++++++------------- frmMainNewFunctions.cs | 100 +- help/aiguide.html | 1532 ++++++++++++++++++++ 16 files changed, 2977 insertions(+), 4303 deletions(-) delete mode 100644 AI.htm create mode 100644 help/aiguide.html diff --git a/AI.htm b/AI.htm deleted file mode 100644 index 9ee55f7..0000000 --- a/AI.htm +++ /dev/null @@ -1,3090 +0,0 @@ - - - - - -Red Alert 2 AI - - - - - - - -
- -

Red Alert 2 AI.INI Guide

- -

 

- -

Sections Covered

- -

·                     -[TaskForces]

- -

·                     -[ScriptTypes]

- -

·                     -A Note On -Structure Numbers

- -

·                     -[TeamTypes]

- -

·                     -[AITriggerTypes]

- -

·                     -A Note On AI -Pool Teams

- -

·                     -Some Tips On -Making A Better AI

- -

 

- -

This file -controls the Artificial Intelligence -employed by the game engine when it assumes the role of a computer controlled -player. Red Alert 2 utilizes 'scripted' AI (that is, a system based on -pre-determined actions and scripts rather than a 'heuristic' system, i.e. one -which intelligently responds to player actions and attempts to forecast future -player actions by recording a log of previous ones in a bid to nullify them -thus giving itself a tactical advantage).

- -

 

- -

An attempt has -been made to give the impression of heuristics in Red Alert 2 by implementing a -success/failure delta system, where the computer keeps a record of instances -where previous scripts were or were not successfully executed to completion, -thus influencing the likelihood of them being used again. See the AI Trigger -Weighting Parameters section in the RULES.INI Guide for details of -these deltas.

- -

 

- -

TIP: to get more out of the AI and to make -more effective use of the changes you make to this file, I recommend referring -to the [AIGenerals] section (see the RULES.INI Guide). -That section provides an ideal way to define specific overall playing styles -and strategies for the AI - use of that technique will ensure that the AI -relies less on simply playing the game in the same continual scripted manner -regardless of the state of the battle and how its doing.

- -

 

- -

AI.INI is perhaps -the least modified file but one which provides immense scope for mod writers as -it allows customization through the game engine 'scripting' language in a -similar manner to map files. The file contains the scripts which make the -computer controlled armies function, and these are in addition to any -supplementary scripts that may be contained within specific map files. -Production and replacement of units, their generic behavioural characteristics -as well as the specific missions that those units will go on are all controlled -through this file.

- -

 

- -

In simple terms, -the scripted system works like this;-

- -

 

- -

·                     -The computer uses -objects, or groups of objects, known as TaskForces...

- -

·                     -...whose generic -behaviour and unique properties are controlled by allocating them to TeamTypes...

- -

·                     -...to carry out an -action, or series of actions, controlled by ScriptTypes...

- -

·                     -...which may or may -not be triggered by predefined game events known as AITriggerTypes.

- -

 

- -

It should be -noted that the AI.INI file provides great scope for modification in Red Alert -2. This is for several reasons - if you take a look through the file, it -becomes clear that the computer is instructed to prioritize only certain types -of attacks, only to use certain units (some are not used), and heavily favors -ground based attacks (naval units are seldom used). Primarily however, the -computer initially relied upon heavy ground assaults to overwhelm enemies -because of the fact that its only enemies were humans, thus would not attack -other computer controlled armies before the 1.004 patch. Despite that change -however, the AI.INI file remained unmodified, and is less than half the size of -than the Tiberian Sun one. NOTE: There is -so much of the game engine unused within this file, that time spent on it will -be well worthwhile - the Red Alert 2 engine is very powerful and versatile. A -lot of this logic is residual from Red Alert and also from the enhancements -made by Tiberian Sun - this is one reason why some features do not entirely -work correctly in the Red Alert 2 engine.

- -

 

- -

To say that the -AI in Red Alert 2 is poor is very wrong - as you will see, it is merely -incredibly under utilized. You will be amazed at what is possible with a -little time and effort. Note that to unleash the full potential of the AI, it -is well worth studying the AI specific statements in RULES.INI too which offer -a high degree of control of the generic AI behaviours - see the RULES.INI -Guide. Editing the AI.INI file is not for the faint hearted, and I would -suggest that you need a good command of the other INI files (particularly -RULES.INI and map files) before embarking upon this!

- -

 

- -

NOTE: the use of '-G'as a suffix to the numbers throughout this file indicates that this is a -'global' value, meaning it will be used throughout the game regardless -of any other conditions placed upon its use. In this case, duplicate use of the -same number for the same purpose (for example on two different ScriptTypes or TaskForces) either in this file or within a map file will lead -to an Internal Error. This means that you can call any of the TeamTypes, TaskForces or ScriptTypes defined in the AI.INI file from a map file without -having to define it again in that map file. This is handy if you want to use -something that has already been defined in the AI.INI file, thus reducing the -size of your map file.

- -

 

- -

[TaskForces]

- -

 

- -

This section -takes the form of a list of all TaskForces to -be used by the computer generically across all games. The list is numbered -starting at 0, new ones should be simply added to the end of the list. If you want -the computer to make use of new units, or to use more units, then this section -is the one to modify. Each entry in the list takes the form of a hexadecimal -numbered string which is the unique identifier for each of the TaskForces - like other lists in the INI files, the game code -requires that each entry in this list is defined with its own section in this -file. For convention, it is wise to stick to this hex numbering system, -although any string appears to be parsed.

- -

 

- -

An example is -detailed below;-

- -

 

- -

[TASKFORCE]

- -

Name=

- -

a=x,UNIT

- -

b=x,UNIT

- -

c=x,UNIT

- -

...

- -

Group=

- -

 

- -

[TASKFORCE] - this is the unique identifier name used -to define the section for this TaskForce and should also be contained in the above -mentioned list.

- -

 

- -

Name= - this is simply a string name used for identification -purposes only, it is not required by the game, although it is useful to leave -this in for debugging and troubleshooting your AI.INI file - as a point of -interest, this statement does not even get parsed.

- -

 

- -

n=x,UNIT - this is used to define which units are -in this TaskForce. This is in the form of a list, and for -each different unit you want in your TaskForce, you -must have a separate line in the list. Each line consists of a number (how many -of the unit) followed by a comma and then the name of that unit from the [BuildingTypes],[InfantryTypes],[VehicleTypes] or [AircraftTypes]lists from RULES.INI. Note that the numbering must -start at 0. For example, to define a TaskForce with -5 GI's and 2 Grizzly Tanks, you could use;-

- -

 

- -

[TASKFORCE]

- -

Name=5 -GI's and 2 Grizzly Tanks

- -

0=5,E1

- -

1=2,MTNK

- -

Group=-1

- -

 

- -

Group= - defines the default grouping for -the units in this TaskForce which is therefore used when it has -executed (or does not have) a ScriptType. This is over-ridden by the Group= setting in the associated TeamType. The following values can be used;-

- -

 

- -

-1                     Lose -Transports - any transports are dissolved

- -

??                     Lose -Units, Lose Transports - all units dissolved

- -

??                     Keep -Units, Keep Transports - all units retained

- -

??                     Lose -Units, Keep Transports - only transports retained

- -

??                     Keep -Units Farthest - only units furthest away are retained

- -

??                     Keep -Units Nearest - only nearest units are retained

- -

??                     Greatest -Threat - group together at object posing greatest threat

- -

-40094              Least -Threat - group together at object posing least threat

- -

 

- -

[ScriptTypes]

- -

 

- -

This section -takes the form of a list of all ScriptTypes -which can be used by TaskForces. The list is numbered starting at 0, new -ones should be simply added to the end of the list. Each entry in the list -takes the form of a hexadecimal numbered string which is the unique identifier -for each of the ScriptTypes - like other lists in the INI files, the -game code requires that each entry in this list is defined with its own section -in this file. For convention, it is wise to stick to this hex numbering system -although again this is not strictly necessary. The section entries describe -what the TaskForce is going to do and consists of a list of -action codes.

- -

 

- -

An example is -detailed below;-

- -

 

- -

[SCRIPT]

- -

Name=

- -

a=x,y

- -

b=x,y

- -

c=x,y

- -

...

- -

 

- -

[SCRIPT] - this is the unique identifier name used -to define the section for this ScriptType and should also be contained in the above -list.

- -

 

- -

Name= - this is simply a string name used for -identification purposes only, it is not required by the game, although it is useful -to leave this in for debugging and troubleshooting your AI.INI file - as a -point of interest, this statement does not even get parsed.

- -

 

- -

n=x,y - this defines the action to be performed -by the TaskForce to which this ScriptType is allocated. This takes the form of a list, and for -each action you want the TaskForce to perform, you should have a new line in -your script. Think of this like writing a computer program - for everything you -want the computer to do, you add a new line to your program - its the same idea -here. Again, by convention, the numbering must begin at 0. These scripts -can become very complex and powerful tools, and provide one of the ultimate -levels of editing potential in the game.

- -

 

- -

The first value, x, contains the action to perform. Some actions -require a parameter, y, which provides information for the -action - they mean different things for different actions. Here's an example of -a script, the first line tells the computer to attack any enemy vehicles, and -the second line tells the computer to attack anything when its finished the -first line (i.e. after it has destroyed one vehicle);-

- -

 

- -

[SCRIPT]

- -

Name=Attack -any vehicle then attack anything

- -

0=0,5

- -

1=0,1

- -

 

- -

Here's a list of -the script actions and their respective parameters (where appropriate);-

- -

 

- -

0,n -= Attack Target Type, n = target type to attack

- -

This instructs -the TeamType to use the TaskForce to approach and attack the target specified by the -second parameter. The following are the target types which can be used;-

- -

 

- -

 0         N/A                   cancel -attack mission

- -

 1         Anything           anything -(usually the first enemy object they encounter) - utilizes threat rating logic

- -

 2         Structures         any -enemy [BuildingTypes]

- -

 3         Ore -Miners        any enemy [VehicleTypes] with Harvester=yes set

- -

 4         Infantry              any -enemy [InfantryTypes]

- -

 5         Vehicles            any -enemy [VehicleTypes]

- -

 6         Factories           any -enemy [BuildingTypes] with a Factory= setting

- -

 7         Base -Defenses  any enemy [BuildingTypes] with IsBaseDefense=yes set

- -

 8         Base -Threats     any enemy objects approaching (or already in) its base and which -are in an attack mission

- -

 9         Power -Plants     any enemy [BuildingTypes] with positive Power= values set

- -

10         Occupiable        any -[BuildingTypes] with CanBeOccupied=yes set (usually neutral structures)

- -

11         Tech -Buildings   any [BuildingTypes] with NeedsEngineer=yes set (usually NeutralTechBuildings=)

- -

 

- -

NOTE: in Yuri's Revenge, Occupiable structures -are defined by having CanOccupyFire=yes set instead of CanBeOccupied=yes.

- -

 

- -

1,n -= Attack Waypoint, n = waypoint number to attack

- -

This instructs -the TeamType to use the TaskForce to attack the waypoint number specified by the -second parameter. If any members have Infiltrate=yes -set they will enter the structure at the waypoint. Members with Engineer=yes set will capture the structure provided -it does not have Capturable=no set or if it has NeedsEngineer=yes set. Members with Agent=yes set will spy on the structure if it has Spyable=yes set. Members that do not have Assaulter=no set will garrison the structure if it has -CanBeOccupied=yes set. Members with C4=yes set will blow up the structure if does not have CanC4=no set. If there is no building at the specified -waypoint, the TaskForce will move to the waypoint and will just -remain in their last mission. Waypoints are used to define specific places -(cells) on the map - see the Map Editing Guide for a detailed -explanation of waypoints. At this point however, its worth noting that Red -Alert 2 usually assigns waypoint number 98 to define the place where the player -starts in single player games (also known as the 'home cell'), waypoint number -99 for the center of the map, and waypoint numbers 0 - 7 to define the starting -places for the 8 players.

- -

 

- -

2,0 -= Go Berzerk

- -

Forces infantry -units with Cyborg=yes -set to go berserk (they -consider all objects, including friendly units, equally in their threat scan).

- -

 

- -

3,n -= Move To Waypoint, n = waypoint number to move to

- -

This instructs -the TeamType to use the TaskForce to move to the waypoint number specified by the -second parameter. Waypoints are used to define specific places (cells) on the -map - see the Map Editing Guide for a detailed explanation of waypoints. -At this point however, its worth noting that Red Alert 2 usually assigns -waypoint number 98 to define the place where the player starts in single player -games (also known as the 'home cell'), waypoint number 99 for the center of the -map, and waypoint numbers 0 - 7 to define the starting places for the 8 -players. TIP: you could use this script -action to get a TeamType to move to Waypoint= number 99 (just about every map has this defined as -the center point) - that will mean it will always strive to get to the center -of the map, providing a good vantage point from which to perform further script -actions and giving the impression that the computer is scouting for enemies.

- -

 

- -

4,n -= Move Into Specific Celltag, n = celltag to move into

- -

This instructs -the TeamType to use the TaskForce to move into the CellTag specified by the second parameter. This is used when -you want the TeamType to trigger a specific Action (when the game tests for the CellTag being entered). CellTags are attached to cells and are used to trigger Events and thus fire Actions when that cell is entered by a unit (or any unit -from the TaskForce). The CellTag parameter should be the waypoint parameter for that CellTag from the [CellTags]listing -in the map file, hence this script action is only of use on specific map files. -See the Map Editing Guide for a detailed explanation of CellTags and their use.

- -

 

- -

5,n -= Guard Area, n = time to guard area in tenths of a minute (multiples of 6 -seconds)

- -

This instructs -the TeamType to put the TaskForce into Guard Mode (same effect as selecting a group of -units and pressing the Guard Mode key as defined in KEYBOARD.INI or clicking -the relevant button on the Advanced Command Bar). Units will move to attack -enemy units that fall within their Sight= range.

- -

 

- -

6,n -= Jump To Script Action, n = number of script action to jump to

- -

This is used to -repeat actions within the ScriptType. The second parameter is the action -number of the ScriptType that you want to jump to. Remember that -the first action of a ScriptType is numbered 0 so if you jump to this (by -using n=6,0 for example) you get the TaskForce to repeat all the commands it has, looping forever. -This is used by the waypoint system in the game for setting up patrols. You -don't have to repeat all the actions as you could jump to say action 3, which -would ignore the first three action commands (remember, the numbering starts at -0) and just go to the fourth.

- -

 

- -

7,0 -= Force Player Win

- -

Forces a game win -condition for the owner of the TeamType (they -win the game).

- -

 

- -

8,n -= Unload, n = type of unloading

- -

If the TaskForce contains a unit or units that have a valid Passengers= value set, and those units contain -passengers, this command will make the units inside the transport(s) disembark. -Note that once the passengers have disembarked, the transport itself is -suspended until given a new mission and is therefore no longer considered a -part of this TaskForce - this means that you cannot, for -example, get units to disembark, do something, then get back into the transport -in the same script. The second parameter can be used to control what happens to -the transport after it 'deploys' its cargo;-

- -

 

- -

0          Keep -transports and units - all remain in the team and execute the remainder of the -script

- -

1          Keep -transport and lose the units - only the transport will execute the remainder of -the script

- -

2          Lose -transport and keep units - only the units will execute the remainder of the -script

- -

3          Lose -transports and lose units - nothing executes the remainder of the script

- -

 

- -

9,0 -= Deploy

- -

If the TaskForce contains a unit or units that are able to deploy -(for example a unit which DeploysInto= a [BuildingType] or has any of Deployer=yes, DeployFire=yes, DeployToFire=yes set) then this action causes them to deploy at the -current cell they are occupying (same effect as selecting a unit and pressing -the Deploy key as defined in KEYBOARD.INI or clicking the relevant button on -the Advanced Command Bar).

- -

 

- -

10,0 -= Follow friendlies

- -

This command -causes the TaskForce to follow the nearest friendly unit when -it moves although it will not function as if it is 'guarding' the unit. The -following is not permanent, when the TaskForce is -assigned another mission it abandons the following. TIP: -If the support TeamType has this as the first line in its ScriptType, then it will escort the first TeamType.

- -

 

- -

11,n -= Assign New Mission, n = new mission type

- -

The objects in -the TaskForce are all assigned the new mission defined -by the second parameter. Not all of them work, some are made obsolete by other -action commands, some do not work because an object in the TaskForce may not support that action. Because these are the -same 'behaviours' to which objects can be assigned when initially placed on the -map some apply only to structures. The following are valid settings for the -second parameter, you should refer to the Mission Control section of the -RULES.INI Guide for a more detailed explanation of the missions and how -they work;-

- -

 

- -

 0         Sleep                    -object sits around and plays dead, will not acquire targets

- -

 1         Attack                   -special attack mission used by AI team types (utilizes threat rating logic)

- -

 2         Move                     -simply moving to destination

- -

 3         QMove                  -special move to destination after other queued moves occur

- -

 4         Retreat                  -object runs away (may even leave the map)

- -

 5         Guard                   -object sits around and will engage an enemy that falls within its weapon range

- -

 6         Sticky                   -just like guard mode, except the object will engage enemies but not pursue them

- -

 7         Enter                    -enter building or transport

- -

 8         Capture                 -engineer entry logic used by MultiEngineer

- -

 9         Eaten                    -when object is being repaired (applies only to structures)

- -

10         Harvest                 -the loop controlling harvesting of Ore and dumping at a Refinery

- -

11         Area -Guard            guard the general area where the object starts at

- -

12         Return                   -return to co-ordinating object (e.g. spawned object returns to the spawner)

- -

13         Stop                     -stop moving or firing at the first available opportunity

- -

14         Ambush                -force fire (units with Infiltrate=yes will enter target if possible)

- -

15         Hunt                     -scan for and attack enemies wherever they may be on the map

- -

16         Unload                  -while dropping off cargo (e.g. Landing Craft unloading passengers)

- -

17         Sabotage              -unit runs to place C4 on a building or Ivan goes to place bomb on object

- -

18         Construction          -structures use this when building up after initial placement

- -

19         Selling                  -structures use this for deconstruction after being sold

- -

20         Repair                   -used when repairing an object (e.g. Service Depot)

- -

21         Rescue                 -special team over-ride mission

- -

22         Missile                  -Nuke Silo special launch missile mission

- -

23         Harmless              -object doesn't fire and is not considered in any threat scan

- -

24         Open                    -while opening or closing a gate to allow passage

- -

25         Patrol                    -patrol a series of waypoints

- -

26         Paradrop -Approachobject is approaching the paradrop site

- -

27         Paradrop -Overfly                object is flying over the paradrop site (i.e. dropping -the paratroopers)

- -

28         Wait                     -paused and awaiting next mission

- -

29         Move                     -(special duplicate) used when Chrono units are moving to destination

- -

30         Attack                   -(special duplicate) used when units are deployed to fire (e.g. weapons with an -area fire effect)

- -

31         Spyplane -Approachobject is flying towards target (YR)

- -

32         Spyplane -Overfly    object is flying over the target (YR)

- -

 

- -

NOTE: there is a difference when using Area -Guard as opposed to Guard. Units with an Area Guard mission are more aggressive -and will pursue enemy units that fall within their Sight= range and continue that pursuit until they can -attack the target. Then the units will return to their original position unless -they catch the target within their initial guard zone (in which case they will -attempt to destroy it). Units in an Area Guard mission are not recruited 'from -the field' when a create team Action is executed, although units in a standard -Guard mission will be gathered to create the new team if they are required.

- -

 

- -

12,n -= Set Global, n = global number to be set

- -

The global number -specified in the second parameter is defined as being 'set' (it is allocated a -value of '1' or 'true'). This should be employed in specific map files only. -This is part of the boolean logic employed by the global variables system in -the game engine - refer to the Map Editing Guide for a more detailed -explanation of global and local variables. The Global Variables are defined in -RULES.INI - see the RULES.INI Guide.

- -

 

- -

13,n -= Play Idle Anim Sequence, n = sequence number

- -

If the TaskForce contains a unit or units that are SHPs (i.e. -infantry) then the relevant idle SHP sequence is displayed as defined by the -frame numbering system in ART.INI.

- -

 

- -

14,0 -= Load Onto Transport

- -

If the TaskForce contains a unit or units that have a valid Passengers= value set, and units whose Size= and PhysicalSize= settings allow them to be carried by that -transport, this command will make the units enter the transport.

- -

 

- -

15,n -= Spy On Structure At Waypoint, n = waypoint number

- -

Should be used -only for units with Infiltrate=yes and Agent=yes set. This instructs the TaskForce to enter the structure at the waypoint number -specified by the second parameter and spy on the structure if it has Spyable=yes set. If there is no building at the -specified waypoint, the TaskForce may not activate correctly and will just -remain in their last mission. Waypoints are used to define specific places -(cells) on the map - see the Map Editing Guide for a detailed -explanation of waypoints. At this point however, its worth noting that Red -Alert 2 usually assigns waypoint number 98 to define the place where the player -starts in single player games (also known as the 'home cell'), waypoint number -99 for the center of the map, and waypoint numbers 0 - 7 to define the starting -places for the 8 players.

- -

 

- -

16,n -= Patrol to waypoint, n = waypoint number

- -

This is similar -to Move to waypoint. This instructs the TeamType to use the TaskForce to -move to the waypoint number specified by the second parameter. The difference -is that the units in the TaskForce will move out of their patrol route to -actively go and engage any enemy objects that are within their Sight= as they move to the waypoint. NOTE: this action eats up processor time, because -the TaskForce will scan for enemy objects with each -movement. If you have a lot of TaskForces (or lots of units in them) engaged in -this action, you will experience slowdown in the game - this is one reason why -the single player missions are comparatively slow, they use this action a lot. -The rate at which the scanning for targets whilst in this mission is controlled -by the PatrolScan= statement in the [AI]section of RULES.INI (see the RULES.INI Guide). Waypoints are -used to define specific places (cells) on the map - see the Map Editing -Guide for a detailed explanation of waypoints. At this point however, its -worth noting that Red Alert 2 usually assigns waypoint number 98 to define the -place where the player starts in single player games (also known as the 'home -cell'), waypoint number 99 for the center of the map, and waypoint numbers 0 - -7 to define the starting places for the 8 players.

- -

 

- -

17,n -= Change Script, n = script number to execute

- -

Very -handy and under utilized - this instructs the TaskForce to execute another ScriptType. The second parameter -specifies the number of the ScriptType to execute as listed in the [ScriptTypes]table (consider the table as -being numbered starting at 0 for this purpose).

- -

 

- -

18,n -= Change Team, n = team number to join

- -

This -instructs the TaskForce to join another TeamType. The second parameter -specifies the number of the TeamType to join as listed in the [TeamTypes]table (consider the table as -being numbered starting at 0 for this purpose).

- -

 

- -

19,0 -= Panic

- -

If the TaskForce contains a unit or units that have Fraidycat=yes set then they will run around aimlessly, -using the Panic= animation from their sequence as defined -in ART.INI. Normally used for the civilian units. Units that do not fulfil this -criteria lie down and act as if prone.

- -

 

- -

20,n -= Change House Ownership, n = house number of new owner

- -

Used in single -player missions on specific map files only, this changes ownership of the -entire TeamType to the House= number specified by the second parameter. See the Map -Editing Guide for details of [Houses] and -their numbering.

- -

 

- -

21,0 -= Scatter

- -

This instructs -the TaskForce to scatter (same effect as selecting a -group of units and pressing the Scatter key as defined in KEYBOARD.INI).

- -

 

- -

22,0 -= Afraid & Run To Shroud

- -

This instructs -the TaskForce to behave in a scared manner and it will -run to the nearest shrouded cell. The TaskForce will -not actively engage in combat, will not acquire targets and will not retaliate -(it will scatter instead if attacked).

- -

 

- -

23,0 -= Force Player Loss

- -

Forces a game -loss condition for the owner of the TeamType (they lose the game).

- -

 

- -

24,n -= Play Speech From EVA.INI, n = number of speech to play

- -

This -instructs the TaskForce to play one of the Sofia or -EVA voices (depending upon the ParentCountry= or the owner of this TaskForce). The second parameter is the number of the sound to be played -from the [DialogList] in the EVA.INI file (note -that you should consider this list as being numbered from 0 instead of 1 to get -the correct numbering convention).

- -

 

- -

25,n -= Play Sound From SOUND.INI, n = number of sound to play

- -

This -instructs the TaskForce to play one of the generic in -game sounds from the [SoundList] in the SOUND.INI file (note -that for all in game Action -and Trigger purposes this number is from -an internal table - see the Map Editing Guide).

- -

 

- -

26,n -= Play Movie

- -

This -instructs the TaskForce to play one of the movies -from the [Movies] list in the ART.INI file -(note that for all in game Action -and Trigger purposes this number is from -an internal table - see the Map Editing Guide).

- -

 

- -

27,n -= Play Theme From THEME.INI, n = number of theme to play

- -

This -instructs the TaskForce to play one of the game -soundtracks from the [Themes] list in the THEME.INI file -(note that for all in game Action -and Trigger purposes this number is from -an internal table - see the Map Editing Guide).

- -

 

- -

28,0 -= Reduce Ore

- -

Reduces -the amount of Ore in the cell that the TeamType is occupying. Used by the special -'weapon' that is inherent with Ore Miners.

- -

 

- -

29,0 -= Begin Production

- -

Forces -the owner of the TeamType to begin the auto-production process (the AI's behaviour in -skirmish games). Should only be used on AI controlled houses.

- -

 

- -

30,0 -= Force Sale

- -

Forces -the 'fire sale' of all remaining structures owned by the House= to which the TeamType belongs.

- -

 

- -

31,0 -= Suicide

- -

This -instructs the TaskForce to destroy itself. In effect -it commits suicide, usually accompanied by an explosion.

- -

 

- -

32,n -= Start Weather Storm In...

- -

This -initiates the Weather Storm intro effect (when the screen goes dark prior to the clouds -appearing) and is set to be delayed by the number of seconds specified by -parameter 2.

- -

 

- -

33,0 -= End Weather Storm

- -

This forces an -end to the Weather Storm intro effect (when the screen goes dark prior to the -clouds appearing).

- -

 

- -

34,n -= Center Map On Team

- -

This will center -the screen on the TeamType. The same effect as hitting the Home key -as defined in KEYBOARD.INI when the screen centers on your MCV (or the unit -defined by the BaseUnit= statement in RULES.INI). The second -parameter determines the speed at which the 'camera' switches view to the TaskForce with 0 being instant.

- -

 

- -

35,n -= Shroud Map For Time Interval, n = time to remain shrouded

- -

This action will -shroud the entire map except for the area around the players MCV's (if they -have one). The second parameter determines the number of frames for which the -map should remain shrouded (1 second = approximately 15 frames) after which the -explored areas are revealed again.

- -

 

- -

36,n -= Reveal Map For Time Interval, n = time to remain revealed

- -

This action will -reveal the entire map. The second parameter determines the number of frames for -which the map should remain revealed (1 second = approximately 15 frames) after -which the map is shrouded again.

- -

 

- -

37,0 -= Delete Team Members

- -

This forces -dissolved members of the TaskForce to leave the map after which they are -deleted (for example aerial transports after their passengers have -disembarked).

- -

 

- -

38,n -= Clear Global, n = Global number to be cleared

- -

The global number -specified in the second parameter is defined as being 'clear' (it is allocated -a value of '0' or 'false'). This should be employed in specific map files only -in which the global variable has been defined. This is part of the boolean -logic employed by the global variables system in the game engine - refer to the -Map Editing Guide for a more detailed explanation of global and local -variables. The Global Variables are defined in RULES.INI - see the RULES.INI -Guide.

- -

 

- -

39,n -= Set Local, n = Local number to be set

- -

The local variable -number specified in the second parameter is defined as being 'set' (it is -allocated a value of '1' or 'true'). This should be employed in specific map -files only in which the local variable has been defined. This is part of the -boolean logic employed by the local variables system in the game engine - refer -to the Map Editing Guide for a more detailed explanation of local and -global variables.

- -

 

- -

40,n -= Clear Local, n = Local number to be cleared

- -

The local -variable number specified in the second parameter is defined as being 'cleared' -(it is allocated a value of '0' or 'false'). This should be employed in -specific map files only in which the local variable has been defined. This is -part of the boolean logic employed by the local variables system in the game -engine - refer to the Map Editing Guide for a more detailed explanation -of local and global variables.

- -

 

- -

41,n -= Unpanic

- -

If the TaskForce contains a unit or units that have Fraidycat=yes set which are currently assigned the Panic= mission then this action nullifies that effect and -the unit(s) adopt their default behaviour.

- -

 

- -

42,n -= Change Facing, n = new direction to face

- -

This instructs -the TaskForce to turn and face the new direction -specified by the second parameter. The facings are as follows;-

- -

 

- -

0          North

- -

1          North -East

- -

2          East

- -

3          South -East

- -

4          South

- -

5          South -West

- -

6          West

- -

7          North West

- -

 

- -

43,0 -= Wait Until Fully Loaded

- -

This is always -used after members of the TaskForce have entered a transport in the same -TaskForce and serves two purposes. The effect of -this is that the transport will be used to carry out any subsequent movement or -deploy actions but after that it is no longer considered a part of this TaskForce and as such is available to be recruited into new TeamTypes. It is this action which enables use of the TransportsReturnOnUnload=yes statement in the corresponding TeamType entry. The second purpose is to flag the transport -as being 'loaded' with passengers and thus is considered in the AI's targeting -logic as a potential threat (see the ContentScan= -entry in the RULES.INI Guide). This action also orders the transport to -wait until it is fully loaded before executing any subsequent script actions.

- -

 

- -

44,0 -= Unload TRUCKB > TRUCKA

- -

Used purely for a -graphical effect and applicable uniquely to the [TRUCKB] unit, this has the effect of converting [TRUCKB] into [TRUCKA] to -give the impression that the unit has unloaded its cargo. NOTE: this is residual from Tiberian Sun and as -such may not work correctly since [TRUCKA] -refers to the Demo Truck image in Red Alert 2 which has no 'unloaded' image. -Changing the image for the Demo Truck and assigning new units to [TRUCKA] and [TRUCKB] enables use of this logic.

- -

 

- -

45,0 -= Load TRUCKA > TRUCKB

- -

Used purely for a -graphical effect and applicable uniquely to the [TRUCKA] unit, this has the effect of converting [TRUCKA] into  [TRUCKB]to -give the impression that the unit has been loaded with cargo. NOTE: this is residual from Tiberian Sun and as -such may not work correctly since [TRUCKA] -refers to the Demo Truck image in Red Alert 2 which has no 'unloaded' image. -Changing the image for the Demo Truck and assigning new units to [TRUCKA] and [TRUCKB] enables use of this logic.

- -

 

- -

46,n -= Attack Enemy Structure, n = structure number (see note below)

- -

Members of this TaskForce attack the enemy structure specified by the second -parameter. This action depends upon the type of units in the TaskForce and if certain members have Infiltrate=yes set. Members with Engineer=yes set will capture the structure provided it does not -have Capturable=no set or if it has NeedsEngineer=yes set. Members with Agent=yes set will spy on the structure if it has Spyable=yes set. Members that do not have Assaulter=no set will garrison the structure if it has -CanBeOccupied=yes set. Members with C4=yes set will blow up the structure if does not have CanC4=no set.

- -

 

- -

47,n -= Move To Enemy Structure, n = structure number (see note below)

- -

Members of this TaskForce move and stay adjacent to the enemy structure -specified by the second parameter.

- -

 

- -

48,0 -= Scout

- -

Causes members of -this TaskForce to move to a pre-determined point on the -map in an attempt to scout an area. The effect is that the TaskForce will move in one randomly chosen direction until it -is no longer able to do so which can make it very useful or a waste of time -depending on the direction chosen. If you want to continually scout the map, -you should loop this script action.

- -

 

- -

49,0 -= Repeat Until Success

- -

This is typically -used after an Attack Target instruction. This forces the TaskForce to carry out its previous action in the script -continually until all of the target types specified by that previous -instruction no longer exist, at which point the TaskForce moves on to the next instruction after this one. The -action is continually executed until any condition on its use can no longer be -met (for example if the previous action was Attack Vehicles and all vehicles -have been destroyed, the script moves on to the next action). In other words, -this can be used to set a 'success' condition on the script.

- -

 

- -

50,n -= Flash (visual effect), n = number of flashes

- -

This causes the TaskForce to 'flash', the visual effect you get on an object -when you order something to attack it. The second parameter is the number of -times to flash the unit 'white'.

- -

 

- -

51,n= -Play Animation, n = animation number

- -

This -instructs the TaskForce to play one of the animations -from the [Animations] in the RULES.INI.INI file -(note that for all in game Action -and Trigger purposes this number is from -an internal table - see the Map Editing Guide).

- -

 

- -

52,n -= Display Talk Bubble, n = talk bubble number

- -

Should be used -for single-unit TaskForces only, this causes a 'talk bubble' to -appear above the unit. The second parameter determines which type of talk -bubble to display;-

- -

 

- -

1          *           general -speech

- -

2          ?          question

- -

3          !           shouting -or statement

- -

 

- -

Note that the -length of time for which the talk bubble is displayed is controlled through the -TalkBubbleTime= statement in RULES.INI - refer to the RULES.INI -Guide for details of this and the steps to take to enable its inclusion in -Red Alert 2 as this remains residual from Tiberian Sun:Firestorm.

- -

 

- -

53,0 -= Gather (at enemy base)

- -

This causes the TaskForce to gather together (sometimes used when members of -the TaskForce move at different speeds and you want the -faster ones to stop while the slower ones catch up) after the previous action -has been executed. If the TaskForce is in an attack mission and moving -towards an enemy base, this command is usually executed when the first member -of the TaskForce reaches the distance from that base -defined by the AISafeDistance= statement in RULES.INI - see the RULES.INI -Guide.

- -

 

- -

54,0 -= Regroup (at friendly base)

- -

This causes the TaskForce to regroup, if for example any of its members have -become engaged in a base defense mission or strayed away whilst in guard mode, -or even the TeamType itself has been suspended for whatever -reason. The members regroup directly next to each other leaving no 'gaps' at -the nearest available point with sufficient space, and is used, for example, -prior to activating the Iron Curtain so that all applicable members are -affected (i.e. they fall within its range of effect).

- -

 

- -

55,0 -= Activate Iron Curtain on TaskForce

- -

If the owner of -the TaskForce to which this ScriptType is attached also has the Iron Curtain fully charged -then it will be fired at this TaskForce. Note that the use of the Iron Curtain in -this manner depends on the percentage chance of the AI incorporating them into -its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI - see the RULES.INI -Guide for more details.

- -

 

- -

56,n -= ChronoSphere TaskForce, n = structure number to be Chronoshifted to (see note -below)

- -

If the owner of -the TaskForce to which this ScriptType is attached also has the Chronosphere fully charged -then it will be used on the TaskForce before moving on to the next action. Note -that the use of the Chronosphere in this manner depends on the percentage -chance of the AI incorporating them into its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI - see the RULES.INI -Guide for more details.

- -

 

- -

57,n -= ChronoWarp TaskForce, n = target number to be Chronoshifted to (see note -below)

- -

If the owner of -the TaskForce to which this ScriptType is attached has been Chronosphered then it will be -used on the same TaskForce to shift them to the enemy structure -number specified in the second parameter before moving on to the next action. -Note that the use of the Chronosphere in this manner depends on the percentage -chance of the AI incorporating them into its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI - see the RULES.INI -Guide for more details.

- -

 

- -

58,n -= Move To Friendly Structure, n = structure number (see note below)

- -

Members of this TaskForce move and stay adjacent to the friendly structure -specified by the second parameter. The structure can be one owned by the owner -of the TaskForce or any of its allies.

- -

 

- -

59,n -= Attack Structure At Waypoint (Yuri's Revenge only)

- -

Members of this TaskForce attack the structure at the Waypoint= specified by the second parameter. This action is -very similar to action number 43 although this action does not test for -ownership of the structure itself - thus the inclusion of this action -allows, for example, InfantryTypes with Engineer=yes set to enter structures owned by the same side for -the purposes of repair. This would be the most appropriate action to use to get -the AI to repair bridges. Use of this also means that the TaskForce will attack the structure with one of its weapons -meaning, for example, that units with C4=yes set -will not C4 the building but shoot at it instead. This is useful if you want to -get a TaskForce to destroy a nearby occupiable structure -instead of entering it in a bid to prevent the enemy getting old of it - a -tactic used in the Yuri's Revenge AI.

- -

 

- -

60,0 -= Enter Grinder (Yuri's Revenge only)

- -

Members of this TaskForce will enter the nearest structure with Grinding=yes set if it is owned by the owner of the TaskForce or any of its allies.

- -

 

- -

61,0 -= Occupy Tank Bunker (Yuri's Revenge only)

- -

Any VehicleType members of this TaskForce which do not have Bunkerable=no set will enter the nearest vacant structure with Bunker=yes set if it is owned by the owner of the TaskForce or any of its allies.

- -

 

- -

62,0 -= Enter Bio Reactor (Yuri's Revenge only)

- -

Any InfantryType members of this TaskForce will enter the nearest structure with InfantryAbsorb=yes set if it is owned by the owner of the TaskForce or any of its allies and has space available.

- -

 

- -

63,0 -= Occupy Battle Bunker (Yuri's Revenge only)

- -

Any InfantryType members of this TaskForce with Occupier=yes -set will enter the nearest structure (which they own) with CanOccupyFire=yes set.

- -

 

- -

64,0 -= Garrison Structure (Yuri's Revenge only)

- -

Any InfantryType members of this TaskForce with Occupier=yes -set will enter the nearest (neutral) structure with CanOccupyFire=yes set. This action is used specifically for this -purpose due to action #59 (see above) since the logic in Yuri's Revenge has -changed so that the units weapon is transferred to the structure. Use of this -action also allows the computer to repair those structures by sending an InfantryType with Engineer=yes set into them and also allows the AI to -differentiate between attacking such a structure and entering it, -which is useful if you want the AI to use infantry to destroy an occupiable -structure thus preventing its enemy from using it.

- -

 

- -

·                     -A -Note On Structure Numbers

- -

 

- -

When used in ScriptTypes, the structure number takes any of -several formats and is derived by finding the structure in the [BuildingTypes] list of RULES.INI and subtracting ONE -from this structures' number in that list (equivalent to renumbering the list -from 0) - this is the explicit number of that structure and is the number to -use as the second parameter of the action. Any one of several amendments can be -made to this number;-

- -

 

- -

·                     -add 131072 to the -number, so GAPOWR (number 1 in RULES.INI thus number 0 for this purpose) -becomes 131072

- -

·                     -add 196608 to the -number, so GAPOWR (number 1 in RULES.INI thus number 0 for this purpose) -becomes 196608

- -

·                     -add 65536 to the -number, so GAPOWR (number 1 in RULES.INI thus number 0 for this purpose) -becomes 65536

- -

 

- -

It has not been -determined what significance or effect the different numbering systems have (if -any). Changing them at random appears to have no effect although it is thought -that there is additional logic attached to them.

- -

 

- -

[TeamTypes]

- -

 

- -

This section -defines the TeamTypes, which connect a ScriptType -with a TaskForce while adding some generic behaviour -parameters (ie behaviours which apply to every member of the TaskForce) whether -they are how the TeamType is created, or how it behaves after -it has been created. These -behavioural modifiers make it difficult to entirely predict or determine the TeamTypes behaviour. The maximum number of TeamTypes which can be in existance at any one time is -controlled with the TotalAITeamCap= statement in RULES.INI - refer to the RULES.INI -Guide for a more detailed explanation of this and many other statements -relating to the AI. These can be created in any of several ways;-

- -

 

- -

·                     -within individual map -files by an Action when some pre-determined condition is met -by the game code (known as an Event) - see the Map Editing Guide

- -

 

- -

·                     -when a generic game -event occurs that may not be specific to a particular map, scenario or House (known as an AITriggerType, again these can be employed and even defined in -individual map files)

- -

 

- -

·                     -based on time rather -than an Event or a Trigger, the TeamType is -automatically created and used, known as Autocreate - this process is inherent in the game code in -skirmish games with the frequency of this process being controlled by the TeamDelays= statement in RULES.INI (see the RULES.INI -Guide). In map files, you must trigger this process yourself through the -relevant Action (see the Map Editing Guide).

- -

 

- -

The section takes -the form of a list of all TeamTypes. The list is numbered starting at 0, new -ones should be simply added to the end of the list. Each entry in the list -takes the form of a hexadecimal numbered string which is the unique identifier -for each of the TeamTypes - like other lists in the INI files, the -game code requires that each entry in this list is defined with its own section -in this file. For convention, it is wise to stick to this hex numbering system -although again this is not strictly necessary. The following statements can be -used;-

- -

 

- -

Name=

- -

This is simply a -string name used for identification purposes only, it is not required by the -game, although it is useful to leave this in for debugging and troubleshooting -your AI.INI file - as a point of interest, this statement does not even get -parsed.

- -

 

- -

VeteranLevel=

- -

Is used to -determine the level of 'veterancy' that each member of the TaskForce used by this TeamType has. Use 1 for 'Little Experience' (default), 2 for -'Veteran' and 3 for 'Elite'. Higher numbers can be used if you edit RULES.INI - -see the Veteran Factors section of the RULES.INI Guide for more -details.

- -

 

- -

(YR) MindControlDecision=

- -

Determines what a -member of the associated TaskForce will do if it 'mind controls' its target. -This only works if that has been placed in an 'attack' type mission, as it gets -over-ridden by other specific script actions. The decisions are;-

- -

 

- -

0 = nothing -(default behaviour) used to indicate that the TeamType should not use this logic

- -

1 = add to AI's -side as Recruitable=yes for further teams

- -

2 = send it to a -structure with Grinding=yes set for sale (e.g. Grinder) if owned

- -

3 = send it to a -structure with InfantryAbsorb=yes and/or UnitAbsorb=yes set (e.g. Bio Reactor) if owned

- -

4 = set object in -'Hunt' mission

- -

5 = do nothing

- -

 

- -

The percentage -chances of each of those actions as well as the parameters used to assist the -decision can be customized through the AICaptureNormal=, AICaptureWounded=, AICaptureLowPower=, AICaptureLowMoney=, AICaptureLowMoneyMark=, and AICaptureWoundedMark= statements in RULESMD.INI (see the RULES.INI Guide).

- -

 

- -

Loadable=

- -

Can be set to -'yes' or 'no' and is used to determine if the associated TaskForce should reload when any of its members run out of Ammo= . This is required in case a particular unit has to -dock with a co-ordinating structure to reload, a process which is a mission in -itself and thus could interrupt (and possibly cause havoc with) the actions for -the TeamType as defined by the associated ScriptType as 'nesting' missions in this manner could cause -Internal Errors - objects can only be in one mission at a time. This logic is -residual from Red Alert (where it was used primarily for the Mine Layer code) -and may be obsolete in Red Alert 2.

- -

 

- -

Full=

- -

Should be used -only in map files, this can be set to 'yes' or 'no' and determines if any units -within the associated TaskForce should be initially 'full' as determined -by the PipScale= statement in their RULES.INI entry - this -applies only to Ore Miners and transport type units in Red Alert 2. If the TaskForce contains a Transport and other units, the units -are automatically placed in the Transport for reinforcement purposes.

- -

 

- -

Annoyance=

- -

Can be set to -'yes' or 'no' and is used to determine if destroyed members of the associated TaskForce  are automatically replaced by the AI and allocated -the same ScriptType, the supposed effect being that this TeamType annoys the player with its persistence.

- -

 

- -

GuardSlower=

- -

Can be set to -'yes' or 'no' and has the effect of increasing the default value of  BaseDefenseDelay= as defined in RULES.INI specific to -this TeamType so that members of the associated TaskForce  in a base defense mission take longer to respond to -any threats to themselves or any objects they are guarding. The factor by which -that value is increased has not been determined.

- -

 

- -

House=

- -

Should be used -within map files and simply defines the House= to which ownership of this TeamType is automatically passed upon creation. For general -AI.INI TeamTypes this should be set to <none>. TIP: -In Yuri's Revenge, this can be used to refer to multiplayer (including -human) houses by specifying individual player houses at any of the 8 starting Waypoints= on the map. For example, to specify the player at -the first starting waypoint, you can use House=<Player @ A>. The letters A to H can be used to -represent Waypoint= numbers 0 - 7 inclusive, thus it is -possible to provide reinforcements to human players in multiplayer games. For -map file Trigger, Event and Action purposes, the multiplayer houses are -numbered 4475 - 4482, again representing the House= at each of the Waypoints numbered 0 - 7 inclusive.

- -

 

- -

Recruiter=

- -

Can be set to -'yes' or 'no' and determines if this TeamType can -be created by using any objects required to assemble the associated TaskForce that already exist on the map (provided they are not -already part of an existing TeamType).

- -

 

- -

Autocreate=

- -

Can be set to -'yes' or 'no' and specifies whether or not this TeamType should be created based on time rather than any -form of trigger. The AI.INI file usually defaults to 'no'  - this is because a TeamType  with Autocreate=yes -set is, obviously, subject to being automatically created. Each House= can, independently, have this function activated -through the relevant Action within a map file. As mentioned above, the frequency of this process is -controlled by the TeamDelays= statement in RULES.INI (see the RULES.INI -Guide).

- -

 

- -

Prebuild=

- -

Can be set to -'yes' or 'no' and determines if an inactive duplicate of the associated TaskForce should be created before it may be needed. This is -used in case the TeamType has a high Priority= setting so that the AI has a backup should the -original be destroyed (useful if the TaskForce -contains an object which is expensive or takes a long time to produce). This is -how the AI can sometimes appear to produce expensive units very quickly in some -single player missions.

- -

 

- -

Reinforce=

- -

Used in map files -only for single player missions, this can be set to 'yes' or 'no' and -determines if this TeamType forms reinforcements, in other words if -set to 'yes' then the TeamType is expected to be created from off the -map rather than on it.

- -

 

- -

Droppod=

- -

Can be set to -'yes' or 'no' and determines if the TaskForce -should be delivered by the AircraftType defined by the name [DPOD] in RULES.INI. This is entirely residual from -Tiberian Sun (where that unit was simply a placeholder for this purpose which -used the Drop Pod Locomotor=) and may be linked to and used by the -Paradrop logic in some way by Red Alert 2. The DPOD unit must have Passengers= and SizeLimit= values set accordingly (to allow it to carry the TaskForce) and for this purpose should also have Spawned=yes set. See the relevant entries in the RULES.INI -Guide for more details of customizing the Drop Pod effect.

- -

 

- -

UseTransportOrigin=

- -

Can be set to -'yes' or 'no' and determines whether or not this TeamType should be created at the point of origin of its -transport, if the transport itself already exists and has been recruited into -this TeamType. This is used in map files to create -reinforcement teams from off the map that will arrive on a transport.

- -

 

- -

Whiner=

- -

Can be set to -'yes' or 'no' and is used only by 'pool' TeamTypes (see AITriggerTypes) -to determine if destroyed members of the associated TaskForce are automatically replaced by the AI. This is -because 'pool'  TeamTypes are normally assigned to base defense -missions or generic missions such as guarding, hunting or scouting and their -members are always made available for recruitment into further teams (a -mechanism which ensures that the AI doesn’t always have to produce every team -from scratch since it will have a pool of units from which to assemble future -teams).

- -

 

- -

LooseRecruit=

- -

Can be set to -'yes' or 'no' and determines whether or not this TeamType should be dissolved after completion of its assigned -ScriptType if that mission was successful (in other -words the members of its associated TaskForce are -then free to be recruited into another TeamType).

- -

 

- -

Aggressive=

- -

The TeamType will execute orders regardless of enemy action and -will not stop to engage in combat with enemy objects, although it may retaliate -and return fire on the way. The supposed effect is that the associated TaskForce will doggedly aspire to complete its assigned ScriptType.

- -

 

- -

Suicide=

- -

The TeamType will execute orders regardless of enemy action and -will not stop to engage in combat with enemy objects and will not retaliate or -return fire. It will ignore Sight= ranges and the GuardRange= of any enemy objects and will not be recruited into -any subsequently created TeamTypes on the presumption that its associated ScriptType will invariably lead to the destruction of the -associated TaskForce.

- -

 

- -

Priority=

- -

This is used to -determine the priority of this TeamType being chosen for creation when the AI is -deciding what to do next. The lower the number, the greater the likelihood of -the AI using this TeamType above others. For simplicity, Red Alert 2 -uses multiples of 5 for this setting (Tiberian Sun used multiples of 4) so it -is best to stick with this convention although other values between 1 and 50 -can be used. Note that the setting of the SuspendPriority= statement in RULES.INI uses this value to determine -whether or not this TeamType will be suspended during base defense -missions (see the RULES.INI Guide for more details).

- -

 

- -

Max=

- -

This serves two -purposes. Firstly, it serves as a trigger to create the TeamType - when set to '1', it will automatically be created -by the AI regardless of whether or not it is already triggered for creation -through an AITriggerType or otherwise only if IsBaseDefense=no is set for this TeamType (see below). Secondly, it serves to indicate the -maximum number of instances of this TeamType that -can exist at the same time only if Autocreate=yes has been set for this TeamType (see above).

- -

 

- -

TechLevel=

- -

This is obsolete -in Red Alert 2 and is unused. In previous C&C games, this was used as a -method of restricting AI auto production by determining the lowest TechLevel= at which this team could be employed by the AI, -however the TechLevel= setting in Red Alert 2 has become all but -obsolete as this can no longer be determined by players. Leave this set to its -default of 0 (see the AITriggerTypes section for a further explanation of how -the TechLevel= setting is used by the AI as a result of -a change in the game engine code for Red Alert 2) .

- -

 

- -

Group=

- -

This defines a -specific grouping for the units in this TaskForce which is used when executing its ScriptType. This over-rides the Group= setting in the associated TaskForce. The following values can be used;-

- -

 

- -

-1                     Lose -Transports - any transports are dissolved and do not execute the script

- -

??                     Lose -Units, Lose Transports - all units dissolved, nothing executes the script

- -

??                     Keep -Units, Keep Transports - all units retained and all execute the script

- -

??                     Lose -Units, Keep Transports - only transports retained to execute script

- -

??                     Keep -Units Farthest - only units furthest away are retained

- -

??                     Keep -Units Nearest - only nearest units are retained

- -

??                     Greatest -Threat - group together at object posing greatest threat

- -

-40094              Least -Threat - group together at object posing least threat

- -

 

- -

Tag=

- -

Used in map files -only, this is used to determine which of the [Tags] is attached to this TeamType if there is a map-specific Event and Action attached to it (e.g. it gets destroyed or -should be created). See the Map Editing Guide for further details on [Tags] and their use. This is not ordinarily used in -AI.INI.

- -

 

- -

Waypoint=

- -

Used in map files -only, this is used to determine the waypoint at which the TeamType is to appear. You should ensure that the waypoint -you specify here is included in the [Waypoints]section -of the map file. See the Map Editing Guide for a detailed explanation of -waypoints. This is not ordinarily used in AI.INI although its worth noting that -Red Alert 2 assigns waypoint number 99 for the center of the map and waypoint -numbers 0 - 7 to define the starting places for the 8 players in multiplayer -maps.

- -

 

- -

OnTransOnly=

- -

Can be set to -'yes' or 'no' and determines whether or not this TeamType should only execute its associated ScriptType if that ScriptType -contains a 'load on transports' action. If that action is not successfully -completed, the TeamType is dissolved and the members of the -associated TaskForce  are made available for recruitment into -further TeamTypes . This is used to ensure that the TaskForce only carries out its mission if it has a transport -or can be transported (as it may depend upon it).

- -

 

- -

TransportWaypoint=

- -

Used in map files -only. Can be set to 'yes' or 'no' and specifies the waypoint at which the -transport for this TeamType is created if its at a separate place to -the rest of the TeamType.

- -

 

- -

AvoidThreats=

- -

Can be set to -'yes' or 'no' and determines whether or not this TeamType should take evasive action, meaning it will avoid, -where possible, Sight= ranges and the GuardRange= of any enemy objects. If set to 'no', the TeamType will engage and return fire on any enemy objects it -encounters during execution of its ScriptType -(if, of course, it is able to do so).

- -

 

- -

IonImmune=

- -

Can be set to -'yes' or 'no' and determines whether or not members of the associated TaskForce are immune to the effects of Weather Storms. This is -probably obsolete in Red Alert 2 as it is residual from Tiberian Sun, where the -occurrence of an Ion Storm would instantly destroy any airborne objects - this -tag would nullify that effect for this TeamType.

- -

 

- -

TransportsReturnOnUnload=

- -

Can be set to -'yes' or 'no' and determines whether or not any transports within the -associated TaskForce should return to their point of origin -upon deployment of their contents provided they have been released from that TaskForce by use of the 'dissolve transport' action or using -an appropriate second parameter on the 'unload transports' action (see above). -The purpose of this is primarily due to the fact that most transports are -unarmed and thus unable to carry out any other mission, so by returning to -their point of origin they are made immediately available for recruitment into -further TeamTypes.

- -

 

- -

AreTeamMembersRecruitable=

- -

Can be set to -'yes' or 'no' and determines whether or not members of the associated TaskForce are available to be recruited into further TeamTypes when they have completed the actions detailed in the -associated ScriptType. This is used because you can't actually -recruit units that are already in a TeamType.

- -

 

- -

IsBaseDefense=

- -

Used mainly for -'pool' teams (see AITriggerTypes). Can be set to 'yes' or 'no' and determines -whether or not this TeamType should assume a base defense mission -based on the actions detailed in its associated ScriptType. The number of TeamTypes which can be assigned to this at any one time is -controlled by the MinimumAIDefensiveTeams= and MaximumAIDefensiveTeams= statements in RULES.INI (see the RULES.INI -Guide). TIP: A TeamType which has IsBaseDefense= -set to 'yes' will also rush to the aid of any units owned by the same House= which have ToProtect=yes -set (the only examples of this in Red Alert 2 are the Ore Miners).

- -

 

- -

OnlyTargetHouseEnemy=

- -

Can be set to -'yes' or 'no' and determines whether or not members of the associated TaskForce will also attack 'neutral' units (e.g. civilians or -other objects belonging to a House= with Side=Neutral set) and consider such objects in its threat scan.

- -

 

- -

Script=

- -

The unique -identifier name used to determine the ScriptType to -use for this TeamType and should also be contained in the [ScriptTypes]list and have its own section defined.

- -

 

- -

TaskForce=

- -

The unique -identifier name used to determine the TaskForce to -use for this TeamType and should also be contained in the [TaskForces]list and have its own section defined.

- -

 

- -

[AITriggerTypes]

- -

 

- -

This section -defines which of the TeamTypes should automatically be created in response -to specific game events or other triggers in the game. Most of these are -created by the AI in an attempt to ensure that it always deals with certain -things, for example 'its a good idea to destroy an enemy Nuke Silo' or 'it -would be good to capture or destroy the enemy Construction Yard'. In effect, -this section is the very essence of the scripted AI.

- -

 

- -

This section also -constitutes the full list of 'global' AI triggers used by the computer in -single and multiplayer games. Individual map files can indicate whether or not -this list should be used with use of the IgnoreGlobalAITriggers= statement in their [Basic] section (setting that to 'yes' means this list will -not be used in games played on that map) and can also define their own AI -triggers to be used only in games played on that map by including their -own [AITriggerTypes] section which simply appends the new ones -to the end of this list. Additionally, map files can also specify which of -these triggers should be used in games played on that map on an individual basis -with use of the [AITriggerTypesEnable] section which effectively allows each -individual trigger to be enabled or disabled - this is used in Red Alert 2, for -example, to ensure the AI makes use of Naval type attack forces on maps which -have a high water content and does not try to attack with ground based units. -See the Map Editing Guide for more details.

- -

 

- -

The section -simply forms a list of each AITriggerType and in a break with convention it is not -numbered and each entry contains its own data. Note that this may partly be due -to the fact that individual AITriggerTypes listed here can each be enabled or -disabled through map files (see the Map Editing Guide) so for example, -the computer will not waste time and resources building a TeamType specifically to capture your Construction Yard if -you can't even acquire one in the mission.

- -

 

- -

Each entry takes -the following format;-

- -

 

- -

[ID]= -A,B,C,D,E,F,G,XX.000000,YY.000000,ZZ.000000,X1,Y,X2,Z,H,D1,D2,D3

- -

 

- -

[ID]

- -

Takes the form of -a hexadecimal numbered string which is the unique identifier for this AITriggerType. DO NOT change this as the [AITriggerTypesEnable] section in most map files depends upon -these values in order to enable/disable this particular AITriggerType as required. If you want to add or modify -one, copy an existing one and add it to the end of the list with a new ID.

- -

 

- -

A = Name

- -

This is simply a -string name used for identification purposes only. In this section, you should -leave this in.

- -

 

- -

B = -TeamType

- -

Determines which -of the TeamTypes should be used for the actions associated -with this trigger. If a TeamType is not required then this should be set -to <none>.

- -

 

- -

C = Owner

- -

Determines which House or Country is associated with using this trigger. -This is to ensure, for example, that Soviet armies do not use TeamTypes containing Allied units and vice versa as this -serves as an override to the Owner= -statement for each object in -RULES.INI. You should set this to <all> if -it pertains to no particular or specific House=.

- -

 

- -

D = -TechLevel

- -

Determines the TechLevel= setting which is required in order for this trigger -to be used. Although the TechLevel= -setting is partly useless to -human players in Red Alert 2, this is used by the AI when it assembles TaskForces. The trigger will only be used when the AI -has reached this TechLevel= setting through construction of the -required structures in its tech tree - setting this value below that required -for a particular unit can often lead to the AI using units for which it has not -met the Prerequisite= requirements. It is best to set this to at -least the setting required to build any units in the associated TaskForce(s).

- -

 

- -

E = -AITriggerType

- -

Holds the type -of AI trigger. This holds values between 0 - 7 with '-1' representing a special -case for 'pool' teams.

- -

 

- -

-1         AI -pool team trigger (autocreated thus not attached to the AIGenerals)

- -

 0         trigger -when enemy owns the Unit -Type or Tech Type (min quantity specified by parameter AABBCCDD)

- -

 1         trigger -when computer owns the Unit -Type or Tech Type (min quantity specified by parameter AABBCCDD)

- -

 2         trigger -when enemy has low power (power is in Yellow)

- -

 3         trigger -when enemy has low power (power is in Red)

- -

 4         trigger -based on number of Credits held by enemy (min quantity specified by -parameter AABBCCDD)

- -

 5         trigger -when Iron Curtain is charged to amount specified by AIMinorSuperReadyPercent= in RULES.INI

- -

 6         trigger -when Chronosphere is charged to amount specified by AIMinorSuperReadyPercent= in RULES.INI

- -

 7         trigger -when neutral owns the Unit -Type or Tech Type (min quantity specified by parameter AABBCCDD)

- -

 

- -

TIP: Use AI Trigger Type number 4 to fire triggers based on the number of -credits held by the player - this will add to the 'unpredictability' of the AI -as it wont be creating a TeamType based on the existence of something else. -This will also allow you to target the player with most money (usually a sign -of 'turtling') in which case destroying/capturing their refineries and hunting -their Ore Miners as well as capturing Oil Derricks make good strategies for the -AI. In Yuri's Revenge, this also makes a useful trigger for launching AI -attacks with Floating Disks against Refineries.

- -

 

- -

F = Tech -Type

- -

Determines which -object in the game will cause the AI to use this trigger. Should be any object -from the [BuildingTypes],[InfantryTypes],[VehicleTypes] or [AircraftTypes]lists from RULES.INI. If the trigger is not fired -based on a unit or tech type, <none> should be used instead (one example is -for the creation of 'pool' teams). TIP: -If you want the AI to defend against a tank rush, make the trigger fire upon the -existence of the enemy Weapons Factory rather than the tanks themselves - this -means the AI will have its defense ready by the time the tanks hit it.

- -

 

- -

G

- -

Determines what -to do in response to the unit or tech type defined in parameter 'F' (above). -Takes the following format;-

- -

AABBCCDD-EEFFGGHH-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

- -

 

- -

·                     -AABBCCDD holds a number (represented by 4 hex -bytes, in reverse) for each subsequently specified condition that must be -satisfied for the trigger to be fired.

- -

·                     -EEFFGGHH holds a value between 0 and 5 and fires -the trigger in response to one of the following condition types;-

- -

·                     -            5 = fire -the trigger if not equal to

- -

·                     -            4 = fire -the trigger if greater than

- -

·                     -            3 = fire -the trigger if greater than or equal to

- -

·                     -            2 = fire -the trigger if equal to

- -

·                     -            1 = fire -the trigger if less than or equal to

- -

·                     -            0 = fire -the trigger if less than

- -

 

- -

If both numbers -are set to '00000000', this signifies the creation of a 'pool' type team (see -below).

- -

 

- -

The long string -of numbers represented by X's are usually all set to '0' - no exceptions to -this have been observed and their use or significance has not been established.

- -

 

- -

XX.000000 -= Weighted Probability

- -

This determines -the percentage probability that this AITriggerType -will be used so that a weighted distribution of triggers is employed rather -than all of them being executed one at a time as if in a list. High values such -as 5000.000000 are used to ensure absolute certainty. The 'predictability' of -the Red Alert 2 AI is due partly to the fact that the same values (10, 20, 40, -50, 70, 500, 5000) are usually employed throughout the triggers.

- -

 

- -

YY.000000 -= Minimum Weighted Probability

- -

This determines -the minimum percentage probability that this AITriggerType will be used when amended by the AI Trigger -Weighting Parameters in RULES.INI so that a weighted distribution of -triggers is employed rather than all of them being executed one at a time as if -in a list. High values such as 5000.000000 are used to ensure absolute -certainty. The 'predictability' of the Red Alert 2 AI is due partly to the fact -that the same values (10, 20, 40, 50, 70, 500, 5000) are usually employed -throughout the triggers.

- -

 

- -

ZZ.000000 -= Maximum Weighted Probability

- -

This determines -the maximum percentage probability that this AITriggerType will be used when amended by the AI Trigger -Weighting Parameters in RULES.INI so that a weighted distribution of -triggers is employed rather than all of them being executed one at a time as if -in a list. High values such as 5000.000000 are used to ensure absolute -certainty. The 'predictability' of the Red Alert 2 AI is due partly to the fact -that the same values (10, 20, 40, 50, 70, 500, 5000) are usually employed -throughout the triggers.

- -

 

- -

X1 = -Skirmish Availability Flag

- -

This should be -set to '1' if the trigger is to be made available to the computer in skirmish -mode and '0' if not.

- -

 

- -

Y = Not -Known

- -

Unknown but is -always set to '0'. Possibly used to associate this trigger with a specific AI -General although this is difficult to substantiate (see the [AIGenerals] section of the RULES.INI Guide for -more details).

- -

 

- -

X2 = Side -Ownership

- -

This value is -what gives ownership of the trigger itself to a particular Side=, since several Houses= could belong to the same Side=. This is what enables generic scripts to be used, for -example any Soviet army to create Dogs to guard against Spies rather than, say, -just Russia. This value should be set to 1 if this AITriggerType applies to an Allied army, '2' if it applies to a -Soviet army and '3' if it applies to a Yuri army (in Yuri's Revenge only). TIP: Setting this parameter to '0' allows any -AI controlled House= or Side= to use this trigger, regardless of the Owner= setting on the units in the TeamType, meaning that any AI player could use the -same trigger in the game.

- -

 

- -

Z = Base -Defense Flag

- -

This should be -set to '1' if the trigger is used for AI base defense and '0' if not. Helps the -AI to decide what to do when it adopts a specific behaviour dictated by the AIGenerals (see the RULES.INI Guide) and also means the -AI will create the associated TeamType even if it has not yet chosen an enemy. -This is also attached to the UseMinDefenseRule= tag (see the RULES.INI Guide).

- -

 

- -

H = -Support TeamType

- -

This is what -gives the AI some degree of 'smartness' - if the AI simply used the AITriggerTypes without this, it would appear to be -boring and predictable as all it would effectively be doing is sending a series -of attacks at the players 'list fashion'. This second TeamType is used if, for whatever reason, the first TeamType comes under attack or is otherwise deemed as being -likely to fail its associated ScriptType. In that instance, this second TeamType is despatched to support the first, either by -eliminating the threat to it or by attacking something else in a bid to create -a distraction. This second TeamType is sometimes despatched prior to the -first - for example the second TeamType could be instructed to destroy any AA -defenses prior to the first being an air-ground assault. This is a much -under-utilized feature which allows for the possibility of combined assaults on -players. TIP: If you have a TeamType which is performing a 'rush', give it a support TeamType which can deal with any Aircraft or Base Defenses -which may pose a threat to it thus rendering it useless.

- -

 

- -

D1 = -Difficulty #1

- -

Flag which should -be set to 1 or 0 and indicates if this AITriggerType can be used on the easiest (or Easy) skill level -setting in the game.

- -

 

- -

D2 = -Difficulty #2

- -

Flag which should -be set to 1 or 0 and indicates if this AITriggerType can be used on the medium (or Normal) skill level -setting in the game.

- -

 

- -

D2 - -Difficulty #3

- -

Flag which should -be set to 1 or 0 and represents of this AITriggerType can be used on the hardest (or Brutal) skill level -setting in the game.

- -

 

- -

·                     -A -Note On AI Pool Teams

- -

 

- -

Its worth noting -that the AI is frequently triggered to create 'pool' teams. These are teams -which tend to be created based on time rather than any specific event (although -some pool teams are still triggered for creation by events) - this is done -automatically in skirmish mode by the 'autocreate' process with the frequency of this being -controlled by the TeamDelays= statement in RULES.INI (see the RULES.INI -Guide). The members of -these teams usually assume some default behaviour such as guarding the AI's -base, and the main reason for their creation is simply to make units available -for the AI so that it doesn't play the game in a scripted, linear fashion. Use -of pool teams also ensures that, for example, the AI always has something -with which to defend its base or guard its Ore Miners.

- -

 

- -

Members of teams -created as pool teams are also used to fill other teams (in other words they -are 'recruitable') so that the AI does not always have to build every team from -scratch. Whilst awaiting recruitment, the pool teams assume a default behaviour -(usually defense) until any or all of their members individually or -collectively are recruited to join another AI team that has a specific script -to perform, although some members may never be recruited into another team.

- -

 

- -

For those -reasons, it is always well worth ensuring that you have the AI create quite a -few pool teams, otherwise you will find its actions slow and infrequent as it -will have to build almost every team from scratch.

- -

 

- -

TIP: its well worth putting pool teams into a -default mission of 'Guard' rather than 'Guard Area', as teams in a 'Guard Area' -mission are not recruited 'from the field'  when making new teams (see -the note above under the relevant script action). This will also speed the game -up a little as 'Guard' requires less processor time than 'Guard Area'. Exploit -the autocreation of 'pool' teams - you don't have to put these teams -into a generic mission such as base defense - you could, for example, make an -autocreated pool team that simply attacks the enemies Construction Yard or -hunts enemy Ore Miners. The autocreate process for pool teams means that the AI -will always conduct such attacks at regular intervals with the pool team you -have defined.

- -
- - - - diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs index d69274b..6033c2b 100644 --- a/AssemblyInfo.cs +++ b/AssemblyInfo.cs @@ -56,4 +56,4 @@ [assembly: AssemblyDelaySign(false)] [assembly: AssemblyKeyFile("")] [assembly: AssemblyKeyName("")] -[assembly: AssemblyFileVersionAttribute("2.0.3")] +[assembly: AssemblyFileVersionAttribute("2.0.3.9")] diff --git a/README.md b/README.md index 8b94928..d786881 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,42 @@ Link: https://github.com/askeladdk/aiedit ## Changelog ## +### v2.0.3.9 ### +- TS config file fix of veteran level and removed unused AITrigger condition choices +- Skipped across list duplicate ID check for AITrigger IDs as vanilla TS has such +- Added version number to application title text +- Updated the AIGuide for script action Attack TargetType (0,n) + +### v2.0.3.8 ### +- Reverted back non-essential changes in the form designer file. + +### v2.0.3.7 ### +- Fixed additional number of duplicate messages on reloading INI files. + +### v2.0.3.6 ### +- Added AI Guide for offline reference. +- Removed the usage of [AIEdit] section for ID generation. +- Provided StartIndex, IDPrefix and IDSuffix fields in config file for customizing IDs. +- Config files updated for corrections and for ID related fields. +- Added duplicate ID check across lists in AI ini. +- Parsing exception message box will now close the application. + +### v2.0.3.5 ### +- Avoid creating duplicate IDs even if [AIEdit] section is deleted from AI ini. + +### v2.0.3.4 ### +- TeamType fields of Max/Priority/Techlevel now allows negative numbers. + +### v2.0.3.3 ### +- Script action's parameters now allow negative numbers wherever needed. +- Script actions 53, 54 and 55 now has editable parameters for YR (config\yr.ini). + +### v2.0.3.2 ### +- Added an error message with faulty ID before throwing an exception while parsing AI ini. + +### v2.0.3.1 ### +- Application path is used to compute the full path of config files. + ### v2.0.3 ### - Changed the wording of the error log messages to be more consistent. - Updated to ObjectListView 2.9.10. diff --git a/ScriptType.cs b/ScriptType.cs index 24e059b..1d841d9 100644 --- a/ScriptType.cs +++ b/ScriptType.cs @@ -5,6 +5,7 @@ using System.Text; using System.IO; using System.Linq; +using System.Windows.Forms; namespace AIEdit { @@ -40,6 +41,7 @@ public int CompareTo(object other) public enum ScriptParamType { Number, + NumPlusMinus, List, TechnoType, AIObject @@ -52,8 +54,8 @@ public interface IActionType string Description { get; } IList List { get; } ScriptParamType ParamType { get; } - string ParamToString(uint param); - IParamListEntry ParamEntry(uint param); + string ParamToString(int param); + IParamListEntry ParamEntry(int param); } public class ActionTypeNumber : IActionType, IComparable @@ -67,12 +69,12 @@ public class ActionTypeNumber : IActionType, IComparable public IList List { get { return null; } } public ScriptParamType ParamType { get { return ScriptParamType.Number; } } - public string ParamToString(uint param) + public string ParamToString(int param) { return param.ToString(); } - public IParamListEntry ParamEntry(uint param) + public IParamListEntry ParamEntry(int param) { return null; } @@ -95,6 +97,45 @@ public int CompareTo(object other) } } + public class ActionTypeNumPlusMinus : IActionType, IComparable + { + private uint code; + private string name, desc; + + public uint Code { get { return code; } } + public string Name { get { return name; } } + public string Description { get { return desc; } } + public IList List { get { return null; } } + public ScriptParamType ParamType { get { return ScriptParamType.NumPlusMinus; } } + + public string ParamToString(int param) + { + return param.ToString(); + } + + public IParamListEntry ParamEntry(int param) + { + return null; + } + + public ActionTypeNumPlusMinus(uint code, string name, string desc) + { + this.code = code; + this.name = name; + this.desc = desc; + } + + public override string ToString() + { + return name; + } + + public int CompareTo(object other) + { + return name.CompareTo((other as IActionType).Name); + } + } + public class ActionTypeList : IActionType, IComparable { private uint code; @@ -108,16 +149,16 @@ public class ActionTypeList : IActionType, IComparable public IList List { get { return list; } } public ScriptParamType ParamType { get { return paramType; } } - public IParamListEntry ParamEntry(uint param) + public IParamListEntry ParamEntry(int param) { foreach (IParamListEntry entry in list) { - if (entry.ParamListIndex == param) return entry; + if (entry.ParamListIndex == (uint)param) return entry; } return null; } - public string ParamToString(uint param) + public string ParamToString(int param) { IParamListEntry entry = ParamEntry(param); return entry != null ? entry.ToString() : ""; @@ -148,10 +189,10 @@ public int CompareTo(object other) /// public class ScriptAction { - private static uint[] offsets = { 0, 65536, 131072, 196608 }; + private static int[] offsets = { 0, 65536, 131072, 196608 }; private static string[] offsetsDesc = { "Least Threat", "Most Threat", "Closest", "Farthest" }; private IActionType action; - private uint param, offset; + private int param, offset; public IActionType Action { @@ -170,8 +211,8 @@ public IActionType Action } } - public uint Param { get { return param; } set { param = value; } } - public uint Offset { get { return offset; } set { offset = value; } } + public int Param { get { return param; } set { param = value; } } + public int Offset { get { return offset; } set { offset = value; } } public string ParamString { get { return action.ParamToString(param); } } @@ -192,7 +233,7 @@ public IParamListEntry ParamEntry } } - public ScriptAction(IActionType action, uint param) + public ScriptAction(IActionType action, int param) { this.action = action; GetOffset(param, out this.param, out offset); @@ -208,18 +249,18 @@ public ScriptAction(ScriptAction other) public void Write(StreamWriter stream, int index) { uint a = action.Code; - uint p = param + offsets[offset]; + int p = param + offsets[offset]; stream.WriteLine(index.ToString() + "=" + a.ToString() + "," + p.ToString()); } - private static void GetOffset(uint index, out uint param, out uint offset) + private static void GetOffset(int index, out int param, out int offset) { for (int i = offsets.Length - 1; i >= 0; i--) { if (index >= offsets[i]) { param = index - offsets[i]; - offset = (uint)i; + offset = i; return; } } @@ -337,31 +378,40 @@ public void Write(StreamWriter stream) string name = id; List actions = new List(); - foreach(DictionaryEntry entry in section) + try { - if ((entry.Key as string) == "Name") - { - name = entry.Value as string; - } - else + foreach(DictionaryEntry entry in section) { - string[] split = (entry.Value as string).Split(','); - - if (split.Length < 2) + if ((entry.Key as string) == "Name") { - logger.Add("ScriptType " + id + ": Entry not in format: =,"); + name = entry.Value as string; } else { - int a = int.Parse(split[0]); - uint p = uint.Parse(split[1]); - IActionType actionType = types[a]; - - ScriptAction action = new ScriptAction(actionType, p); - actions.Add(action); + string[] split = (entry.Value as string).Split(','); + + if (split.Length < 2) + { + logger.Add("ScriptType " + id + ": Entry not in format: =,"); + } + else + { + int a = int.Parse(split[0]); + int p = int.Parse(split[1]); + IActionType actionType = types[a]; + + ScriptAction action = new ScriptAction(actionType, p); + actions.Add(action); + } } } } + catch (Exception ) + { + string msg = "Error occured at ScriptType: [" + id + "]" + "\nPlease verify its format. Application will now close."; + MessageBox.Show(msg, "Parse Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); + Application.Exit(); + } return new ScriptType(id, name, actions); } diff --git a/TaskForce.cs b/TaskForce.cs index 534b449..40c8a8d 100644 --- a/TaskForce.cs +++ b/TaskForce.cs @@ -177,53 +177,62 @@ public void Write(StreamWriter stream) int groupi = -1; List units = new List(); - foreach(DictionaryEntry entry in section) + try { - string currKey = entry.Key as string; - string currValue = entry.Value as string; - - if (currKey == "Name") - { - name = currValue; - } - else if (currKey == "Group") + foreach(DictionaryEntry entry in section) { - groupi = int.Parse(currValue); - } - else - { - string[] split = currValue.Split(','); + string currKey = entry.Key as string; + string currValue = entry.Value as string; - if (split.Length < 2) + if (currKey == "Name") + { + name = currValue; + } + else if (currKey == "Group") { - logger.Add("Task Force [" + id + "] not in format: =,"); + groupi = int.Parse(currValue); } - else + else { - uint count = uint.Parse(split[0] as string); - string unitid = split[1] as string; - TechnoType tt = technoTypes.SingleOrDefault(t => t.ID == unitid); + string[] split = currValue.Split(','); - if (tt == null) + if (split.Length < 2) { - logger.Add("TechnoType [" + unitid + "] referenced by Task Force [" + id + "] does not exist!"); - tt = new TechnoType(unitid, unitid, 0, 0); - technoTypes.Add(tt); + logger.Add("Task Force [" + id + "] not in format: =,"); } - - if (int.Parse(currKey) > 5) + else { - logger.Add("Task Force [" + id + "]: Game ignores unit entry index greater than 5."); + uint count = uint.Parse(split[0] as string); + string unitid = split[1] as string; + TechnoType tt = technoTypes.SingleOrDefault(t => t.ID == unitid); + + if (tt == null) + { + logger.Add("TechnoType [" + unitid + "] referenced by Task Force [" + id + "] does not exist!"); + tt = new TechnoType(unitid, unitid, 0, 0); + technoTypes.Add(tt); + } + + if (int.Parse(currKey) > 5) + { + logger.Add("Task Force [" + id + "]: Game ignores unit entry index greater than 5."); + } + + units.Add(new TaskForceEntry(tt, count)); } - - units.Add(new TaskForceEntry(tt, count)); } } } + catch (Exception ) + { + string msg = "Error occured at TaskForce: [" + id + "]" + "\nPlease verify its format. Application will now close."; + MessageBox.Show(msg, "Parse Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); + Application.Exit(); + } AITypeListEntry group = groupTypes.SingleOrDefault(g => g.Index == groupi); if (group == null) group = groupTypes[0]; - + return new TaskForce(id, name, group, units); } } diff --git a/TeamType.cs b/TeamType.cs index 1d45bcc..1e3d92f 100644 --- a/TeamType.cs +++ b/TeamType.cs @@ -5,6 +5,7 @@ using System.Text; using System.IO; using System.Linq; +using System.Windows.Forms; namespace AIEdit { @@ -51,18 +52,18 @@ public TeamTypeOptionNumber(string tag, string name) : base(tag, name) } public override IList List { get { return null; } } - public override TeamTypeEntry DefaultValue { get { return new TeamTypeEntry(this, (object)0U); } } + public override TeamTypeEntry DefaultValue { get { return new TeamTypeEntry(this, (object)0); } } public override int SortOrder { get { return 2; } } public override TeamTypeEntry Parse(OrderedDictionary section) { if (!section.Contains(tag)) return DefaultValue; - return new TeamTypeEntry(this, section.GetUint(tag)); + return new TeamTypeEntry(this, section.GetInt(tag)); } public override void Write(StreamWriter stream, object value) { - stream.WriteLine(tag + "=" + ((uint)value)); + stream.WriteLine(tag + "=" + ((int)value)); } } @@ -268,9 +269,18 @@ public static TeamType Parse(string id, OrderedDictionary section, List @@ -76,7 +84,7 @@ Digest=pciAS/TnHWXQNmZa4GbC9emvP3M= 0=Don't use this logic [Group] --1=No Group +-1=No Group (Recommended) -2=Any Group -3=Group 1 -4=Group 2 @@ -185,15 +193,15 @@ Digest=pciAS/TnHWXQNmZa4GbC9emvP3M= ; This list contains all the script actions. ; The format is: ; Index = Name, Type, Description -; Type = Number, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. +; Type = Number (>=0), NumPlusMinus, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. [ActionTypes] -0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type. +0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type repeatedly. 1=Attack Waypoint,Number, 2=Go Berserk,NoTypes,Causes cyborgs to go berserk (does not work). 3=Move To Waypoint,Number, 4=Move Into Celltag,Number,Only used in maps. 5=Guard Area,Number,The parameter is the time in multiples of 6 seconds. -6=Jump To Script Action,Number,The parameter is the number of the action to jump to. +6=Jump To Script Action,Number,The parameter is the line number of the action to jump to (line number starts at 1, not 0). 7=Force Player Win,NoTypes,Forces the TaskForce owner to win. 8=Unload,UnloadTypes,Unload transport. 9=Deploy,NoTypes,Causes the units in taskforce to deploy if they can. @@ -202,7 +210,7 @@ Digest=pciAS/TnHWXQNmZa4GbC9emvP3M= 12=Set Global,Number,The parameter is the global variable number to set to TRUE. 13=Play Idle Anim Sequence,Number,Causes infantry units in the taskforce to play the specified idle animation. 14=Load Onto Transport,NoTypes,Instruct TaskForce members to enter a transport in the TaskForce. -15=Spy On Structure At Waypoint,Number, +15=Enter Structure At Waypoint,Number, 16=Patrol To Waypoint,Number, 17=Change To Script,Number,Instructs the task force to switch to a different script. 18=Join Team,Number,Instructs the task force to join another team type. @@ -236,7 +244,7 @@ Digest=pciAS/TnHWXQNmZa4GbC9emvP3M= 46=Attack Enemy Structure,BuildingTypes,Instructs the taskforce to attack a specific enemy structure. 47=Move To Enemy Structure,BuildingTypes,Instructs the taskforce to move to a specific enemy structure. 48=Scout,NoTypes,Move as far as possible in a random direction. Use this to make the AI scout the map. -49=Repeat Until Success,NoTypes,Instructs the taskforce to continually execute the previous action until it is unable to. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. +49=Register Success,NoTypes,Register success for AITrigger weight adjustment. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. 50=Flash,Number,Flashes the taskforce a number of times. 51=Play Animation,Number,Plays an animation from [Animations] in RULES.ini. 52=Display Talk Bubble,TalkBubbleTypes,Displays a talk bubble over the taskforce. diff --git a/config/ts.ini b/config/ts.ini index 8dd9204..139809a 100644 --- a/config/ts.ini +++ b/config/ts.ini @@ -4,6 +4,14 @@ Houses=Houses EditorName=EditorName Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= +; Index IDs customization like 01000000-G. StartIndex format is 8-digit hex +; number from 0 to FFFFFFFF, default is 01000000. IDPrefix, a string prefix, +; default is empty. IDSuffix, a string suffix, default is -G. IDPrefix/IDSuffix +; strings can contain alphabets/numbers/hyphen/underscore and should +; be short. These are converted to uppercase. +;StartIndex=01000000 +;IDPrefix= +;IDSuffix=-G [Sides] 0= @@ -67,15 +75,15 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= 16=BaseDefense,Used In Base Defense?,BOOL [VeteranLevels] -0=Rookie -1=Veteran -2=Elite +1=Rookie +2=Veteran +3=Elite [MCDecisions] 0=Don't use this logic [Group] --1=No Group +-1=No Group (Recommended) -2=Any Group -3=Group 1 -4=Group 2 @@ -96,9 +104,6 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= 2=Enemy power is YELLOW 3=Enemy power is RED 4=Enemy has at least AMOUNT of credits -5=<5 unused?> -6=<6 unused?> -7=Neutral owns AMOUNT of TECH TYPE [Operators] 0=Less than @@ -119,8 +124,6 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= 7=Base Defenses 8=Base Threats 9=Power Plants -10=Occupiable Buildings -11=Tech Buildings [UnloadTypes] 0=Keep transports and units @@ -179,15 +182,15 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= ; The format is: ; Index = Name, Type, Description ; Index = Name, Type, Description -; Type = Number, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. +; Type = Number (>=0), NumPlusMinus, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. [ActionTypes] -0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type. +0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type repeatedly. 1=Attack Waypoint,Number, 2=Go Berserk,NoTypes,Causes cyborgs to go berserk (does not work). 3=Move To Waypoint,Number, 4=Move Into Celltag,Number,Only used in maps. 5=Guard Area,Number,The parameter is the time in multiples of 6 seconds. -6=Jump To Script Action,Number,The parameter is the number of the action to jump to. +6=Jump To Script Action,Number,The parameter is the line number of the action to jump to (line number starts at 1, not 0). 7=Force Player Win,NoTypes,Forces the TaskForce owner to win. 8=Unload,UnloadTypes,Unload transport. 9=Deploy,NoTypes,Causes the units in taskforce to deploy if they can. @@ -196,7 +199,7 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= 12=Set Global,Number,The parameter is the global variable number to set to TRUE. 13=Play Idle Anim Sequence,Number,Causes infantry units in the taskforce to play the specified idle animation. 14=Load Onto Transport,NoTypes,Instruct TaskForce members to enter a transport in the TaskForce. -15=Spy On Structure At Waypoint,Number, +15=Enter Structure At Waypoint,Number, 16=Patrol To Waypoint,Number, 17=Change To Script,Number,Instructs the taskforce to switch to a different script. 18=Join Team,Number,Instructs the taskforce to join another teamtype. @@ -230,7 +233,7 @@ Digest=aG6xg9lMqJoMyUqKRzv4QJZ2vmk= 46=Attack Enemy Structure,BuildingTypes,Instructs the taskforce to attack a specific enemy structure. 47=Move To Enemy Structure,BuildingTypes,Instructs the taskforce to move to a specific enemy structure. 48=Scout,NoTypes,Move as far as possible in a random direction. Use this to make the AI scout the map. -49=Repeat Until Success,NoTypes,Instructs the taskforce to continually execute the previous action until it is unable to. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. +49=Register Success,NoTypes,Register success for AITrigger weight adjustment. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. 50=Flash,Number,Flashes the taskforce a number of times. 51=Play Animation,Number,Plays an animation from [Animations] in RULES.ini. 52=Display Talk Bubble,TalkBubbleTypes,Displays a talk bubble over the taskforce. diff --git a/config/yr.ini b/config/yr.ini index 63d013d..bb16ad9 100644 --- a/config/yr.ini +++ b/config/yr.ini @@ -4,6 +4,14 @@ Houses=Countries EditorName=Name Digest=m+F1aOs8y7FvcCJjyEsh2JEPw4I= +; Index IDs customization like 01000000-G. StartIndex format is 8-digit hex +; number from 0 to FFFFFFFF, default is 01000000. IDPrefix, a string prefix, +; default is empty. IDSuffix, a string suffix, default is -G. IDPrefix/IDSuffix +; strings can contain alphabets/numbers/hyphen/underscore and should +; be short. These are converted to uppercase. +;StartIndex=01000000 +;IDPrefix= +;IDSuffix=-G [Sides] 0= @@ -85,7 +93,7 @@ Digest=m+F1aOs8y7FvcCJjyEsh2JEPw4I= 5=Do nothing [Group] --1=No Group +-1=No Group (Recommended) -2=Any Group -3=Group 1 -4=Group 2 @@ -196,15 +204,15 @@ Digest=m+F1aOs8y7FvcCJjyEsh2JEPw4I= ; This list contains all the script actions. ; The format is: ; Index = Name, Type, Description -; Type = Number, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. +; Type = Number (>=0), NumPlusMinus, NoTypes, TargetTypes, UnloadTypes, MissionTypes, FacingTypes, TalkBubbleTypes, BuildingTypes. [ActionTypes] -0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type. +0=Attack Target Type,TargetTypes,Instructs the taskforce to find and attack the specified target type repeatedly. 1=Attack Waypoint,Number, 2=Go Berserk,NoTypes,Causes cyborgs to go berserk (does not work). 3=Move To Waypoint,Number, 4=Move Into Celltag,Number,Only used in maps. 5=Guard Area,Number,The parameter is the time in multiples of 6 seconds. -6=Jump To Script Action,Number,The parameter is the number of the action to jump to. +6=Jump To Script Action,Number,The parameter is the line number of the action to jump to (line number starts at 1, not 0). 7=Force Player Win,NoTypes,Forces the TaskForce owner to win. 8=Unload,UnloadTypes,Unload transport. 9=Deploy,NoTypes,Causes the units in taskforce to deploy if they can. @@ -213,7 +221,7 @@ Digest=m+F1aOs8y7FvcCJjyEsh2JEPw4I= 12=Set Global,Number,The parameter is the global variable number to set to TRUE. 13=Play Idle Anim Sequence,Number,Causes infantry units in the taskforce to play the specified idle animation. 14=Load Onto Transport,NoTypes,Instruct TaskForce members to enter a transport in the TaskForce. -15=Spy On Structure At Waypoint,Number, +15=Enter Structure At Waypoint,Number, 16=Patrol To Waypoint,Number, 17=Change To Script,Number,Instructs the task force to switch to a different script. 18=Join Team,Number,Instructs the task force to join another team type. @@ -247,13 +255,13 @@ Digest=m+F1aOs8y7FvcCJjyEsh2JEPw4I= 46=Attack Enemy Structure,BuildingTypes,Instructs the taskforce to attack a specific enemy structure. 47=Move To Enemy Structure,BuildingTypes,Instructs the taskforce to move to a specific enemy structure. 48=Scout,NoTypes,Move as far as possible in a random direction. Use this to make the AI scout the map. -49=Repeat Until Success,NoTypes,Instructs the taskforce to continually execute the previous action until it is unable to. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. +49=Register Success,NoTypes,Register success for AITrigger weight adjustment. Executing this script just once makes its AITrigger successful - used in success/failure delta calculations. 50=Flash,Number,Flashes the taskforce a number of times. 51=Play Animation,Number,Plays an animation from [Animations] in RULES.ini. 52=Display Talk Bubble,TalkBubbleTypes,Displays a talk bubble over the taskforce. -53=Gather At Enemy Base,NoTypes, -54=Regroup At Friendly Base,NoTypes, -55=Activate Iron Curtain,NoTypes,Activates the Iron Curtain on the taskforce if it is fully charged. +53=Gather At Enemy Base,NumPlusMinus, +54=Regroup At Friendly Base,NumPlusMinus, +55=Activate Iron Curtain,NumPlusMinus,Activates the Iron Curtain on the taskforce if it is fully charged. 56=Chronosphere TaskForce,BuildingTypes,Chronospheres the taskforce to a specific structure if it is almost fully charged. 57=Chronowarps TaskForce,BuildingTypes,Chronowarps the taskforce to a specific structure if it fully charged. 58=Move To Friendly Structure,BuildingTypes, diff --git a/frmMainNew.Designer.cs b/frmMainNew.Designer.cs index 2b84679..f3f2a3c 100644 --- a/frmMainNew.Designer.cs +++ b/frmMainNew.Designer.cs @@ -118,6 +118,7 @@ private void InitializeComponent() this.txtLog = new System.Windows.Forms.TextBox(); this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.aIGuideToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); this.tabControl1.SuspendLayout(); this.tabPageTF.SuspendLayout(); @@ -207,6 +208,7 @@ private void InitializeComponent() // helpToolStripMenuItem // this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.aIGuideToolStripMenuItem, this.mnuAbout}); this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); @@ -263,8 +265,8 @@ private void InitializeComponent() this.olvTF.Cursor = System.Windows.Forms.Cursors.Default; this.olvTF.FullRowSelect = true; this.olvTF.HideSelection = false; - this.olvTF.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTF.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTF.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTF.SelectedForeColor = System.Drawing.Color.Empty; this.olvTF.Location = new System.Drawing.Point(6, 6); this.olvTF.MultiSelect = false; this.olvTF.Name = "olvTF"; @@ -376,8 +378,8 @@ private void InitializeComponent() this.olvTFUnits.Cursor = System.Windows.Forms.Cursors.Default; this.olvTFUnits.FullRowSelect = true; this.olvTFUnits.HideSelection = false; - this.olvTFUnits.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTFUnits.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTFUnits.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTFUnits.SelectedForeColor = System.Drawing.Color.Empty; this.olvTFUnits.Location = new System.Drawing.Point(6, 19); this.olvTFUnits.MultiSelect = false; this.olvTFUnits.Name = "olvTFUnits"; @@ -496,8 +498,8 @@ private void InitializeComponent() this.olvST.Cursor = System.Windows.Forms.Cursors.Default; this.olvST.FullRowSelect = true; this.olvST.HideSelection = false; - this.olvST.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvST.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvST.SelectedBackColor = System.Drawing.Color.Empty; + this.olvST.SelectedForeColor = System.Drawing.Color.Empty; this.olvST.Location = new System.Drawing.Point(6, 6); this.olvST.MultiSelect = false; this.olvST.Name = "olvST"; @@ -618,8 +620,8 @@ private void InitializeComponent() this.olvSTActions.FullRowSelect = true; this.olvSTActions.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; this.olvSTActions.HideSelection = false; - this.olvSTActions.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvSTActions.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvSTActions.SelectedBackColor = System.Drawing.Color.Empty; + this.olvSTActions.SelectedForeColor = System.Drawing.Color.Empty; this.olvSTActions.Location = new System.Drawing.Point(6, 19); this.olvSTActions.MultiSelect = false; this.olvSTActions.Name = "olvSTActions"; @@ -747,8 +749,8 @@ private void InitializeComponent() this.olvTTSettings.FullRowSelect = true; this.olvTTSettings.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; this.olvTTSettings.HideSelection = false; - this.olvTTSettings.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTTSettings.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTTSettings.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTTSettings.SelectedForeColor = System.Drawing.Color.Empty; this.olvTTSettings.Location = new System.Drawing.Point(6, 19); this.olvTTSettings.MultiSelect = false; this.olvTTSettings.Name = "olvTTSettings"; @@ -804,8 +806,8 @@ private void InitializeComponent() this.olvTT.Cursor = System.Windows.Forms.Cursors.Default; this.olvTT.FullRowSelect = true; this.olvTT.HideSelection = false; - this.olvTT.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTT.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTT.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTT.SelectedForeColor = System.Drawing.Color.Empty; this.olvTT.Location = new System.Drawing.Point(6, 6); this.olvTT.MultiSelect = false; this.olvTT.Name = "olvTT"; @@ -924,8 +926,8 @@ private void InitializeComponent() this.olvTrSettings.FullRowSelect = true; this.olvTrSettings.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; this.olvTrSettings.HideSelection = false; - this.olvTrSettings.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTrSettings.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTrSettings.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTrSettings.SelectedForeColor = System.Drawing.Color.Empty; this.olvTrSettings.Location = new System.Drawing.Point(6, 19); this.olvTrSettings.MultiSelect = false; this.olvTrSettings.Name = "olvTrSettings"; @@ -977,8 +979,8 @@ private void InitializeComponent() this.olvTr.Cursor = System.Windows.Forms.Cursors.Default; this.olvTr.FullRowSelect = true; this.olvTr.HideSelection = false; - this.olvTr.HighlightBackgroundColor = System.Drawing.Color.Empty; - this.olvTr.HighlightForegroundColor = System.Drawing.Color.Empty; + this.olvTr.SelectedBackColor = System.Drawing.Color.Empty; + this.olvTr.SelectedForeColor = System.Drawing.Color.Empty; this.olvTr.Location = new System.Drawing.Point(6, 6); this.olvTr.MultiSelect = false; this.olvTr.Name = "olvTr"; @@ -1069,6 +1071,12 @@ private void InitializeComponent() // this.saveFileDialog1.Filter = "Ini files (*.ini)|*.ini"; // + // aIGuideToolStripMenuItem + // + this.aIGuideToolStripMenuItem.Name = "aIGuideToolStripMenuItem"; + this.aIGuideToolStripMenuItem.Size = new System.Drawing.Size(216, 26); + this.aIGuideToolStripMenuItem.Text = "AI Guide"; + this.aIGuideToolStripMenuItem.Click += new System.EventHandler(this.aIGuideToolStripMenuItem_Click); // frmMainNew // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1082,7 +1090,7 @@ private void InitializeComponent() this.MaximizeBox = false; this.Name = "frmMainNew"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "C&C AI Editor"; + this.Text = "C&C AI Editor " + System.Windows.Forms.Application.ProductVersion; this.menuStrip1.ResumeLayout(false); this.menuStrip1.PerformLayout(); this.tabControl1.ResumeLayout(false); @@ -1206,5 +1214,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem mnuCopyTT; private System.Windows.Forms.ToolStripMenuItem mnuCopyTr; private System.Windows.Forms.TextBox txtLog; + private System.Windows.Forms.ToolStripMenuItem aIGuideToolStripMenuItem; } } \ No newline at end of file diff --git a/frmMainNew.cs b/frmMainNew.cs index 66de867..d6684ca 100644 --- a/frmMainNew.cs +++ b/frmMainNew.cs @@ -1,955 +1,984 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Text; -using System.Windows.Forms; -using System.IO; -using System.Linq; - -namespace AIEdit -{ - using IniDictionary = Dictionary; - - public partial class frmMainNew : Form - { - public frmMainNew() - { - InitializeComponent(); - } - - public TaskForce SelectedTaskForce() - { - return olvTF.SelectedObject as TaskForce; - } - - public ScriptType SelectedScriptType() - { - return olvST.SelectedObject as ScriptType; - } - - public TeamType SelectedTeamType() - { - return olvTT.SelectedObject as TeamType; - } - - public TriggerType SelectedTriggerType() - { - return olvTr.SelectedObject as TriggerType; - } - - private void UpdateTFUnit(int mod) - { - TechnoType tt = cmbTFUnit.SelectedItem as TechnoType; - TaskForce tf = SelectedTaskForce(); - - if (tf.Mod(tt, mod) != 0) - { - olvTFUnits.SetObjects(tf); - } - else - { - TaskForceEntry tfe = tf.SingleOrDefault(s => s.Unit == tt); - olvTFUnits.RefreshObject(tfe); - } - - UpdateTFCost(); - } - - private void btnTFAddUnit_Click(object sender, EventArgs e) - { - UpdateTFUnit(1); - } - - private void btnTFDelUnit_Click(object sender, EventArgs e) - { - UpdateTFUnit(-1); - } - - private void mnuSave_Click(object sender, EventArgs e) - { - saveFileDialog1.FileName = saveFilename; - saveFileDialog1.Title = "Save AI"; - if (saveFileDialog1.ShowDialog() != DialogResult.OK) return; - saveFilename = saveFileDialog1.FileName; - WriteAI(saveFilename); - this.Text = "C&C AI Editor - " + saveFilename; - } - - /** - * Control Delegates. - **/ - - - private void mnuDelTF_Click(object sender, EventArgs e) - { - TaskForce tf = SelectedTaskForce(); - - if (tf.Uses > 0) - { - MessageBox.Show("Cannot delete Task Force while it is in use.", "Delete Task Force"); - return; - } - - DialogResult res = MessageBox.Show("Are you sure you want to delete this Task Force?", - "Delete Task Force", MessageBoxButtons.YesNo); - - if (res == DialogResult.Yes) - { - int idx = Math.Min(olvTF.SelectedIndex, olvTF.Items.Count - 1); - taskForces.Remove(tf); - olvTF.BeginUpdate(); - olvTF.RemoveObject(tf); - olvTF.EndUpdate(); - olvTF.SelectedIndex = idx; - } - } - - private void mnuNewTF_Click(object sender, EventArgs e) - { - InputBox.InputResult res = InputBox.Show("New Task Force", "Enter name:"); - - if (res.ReturnCode == DialogResult.OK) - { - string id = nextID(); - TaskForce tf = new TaskForce(id, res.Text, groupTypes[0]); - taskForces.Add(tf); - olvTF.BeginUpdate(); - olvTF.AddObject(tf); - olvTF.EndUpdate(); - olvTF.SelectedObject = tf; - olvTF.EnsureVisible(); - } - } - - private void olvTF_SelectedIndexChanged(object sender, EventArgs e) - { - TaskForce tf = SelectedTaskForce(); - if (tf == null) return; - olvTFUnits.SetObjects(tf); - olvTFUnits.SelectedIndex = 0; - cmbTFGroup.SelectedItem = tf.Group; - UpdateTFCost(); - } - - private void olvTF_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - olvTF.Sort(); - olvTF.EnsureVisible(); - } - - private void olvTFUnits_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - if (e.SubItemIndex == 1) - { - TaskForceEntry tfe = e.RowObject as TaskForceEntry; - int idx = unitTypes.TakeWhile(s => s != tfe.Unit).Count(); - - // Unit selector - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - foreach (TechnoType entry in unitTypes) cmb.Items.Add(entry); - cmb.Bounds = e.CellBounds; - cmb.SelectedIndex = idx; - e.Control = cmb; - } - } - - private void olvTFUnits_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - if(!e.Cancel && e.SubItemIndex == 1) - { - ComboBox cmb = e.Control as ComboBox; - TaskForce tf = SelectedTaskForce(); - TaskForceEntry tfe = e.RowObject as TaskForceEntry; - TechnoType unit = cmb.SelectedItem as TechnoType; - - TaskForceEntry exists = tf.SingleOrDefault(s => s.Unit == unit); - - if (exists != null && exists != tfe) - { - tf.Remove(tfe.Unit); - exists.Count = exists.Count + tfe.Count; - olvTFUnits.SetObjects(tf); - } - else - { - tfe.Unit = unit; - olvTFUnits.RefreshItem(e.ListViewItem); - } - } - } - - private void olvTFUnits_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - TaskForce tf = SelectedTaskForce(); - if (e.SubItemIndex == 0) - { - uint val = (uint)e.NewValue; - TaskForceEntry tfe = e.RowObject as TaskForceEntry; - - if (val == 0) - { - tf.Remove(tfe.Unit); - olvTFUnits.SetObjects(tf); - } - } - - UpdateTFCost(); - } - - private void olvTF_KeyDown(object sender, KeyEventArgs e) - { - switch(e.KeyCode) - { - case Keys.Insert: - mnuNewTF_Click(sender, e); - break; - case Keys.Delete: - mnuDelTF_Click(sender, e); - break; - } - } - - private void olvTFUnits_KeyDown(object sender, KeyEventArgs e) - { - if(e.KeyCode == Keys.Delete) - { - TaskForce tf = SelectedTaskForce(); - TaskForceEntry tfe = olvTFUnits.SelectedObject as TaskForceEntry; - tf.Remove(tfe.Unit); - olvTFUnits.SetObjects(tf); - e.Handled = true; - } - } - - private void cmbTFGroup_SelectionChangeCommitted(object sender, EventArgs e) - { - TaskForce tf = SelectedTaskForce(); - tf.Group = cmbTFGroup.SelectedItem as AITypeListEntry; - } - - private void olvST_SelectedIndexChanged(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - if (st == null) return; - olvSTActions.SetObjects(st); - olvSTActions.SelectedIndex = 0; - } - - private void olvSTActions_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) - { - // numbers every row - e.Item.SubItems[0].Text = e.DisplayIndex.ToString(); - } - - private void olvST_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - olvST.Sort(); - olvST.EnsureVisible(); - } - - - private void UpdateSTActionDescription() - { - ScriptAction action = olvSTActions.SelectedObject as ScriptAction; - if (action != null) txtSTActionDesc.Text = action.Action.Description; - } - - private void olvSTActions_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - ScriptAction action = e.RowObject as ScriptAction; - - // action - if (e.SubItemIndex == 1) - { - uint idx = action.Action.Code; - - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - cmb.Sorted = true; - foreach (IActionType entry in actionTypes) cmb.Items.Add(entry); - cmb.SelectedItem = action.Action; - cmb.Bounds = e.CellBounds; - e.Control = cmb; - } - // parameter - else if(e.SubItemIndex == 2) - { - if(action.Action.ParamType == ScriptParamType.Number) - { - NumericUpDown nud = new NumericUpDown(); - nud.Minimum = 0; - nud.Value = action.Param; - nud.Bounds = e.CellBounds; - e.Control = nud; - } - else - { - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - cmb.Sorted = true; - foreach (object obj in action.Action.List) cmb.Items.Add(obj); - cmb.SelectedItem = action.ParamEntry; - cmb.Bounds = e.CellBounds; - e.Control = cmb; - } - } - // offset - else if(e.SubItemIndex == 3) - { - if (action.Action.ParamType != ScriptParamType.TechnoType) - { - e.Cancel = true; - return; - } - - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - foreach (string s in ScriptAction.OffsetDescriptions()) cmb.Items.Add(s); - cmb.SelectedIndex = (int)action.Offset; - cmb.Bounds = e.CellBounds; - e.Control = cmb; - } - } - - private void olvSTActions_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - if (e.Cancel) return; - - ScriptAction action = e.RowObject as ScriptAction; - - // action - if (e.SubItemIndex == 1) - { - ComboBox cmb = e.Control as ComboBox; - e.NewValue = cmb.SelectedItem; - } - // parameter - else if(e.SubItemIndex == 2) - { - if(action.Action.ParamType == ScriptParamType.Number) - { - NumericUpDown nud = e.Control as NumericUpDown; - action.Param = (uint)nud.Value; - } - else if(action.Action.ParamType == ScriptParamType.AIObject) - { - //action.Param = - } - else - { - ComboBox cmb = e.Control as ComboBox; - action.Param = (cmb.SelectedItem as IParamListEntry).ParamListIndex; - } - - e.Cancel = true; - olvSTActions.RefreshItem(e.ListViewItem); - } - // offset - else if(e.SubItemIndex == 3) - { - ComboBox cmb = e.Control as ComboBox; - action.Offset = (uint)cmb.SelectedIndex; - e.Cancel = true; - olvSTActions.RefreshItem(e.ListViewItem); - } - } - - private void olvSTActions_SelectedIndexChanged(object sender, EventArgs e) - { - UpdateSTActionDescription(); - } - - - private void olvSTActions_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - UpdateSTActionDescription(); - } - - private void mnuNewST_Click(object sender, EventArgs e) - { - InputBox.InputResult res = InputBox.Show("New Script Type", "Enter name:"); - - if (res.ReturnCode == DialogResult.OK) - { - string id = nextID(); - ScriptType st = new ScriptType(id, res.Text); - scriptTypes.Add(st); - olvST.BeginUpdate(); - olvST.AddObject(st); - olvST.EndUpdate(); - olvST.SelectedObject = st; - olvST.EnsureVisible(); - } - } - - private void mnuDelST_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - - if (st.Uses > 0) - { - MessageBox.Show("Cannot delete Script Type while it is in use.", "Delete Script Type"); - return; - } - - DialogResult res = MessageBox.Show("Are you sure you want to delete this Script Type?", - "Delete Script Type", MessageBoxButtons.YesNo); - - if (res == DialogResult.Yes) - { - int idx = Math.Min(olvST.SelectedIndex, olvST.Items.Count - 1); - scriptTypes.Remove(st); - olvST.BeginUpdate(); - olvST.RemoveObject(st); - olvST.EndUpdate(); - olvST.SelectedIndex = idx; - } - } - - private void olvTFUnits_SelectedIndexChanged(object sender, EventArgs e) - { - TaskForceEntry tfe = olvTFUnits.SelectedObject as TaskForceEntry; - if(tfe != null) cmbTFUnit.SelectedItem = tfe.Unit; - } - - private void mnuSTActionUp_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - if (st == null) return; - int idx = st.MoveUp(olvSTActions.SelectedIndex); - olvSTActions.SetObjects(st.Actions); - olvSTActions.SelectedIndex = idx; - } - - - private void mnuSTActionDown_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - if (st == null) return; - ScriptAction a = olvSTActions.SelectedObject as ScriptAction; - int idx = st.MoveDown(olvSTActions.SelectedIndex); - olvSTActions.SetObjects(st.Actions); - olvSTActions.SelectedIndex = idx; - } - - private void mnuSTActionNew_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - if (st == null) return; - ScriptAction sa = new ScriptAction(actionTypes[0], 0); - int idx = olvSTActions.SelectedIndex; - idx = idx == -1 ? st.Actions.Count : idx + 1; - st.Insert(sa, idx); - olvSTActions.SetObjects(st.Actions); - olvSTActions.SelectedIndex = idx; - } - - - private void mnuSTActionDelete_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - if (st == null) return; - ScriptAction sa = olvSTActions.SelectedObject as ScriptAction; - int idx = olvSTActions.SelectedIndex; - if (idx == -1) return; - st.Remove(sa); - olvSTActions.SetObjects(st.Actions); - idx = Math.Min(idx, st.Count - 1); - olvSTActions.SelectedIndex = idx; - } - - private void olvSTActions_KeyDown(object sender, KeyEventArgs e) - { - switch(e.KeyCode) - { - case Keys.PageUp: - mnuSTActionUp_Click(sender, e); - e.Handled = true; - break; - case Keys.PageDown: - mnuSTActionDown_Click(sender, e); - e.Handled = true; - break; - case Keys.Insert: - mnuSTActionNew_Click(sender, e); - e.Handled = true; - break; - case Keys.Delete: - mnuSTActionDelete_Click(sender, e); - e.Handled = true; - break; - } - } - - private void olvTT_SelectedIndexChanged(object sender, EventArgs e) - { - TeamType tt = SelectedTeamType(); - olvTTSettings.PrimarySortColumn = olvColTTSort; - olvTTSettings.PrimarySortOrder = SortOrder.Ascending; - olvTTSettings.SecondarySortColumn = olvColTTName; - olvTTSettings.SecondarySortOrder = SortOrder.Ascending; - olvTTSettings.Sort(); - olvTTSettings.SetObjects(tt); - olvTTSettings.SelectedIndex = 0; - } - - private void olvTTSettings_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) - { - //e.Item.SubItems[0].Text = (e.Model as TeamTypeEntry).Option.Name; - } - - private void olvTTSettings_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - int idx = olvTTSettings.SelectedIndex; - TeamTypeOption option = (e.RowObject as TeamTypeEntry).Option; - - if(option.List != null)// (option is TeamTypeOptionAIObject) || (option is TeamTypeOptionList) ) - { - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - cmb.Sorted = option is TeamTypeOptionAIObject; - foreach(object item in option.List) cmb.Items.Add(item); - cmb.SelectedItem = e.Value; - cmb.Bounds = e.CellBounds; - e.Control = cmb; - } - } - - private void olvTTSettings_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - int idx = olvTTSettings.SelectedIndex; - TeamTypeOption option = (e.RowObject as TeamTypeEntry).Option; //teamTypeOptions[idx]; - - if(option.List != null)// ((option is TeamTypeOptionAIObject) || (option is TeamTypeOptionList)) - { - e.NewValue = (e.Control as ComboBox).SelectedItem; - } - } - - private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) - { - /* - switch(tabControl1.SelectedIndex) - { - case 0: - olvTF.RefreshObjects(taskForces.Items); - break; - case 1: - olvST.RefreshObjects(scriptTypes.Items); - break; - case 2: - olvTT.RefreshObjects(teamTypes.Items); - break; - case 3: - olvTr.RefreshObjects(triggerTypes.Items); - break; - } - */ - } - - private void mnuTTNew_Click(object sender, EventArgs e) - { - InputBox.InputResult res = InputBox.Show("New Team", "Enter name:"); - - if (res.ReturnCode == DialogResult.OK) - { - string id = nextID(); - List entries = new List(); - foreach (TeamTypeOption option in teamTypeOptions) entries.Add(option.DefaultValue); - TeamType tt = new TeamType(id, res.Text, entries); - teamTypes.Add(tt); - olvTT.BeginUpdate(); - olvTT.AddObject(tt); - olvTT.EndUpdate(); - olvTT.SelectedObject = tt; - olvTT.EnsureVisible(); - } - } - - private void mnuTTDelete_Click(object sender, EventArgs e) - { - TeamType tt = SelectedTeamType(); - - if (tt.Uses > 0) - { - MessageBox.Show("Cannot delete Team while it is in use.", "Delete Team"); - return; - } - - DialogResult res = MessageBox.Show("Are you sure you want to delete this Team?", - "Delete Trigger", MessageBoxButtons.YesNo); - - if (res == DialogResult.Yes) - { - int idx = Math.Min(olvTT.SelectedIndex, olvTT.Items.Count - 1); - teamTypes.Remove(tt); - olvTT.BeginUpdate(); - olvTT.RemoveObject(tt); - olvTT.EndUpdate(); - olvTT.SelectedIndex = idx; - } - } - - private void olvTr_SelectedIndexChanged(object sender, EventArgs e) - { - TriggerType tr = SelectedTriggerType(); - olvTrSettings.PrimarySortColumn = olvColTrSort; - olvTrSettings.PrimarySortOrder = SortOrder.Ascending; - olvTrSettings.Sort(); - olvTrSettings.SetObjects(tr); - olvTrSettings.SelectedIndex = 0; - } - - private void olvTrSettings_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - int idx = olvTrSettings.SelectedIndex; - TriggerTypeOption option = (e.RowObject as TriggerTypeEntry).Option; - - if (option.List != null) - { - ComboBox cmb = new ComboBox(); - cmb.FlatStyle = FlatStyle.Flat; - cmb.DropDownStyle = ComboBoxStyle.DropDownList; - cmb.Sorted = option is TriggerTypeOptionAIObject; - - if (option is TriggerTypeOptionAIObject) cmb.Items.Add(noneTeam); - foreach (object item in option.List) cmb.Items.Add(item); - - cmb.SelectedItem = e.Value; - cmb.Bounds = e.CellBounds; - e.Control = cmb; - } - } - - private void olvTrSettings_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - int idx = olvTrSettings.SelectedIndex; - TriggerTypeOption option = (e.RowObject as TriggerTypeEntry).Option; - - if (option.List != null) - { - e.NewValue = (e.Control as ComboBox).SelectedItem; - } - } - - private void mnuNewTr_Click(object sender, EventArgs e) - { - InputBox.InputResult res = InputBox.Show("New Trigger", "Enter name:"); - - if (res.ReturnCode == DialogResult.OK) - { - string id = nextID(); - TriggerType tr = new TriggerType(id, res.Text, triggerTypeOptions); - triggerTypes.Add(tr); - olvTr.BeginUpdate(); - olvTr.AddObject(tr); - olvTr.EndUpdate(); - olvTr.SelectedObject = tr; - olvTr.EnsureVisible(); - } - } - - private void mnuDeleteTr_Click(object sender, EventArgs e) - { - TriggerType tr = SelectedTriggerType(); - - DialogResult res = MessageBox.Show("Are you sure you want to delete this Trigger?", - "Delete Trigger", MessageBoxButtons.YesNo); - - if (res == DialogResult.Yes) - { - int idx = Math.Min(olvTr.SelectedIndex, olvTr.Items.Count - 1); - triggerTypes.Remove(tr); - olvTr.BeginUpdate(); - olvTr.RemoveObject(tr); - olvTr.EndUpdate(); - olvTr.SelectedIndex = idx; - } - } - - private void olvTr_KeyDown(object sender, KeyEventArgs e) - { - switch(e.KeyCode) - { - case Keys.Insert: - mnuNewTr_Click(sender, e); - break; - case Keys.Delete: - mnuDeleteTr_Click(sender, e); - break; - } - } - - string OpenFileDialog(string title, string filename) - { - openFileDialog1.Title = title; - openFileDialog1.FileName = filename; - - if (openFileDialog1.ShowDialog() == DialogResult.OK) - { - return openFileDialog1.FileName; - } - - return null; - } - - void LoadAI(string rulesfile, string aifile) - { - logger.Clear(); - LoadData(rulesfile, aifile); - - olvTFUnits.Items.Clear(); - olvSTActions.Items.Clear(); - olvTTSettings.Items.Clear(); - olvTrSettings.Items.Clear(); - - // cmb tf unit - cmbTFUnit.Items.Clear(); - foreach (TechnoType entry in unitTypes) cmbTFUnit.Items.Add(entry); - cmbTFUnit.SelectedIndex = 0; - - // cmb tf group - cmbTFGroup.Items.Clear(); - foreach (AITypeListEntry gt in groupTypes) cmbTFGroup.Items.Add(gt); - cmbTFGroup.SelectedIndex = 0; - - olvTF.Sort(olvColTFName, SortOrder.Ascending); - olvTF.SetObjects(taskForces.Items); - - olvST.Sort(olvColSTName, SortOrder.Ascending); - olvST.SetObjects(scriptTypes.Items); - - olvTT.Sort(olvColTTName, SortOrder.Ascending); - olvTT.SetObjects(teamTypes.Items); - - olvTr.Sort(olvColTrName, SortOrder.Ascending); - olvTr.SetObjects(triggerTypes.Items); - - txtLog.Clear(); - foreach (string s in logger) txtLog.AppendText(s + "\n"); - - if(logger.Count > 0) - { - MessageBox.Show("Possibly " + logger.Count + " error(s) while loading. See the Error Log tab for details."); - } - } - - private void mnuLoad_Click(object sender, EventArgs e) - { - string rulesfile = OpenFileDialog("Select Rules", "rules*.ini"); - if (rulesfile == null) return; - string aifile = OpenFileDialog("Select AI", "ai*.ini"); - if (aifile == null) return; - - LoadAI(rulesfile, aifile); - this.Text = "C&C AI Editor - " + aifile; - saveFilename = aifile; - tabControl1.Enabled = true; - } - - private void mnuNew_Click(object sender, EventArgs e) - { - string rulesfile = OpenFileDialog("Select Rules", "rules*.ini"); - if (rulesfile == null) return; - - LoadAI(rulesfile, "config/default.ini"); - this.Text = "C&C AI Editor"; - saveFilename = null; - tabControl1.Enabled = true; - } - - private void olvST_KeyDown(object sender, KeyEventArgs e) - { - switch(e.KeyCode) - { - case Keys.Insert: - mnuNewST_Click(sender, e); - break; - case Keys.Delete: - mnuDelST_Click(sender, e); - break; - } - } - - private void olvTT_KeyDown(object sender, KeyEventArgs e) - { - switch(e.KeyCode) - { - case Keys.Insert: - mnuTTNew_Click(sender, e); - break; - case Keys.Delete: - mnuTTDelete_Click(sender, e); - break; - } - } - - - private void mnuInfoTF_Click(object sender, EventArgs e) - { - TaskForce tf = SelectedTaskForce(); - var tts = FilterTeamTypes(tf); - object tt = UseInfoBox.Show("Used by Teams", tts); - if(tt != null) - { - tabControl1.SelectedIndex = 2; - olvTT.SelectedObject = tt; - olvTT.EnsureVisible(); - } - } - - private void mnuInfoST_Click(object sender, EventArgs e) - { - ScriptType st = SelectedScriptType(); - var tts = FilterTeamTypes(st); - object tt = UseInfoBox.Show("Used by Teams", tts); - if (tt != null) - { - tabControl1.SelectedIndex = 2; - olvTT.SelectedObject = tt; - olvTT.EnsureVisible(); - } - } - - private void mnuInfoTT_Click(object sender, EventArgs e) - { - TeamType tt = SelectedTeamType(); - var trs = from tre in triggerTypes.Items - where tre.HasTeamType(tt) - select tre; - object tr = UseInfoBox.Show("Used by Triggers", trs); - if (tr != null) - { - tabControl1.SelectedIndex = 3; - olvTr.SelectedObject = tr; - olvTr.EnsureVisible(); - } - } - - private void mnuExit_Click(object sender, EventArgs e) - { - Application.Exit(); - } - - private void mnuAbout_Click(object sender, EventArgs e) - { - string text = "C&C AI Editor v" + Application.ProductVersion + "\nDeveloped by Askeladd"; - string title = "About"; - MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Information); - } - - private void olvLog_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) - { - e.Item.SubItems[0].Text = e.Model.ToString(); - } - - public void CopyAIObject(string title, T selected, AITable aitable, BrightIdeasSoftware.ObjectListView olv) - where T:class, IAIObject - { - if (selected == null) return; - InputBox.InputResult res = InputBox.Show(title, "Enter name:", selected.Name); - if (res.ReturnCode == DialogResult.OK) - { - T newai = selected.Copy(nextID(), res.Text) as T; - aitable.Add(newai); - olv.BeginUpdate(); - olv.AddObject(newai); - olv.EndUpdate(); - olv.SelectedObject = newai; - olv.EnsureVisible(); - } - } - - private void mnuCopyTF_Click(object sender, EventArgs e) - { - CopyAIObject("Copy Task Force", SelectedTaskForce(), taskForces, olvTF); - } - - private void mnuCopyST_Click(object sender, EventArgs e) - { - CopyAIObject("Copy Script", SelectedScriptType(), scriptTypes, olvST); - } - - private void mnuCopyTT_Click(object sender, EventArgs e) - { - CopyAIObject("Copy Team", SelectedTeamType(), teamTypes, olvTT); - } - - private void mnuCopyTr_Click(object sender, EventArgs e) - { - CopyAIObject("Copy Trigger", SelectedTriggerType(), triggerTypes, olvTr); - } - - public void JumpToAIObject(IAIObject obj) - { - if (obj is TaskForce) - { - olvTF.SelectedObject = obj; - olvTF.EnsureVisible(); - tabControl1.SelectedIndex = 0; - } - else if (obj is ScriptType) - { - olvST.SelectedObject = obj; - olvST.EnsureVisible(); - tabControl1.SelectedIndex = 1; - } - else if(obj is TeamType) - { - if (obj == noneTeam) return; - olvTT.SelectedObject = obj; - olvTT.EnsureVisible(); - tabControl1.SelectedIndex = 2; - } - } - - private void olvTTSettings_MouseDoubleClick(object sender, MouseEventArgs e) - { - TeamTypeEntry entry = olvTTSettings.SelectedObject as TeamTypeEntry; - JumpToAIObject(entry.Value as IAIObject); - } - - private void olvTrSettings_MouseDoubleClick(object sender, MouseEventArgs e) - { - TriggerTypeEntry entry = olvTrSettings.SelectedObject as TriggerTypeEntry; - JumpToAIObject(entry.Value as IAIObject); - } - - private void olvNameCol_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - TextBox txt = new TextBox(); - txt.Text = e.Value as string; - txt.Bounds = e.CellBounds; - txt.SelectAll(); - e.Control = txt; - } - - private void olvNameCol_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - TextBox txt = e.Control as TextBox; - e.NewValue = txt.Text; - } - - private void olvTT_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - olvTT.Sort(); - olvTT.EnsureVisible(); - } - - private void olvTr_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) - { - olvTr.Sort(); - olvTr.EnsureVisible(); - } - } -} +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Linq; +using Microsoft.Win32; +using System.Diagnostics; + +namespace AIEdit +{ + using IniDictionary = Dictionary; + + public partial class frmMainNew : Form + { + public frmMainNew() + { + InitializeComponent(); + } + + public TaskForce SelectedTaskForce() + { + return olvTF.SelectedObject as TaskForce; + } + + public ScriptType SelectedScriptType() + { + return olvST.SelectedObject as ScriptType; + } + + public TeamType SelectedTeamType() + { + return olvTT.SelectedObject as TeamType; + } + + public TriggerType SelectedTriggerType() + { + return olvTr.SelectedObject as TriggerType; + } + + private void UpdateTFUnit(int mod) + { + TechnoType tt = cmbTFUnit.SelectedItem as TechnoType; + TaskForce tf = SelectedTaskForce(); + + if (tf.Mod(tt, mod) != 0) + { + olvTFUnits.SetObjects(tf); + } + else + { + TaskForceEntry tfe = tf.SingleOrDefault(s => s.Unit == tt); + olvTFUnits.RefreshObject(tfe); + } + + UpdateTFCost(); + } + + private void btnTFAddUnit_Click(object sender, EventArgs e) + { + UpdateTFUnit(1); + } + + private void btnTFDelUnit_Click(object sender, EventArgs e) + { + UpdateTFUnit(-1); + } + + private void mnuSave_Click(object sender, EventArgs e) + { + saveFileDialog1.FileName = saveFilename; + saveFileDialog1.Title = "Save AI"; + if (saveFileDialog1.ShowDialog() != DialogResult.OK) return; + saveFilename = saveFileDialog1.FileName; + WriteAI(saveFilename); + this.Text = "C&C AI Editor " + System.Windows.Forms.Application.ProductVersion + " - " + saveFilename; + } + + /** + * Control Delegates. + **/ + + + private void mnuDelTF_Click(object sender, EventArgs e) + { + TaskForce tf = SelectedTaskForce(); + + if (tf.Uses > 0) + { + MessageBox.Show("Cannot delete Task Force while it is in use.", "Delete Task Force"); + return; + } + + DialogResult res = MessageBox.Show("Are you sure you want to delete this Task Force?", + "Delete Task Force", MessageBoxButtons.YesNo); + + if (res == DialogResult.Yes) + { + int idx = Math.Min(olvTF.SelectedIndex, olvTF.Items.Count - 1); + taskForces.Remove(tf); + olvTF.BeginUpdate(); + olvTF.RemoveObject(tf); + olvTF.EndUpdate(); + olvTF.SelectedIndex = idx; + } + } + + private void mnuNewTF_Click(object sender, EventArgs e) + { + InputBox.InputResult res = InputBox.Show("New Task Force", "Enter name:"); + + if (res.ReturnCode == DialogResult.OK) + { + string id = nextID(); + TaskForce tf = new TaskForce(id, res.Text, groupTypes[0]); + taskForces.Add(tf); + olvTF.BeginUpdate(); + olvTF.AddObject(tf); + olvTF.EndUpdate(); + olvTF.SelectedObject = tf; + olvTF.EnsureVisible(); + } + } + + private void olvTF_SelectedIndexChanged(object sender, EventArgs e) + { + TaskForce tf = SelectedTaskForce(); + if (tf == null) return; + olvTFUnits.SetObjects(tf); + olvTFUnits.SelectedIndex = 0; + cmbTFGroup.SelectedItem = tf.Group; + UpdateTFCost(); + } + + private void olvTF_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + olvTF.Sort(); + olvTF.EnsureVisible(); + } + + private void olvTFUnits_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + if (e.SubItemIndex == 1) + { + TaskForceEntry tfe = e.RowObject as TaskForceEntry; + int idx = unitTypes.TakeWhile(s => s != tfe.Unit).Count(); + + // Unit selector + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + foreach (TechnoType entry in unitTypes) cmb.Items.Add(entry); + cmb.Bounds = e.CellBounds; + cmb.SelectedIndex = idx; + e.Control = cmb; + } + } + + private void olvTFUnits_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + if(!e.Cancel && e.SubItemIndex == 1) + { + ComboBox cmb = e.Control as ComboBox; + TaskForce tf = SelectedTaskForce(); + TaskForceEntry tfe = e.RowObject as TaskForceEntry; + TechnoType unit = cmb.SelectedItem as TechnoType; + + TaskForceEntry exists = tf.SingleOrDefault(s => s.Unit == unit); + + if (exists != null && exists != tfe) + { + tf.Remove(tfe.Unit); + exists.Count = exists.Count + tfe.Count; + olvTFUnits.SetObjects(tf); + } + else + { + tfe.Unit = unit; + olvTFUnits.RefreshItem(e.ListViewItem); + } + } + } + + private void olvTFUnits_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + TaskForce tf = SelectedTaskForce(); + if (e.SubItemIndex == 0) + { + uint val = (uint)e.NewValue; + TaskForceEntry tfe = e.RowObject as TaskForceEntry; + + if (val == 0) + { + tf.Remove(tfe.Unit); + olvTFUnits.SetObjects(tf); + } + } + + UpdateTFCost(); + } + + private void olvTF_KeyDown(object sender, KeyEventArgs e) + { + switch(e.KeyCode) + { + case Keys.Insert: + mnuNewTF_Click(sender, e); + break; + case Keys.Delete: + mnuDelTF_Click(sender, e); + break; + } + } + + private void olvTFUnits_KeyDown(object sender, KeyEventArgs e) + { + if(e.KeyCode == Keys.Delete) + { + TaskForce tf = SelectedTaskForce(); + TaskForceEntry tfe = olvTFUnits.SelectedObject as TaskForceEntry; + tf.Remove(tfe.Unit); + olvTFUnits.SetObjects(tf); + e.Handled = true; + } + } + + private void cmbTFGroup_SelectionChangeCommitted(object sender, EventArgs e) + { + TaskForce tf = SelectedTaskForce(); + tf.Group = cmbTFGroup.SelectedItem as AITypeListEntry; + } + + private void olvST_SelectedIndexChanged(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + if (st == null) return; + olvSTActions.SetObjects(st); + olvSTActions.SelectedIndex = 0; + } + + private void olvSTActions_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) + { + // numbers every row + e.Item.SubItems[0].Text = e.DisplayIndex.ToString(); + } + + private void olvST_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + olvST.Sort(); + olvST.EnsureVisible(); + } + + + private void UpdateSTActionDescription() + { + ScriptAction action = olvSTActions.SelectedObject as ScriptAction; + if (action != null) txtSTActionDesc.Text = action.Action.Description; + } + + private void olvSTActions_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + ScriptAction action = e.RowObject as ScriptAction; + + // action + if (e.SubItemIndex == 1) + { + uint idx = action.Action.Code; + + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + cmb.Sorted = true; + foreach (IActionType entry in actionTypes) cmb.Items.Add(entry); + cmb.SelectedItem = action.Action; + cmb.Bounds = e.CellBounds; + e.Control = cmb; + } + // parameter + else if(e.SubItemIndex == 2) + { + if((action.Action.ParamType == ScriptParamType.Number) || (action.Action.ParamType == ScriptParamType.NumPlusMinus)) + { + NumericUpDown nud = new NumericUpDown(); + if(action.Action.ParamType == ScriptParamType.Number) + { + nud.Minimum = 0; + } + else + { + nud.Minimum = -999999; + } + nud.Value = action.Param; + nud.Bounds = e.CellBounds; + e.Control = nud; + } + else + { + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + cmb.Sorted = true; + foreach (object obj in action.Action.List) cmb.Items.Add(obj); + cmb.SelectedItem = action.ParamEntry; + cmb.Bounds = e.CellBounds; + e.Control = cmb; + } + } + // offset + else if(e.SubItemIndex == 3) + { + if (action.Action.ParamType != ScriptParamType.TechnoType) + { + e.Cancel = true; + return; + } + + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + foreach (string s in ScriptAction.OffsetDescriptions()) cmb.Items.Add(s); + cmb.SelectedIndex = (int)action.Offset; + cmb.Bounds = e.CellBounds; + e.Control = cmb; + } + } + + private void olvSTActions_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + if (e.Cancel) return; + + ScriptAction action = e.RowObject as ScriptAction; + + // action + if (e.SubItemIndex == 1) + { + ComboBox cmb = e.Control as ComboBox; + e.NewValue = cmb.SelectedItem; + } + // parameter + else if(e.SubItemIndex == 2) + { + if((action.Action.ParamType == ScriptParamType.Number) || (action.Action.ParamType == ScriptParamType.NumPlusMinus)) + { + NumericUpDown nud = e.Control as NumericUpDown; + action.Param = (int)nud.Value; + } + else if(action.Action.ParamType == ScriptParamType.AIObject) + { + //action.Param = + } + else + { + ComboBox cmb = e.Control as ComboBox; + action.Param = (int)(cmb.SelectedItem as IParamListEntry).ParamListIndex; + } + + e.Cancel = true; + olvSTActions.RefreshItem(e.ListViewItem); + } + // offset + else if(e.SubItemIndex == 3) + { + ComboBox cmb = e.Control as ComboBox; + action.Offset = cmb.SelectedIndex; + e.Cancel = true; + olvSTActions.RefreshItem(e.ListViewItem); + } + } + + private void olvSTActions_SelectedIndexChanged(object sender, EventArgs e) + { + UpdateSTActionDescription(); + } + + + private void olvSTActions_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + UpdateSTActionDescription(); + } + + private void mnuNewST_Click(object sender, EventArgs e) + { + InputBox.InputResult res = InputBox.Show("New Script Type", "Enter name:"); + + if (res.ReturnCode == DialogResult.OK) + { + string id = nextID(); + ScriptType st = new ScriptType(id, res.Text); + scriptTypes.Add(st); + olvST.BeginUpdate(); + olvST.AddObject(st); + olvST.EndUpdate(); + olvST.SelectedObject = st; + olvST.EnsureVisible(); + } + } + + private void mnuDelST_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + + if (st.Uses > 0) + { + MessageBox.Show("Cannot delete Script Type while it is in use.", "Delete Script Type"); + return; + } + + DialogResult res = MessageBox.Show("Are you sure you want to delete this Script Type?", + "Delete Script Type", MessageBoxButtons.YesNo); + + if (res == DialogResult.Yes) + { + int idx = Math.Min(olvST.SelectedIndex, olvST.Items.Count - 1); + scriptTypes.Remove(st); + olvST.BeginUpdate(); + olvST.RemoveObject(st); + olvST.EndUpdate(); + olvST.SelectedIndex = idx; + } + } + + private void olvTFUnits_SelectedIndexChanged(object sender, EventArgs e) + { + TaskForceEntry tfe = olvTFUnits.SelectedObject as TaskForceEntry; + if(tfe != null) cmbTFUnit.SelectedItem = tfe.Unit; + } + + private void mnuSTActionUp_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + if (st == null) return; + int idx = st.MoveUp(olvSTActions.SelectedIndex); + olvSTActions.SetObjects(st.Actions); + olvSTActions.SelectedIndex = idx; + } + + + private void mnuSTActionDown_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + if (st == null) return; + ScriptAction a = olvSTActions.SelectedObject as ScriptAction; + int idx = st.MoveDown(olvSTActions.SelectedIndex); + olvSTActions.SetObjects(st.Actions); + olvSTActions.SelectedIndex = idx; + } + + private void mnuSTActionNew_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + if (st == null) return; + ScriptAction sa = new ScriptAction(actionTypes[0], 0); + int idx = olvSTActions.SelectedIndex; + idx = idx == -1 ? st.Actions.Count : idx + 1; + st.Insert(sa, idx); + olvSTActions.SetObjects(st.Actions); + olvSTActions.SelectedIndex = idx; + } + + + private void mnuSTActionDelete_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + if (st == null) return; + ScriptAction sa = olvSTActions.SelectedObject as ScriptAction; + int idx = olvSTActions.SelectedIndex; + if (idx == -1) return; + st.Remove(sa); + olvSTActions.SetObjects(st.Actions); + idx = Math.Min(idx, st.Count - 1); + olvSTActions.SelectedIndex = idx; + } + + private void olvSTActions_KeyDown(object sender, KeyEventArgs e) + { + switch(e.KeyCode) + { + case Keys.PageUp: + mnuSTActionUp_Click(sender, e); + e.Handled = true; + break; + case Keys.PageDown: + mnuSTActionDown_Click(sender, e); + e.Handled = true; + break; + case Keys.Insert: + mnuSTActionNew_Click(sender, e); + e.Handled = true; + break; + case Keys.Delete: + mnuSTActionDelete_Click(sender, e); + e.Handled = true; + break; + } + } + + private void olvTT_SelectedIndexChanged(object sender, EventArgs e) + { + TeamType tt = SelectedTeamType(); + olvTTSettings.PrimarySortColumn = olvColTTSort; + olvTTSettings.PrimarySortOrder = SortOrder.Ascending; + olvTTSettings.SecondarySortColumn = olvColTTName; + olvTTSettings.SecondarySortOrder = SortOrder.Ascending; + olvTTSettings.Sort(); + olvTTSettings.SetObjects(tt); + olvTTSettings.SelectedIndex = 0; + } + + private void olvTTSettings_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) + { + //e.Item.SubItems[0].Text = (e.Model as TeamTypeEntry).Option.Name; + } + + private void olvTTSettings_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + int idx = olvTTSettings.SelectedIndex; + TeamTypeOption option = (e.RowObject as TeamTypeEntry).Option; + + if(option.List != null)// (option is TeamTypeOptionAIObject) || (option is TeamTypeOptionList) ) + { + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + cmb.Sorted = option is TeamTypeOptionAIObject; + foreach(object item in option.List) cmb.Items.Add(item); + cmb.SelectedItem = e.Value; + cmb.Bounds = e.CellBounds; + e.Control = cmb; + } + } + + private void olvTTSettings_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + int idx = olvTTSettings.SelectedIndex; + TeamTypeOption option = (e.RowObject as TeamTypeEntry).Option; //teamTypeOptions[idx]; + + if(option.List != null)// ((option is TeamTypeOptionAIObject) || (option is TeamTypeOptionList)) + { + e.NewValue = (e.Control as ComboBox).SelectedItem; + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + /* + switch(tabControl1.SelectedIndex) + { + case 0: + olvTF.RefreshObjects(taskForces.Items); + break; + case 1: + olvST.RefreshObjects(scriptTypes.Items); + break; + case 2: + olvTT.RefreshObjects(teamTypes.Items); + break; + case 3: + olvTr.RefreshObjects(triggerTypes.Items); + break; + } + */ + } + + private void mnuTTNew_Click(object sender, EventArgs e) + { + InputBox.InputResult res = InputBox.Show("New Team", "Enter name:"); + + if (res.ReturnCode == DialogResult.OK) + { + string id = nextID(); + List entries = new List(); + foreach (TeamTypeOption option in teamTypeOptions) entries.Add(option.DefaultValue); + TeamType tt = new TeamType(id, res.Text, entries); + teamTypes.Add(tt); + olvTT.BeginUpdate(); + olvTT.AddObject(tt); + olvTT.EndUpdate(); + olvTT.SelectedObject = tt; + olvTT.EnsureVisible(); + } + } + + private void mnuTTDelete_Click(object sender, EventArgs e) + { + TeamType tt = SelectedTeamType(); + + if (tt.Uses > 0) + { + MessageBox.Show("Cannot delete Team while it is in use.", "Delete Team"); + return; + } + + DialogResult res = MessageBox.Show("Are you sure you want to delete this Team?", + "Delete Trigger", MessageBoxButtons.YesNo); + + if (res == DialogResult.Yes) + { + int idx = Math.Min(olvTT.SelectedIndex, olvTT.Items.Count - 1); + teamTypes.Remove(tt); + olvTT.BeginUpdate(); + olvTT.RemoveObject(tt); + olvTT.EndUpdate(); + olvTT.SelectedIndex = idx; + } + } + + private void olvTr_SelectedIndexChanged(object sender, EventArgs e) + { + TriggerType tr = SelectedTriggerType(); + olvTrSettings.PrimarySortColumn = olvColTrSort; + olvTrSettings.PrimarySortOrder = SortOrder.Ascending; + olvTrSettings.Sort(); + olvTrSettings.SetObjects(tr); + olvTrSettings.SelectedIndex = 0; + } + + private void olvTrSettings_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + int idx = olvTrSettings.SelectedIndex; + TriggerTypeOption option = (e.RowObject as TriggerTypeEntry).Option; + + if (option.List != null) + { + ComboBox cmb = new ComboBox(); + cmb.FlatStyle = FlatStyle.Flat; + cmb.DropDownStyle = ComboBoxStyle.DropDownList; + cmb.Sorted = option is TriggerTypeOptionAIObject; + + if (option is TriggerTypeOptionAIObject) cmb.Items.Add(noneTeam); + foreach (object item in option.List) cmb.Items.Add(item); + + cmb.SelectedItem = e.Value; + cmb.Bounds = e.CellBounds; + e.Control = cmb; + } + } + + private void olvTrSettings_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + int idx = olvTrSettings.SelectedIndex; + TriggerTypeOption option = (e.RowObject as TriggerTypeEntry).Option; + + if (option.List != null) + { + e.NewValue = (e.Control as ComboBox).SelectedItem; + } + } + + private void mnuNewTr_Click(object sender, EventArgs e) + { + InputBox.InputResult res = InputBox.Show("New Trigger", "Enter name:"); + + if (res.ReturnCode == DialogResult.OK) + { + string id = nextID(); + TriggerType tr = new TriggerType(id, res.Text, triggerTypeOptions); + triggerTypes.Add(tr); + olvTr.BeginUpdate(); + olvTr.AddObject(tr); + olvTr.EndUpdate(); + olvTr.SelectedObject = tr; + olvTr.EnsureVisible(); + } + } + + private void mnuDeleteTr_Click(object sender, EventArgs e) + { + TriggerType tr = SelectedTriggerType(); + + DialogResult res = MessageBox.Show("Are you sure you want to delete this Trigger?", + "Delete Trigger", MessageBoxButtons.YesNo); + + if (res == DialogResult.Yes) + { + int idx = Math.Min(olvTr.SelectedIndex, olvTr.Items.Count - 1); + triggerTypes.Remove(tr); + olvTr.BeginUpdate(); + olvTr.RemoveObject(tr); + olvTr.EndUpdate(); + olvTr.SelectedIndex = idx; + } + } + + private void olvTr_KeyDown(object sender, KeyEventArgs e) + { + switch(e.KeyCode) + { + case Keys.Insert: + mnuNewTr_Click(sender, e); + break; + case Keys.Delete: + mnuDeleteTr_Click(sender, e); + break; + } + } + + string OpenFileDialog(string title, string filename) + { + openFileDialog1.Title = title; + openFileDialog1.FileName = filename; + + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + return openFileDialog1.FileName; + } + + return null; + } + + void LoadAI(string rulesfile, string aifile) + { + logger.Clear(); + LoadData(rulesfile, aifile); + + olvTFUnits.Items.Clear(); + olvSTActions.Items.Clear(); + olvTTSettings.Items.Clear(); + olvTrSettings.Items.Clear(); + + // cmb tf unit + cmbTFUnit.Items.Clear(); + foreach (TechnoType entry in unitTypes) cmbTFUnit.Items.Add(entry); + cmbTFUnit.SelectedIndex = 0; + + // cmb tf group + cmbTFGroup.Items.Clear(); + foreach (AITypeListEntry gt in groupTypes) cmbTFGroup.Items.Add(gt); + cmbTFGroup.SelectedIndex = 0; + + olvTF.Sort(olvColTFName, SortOrder.Ascending); + olvTF.SetObjects(taskForces.Items); + + olvST.Sort(olvColSTName, SortOrder.Ascending); + olvST.SetObjects(scriptTypes.Items); + + olvTT.Sort(olvColTTName, SortOrder.Ascending); + olvTT.SetObjects(teamTypes.Items); + + olvTr.Sort(olvColTrName, SortOrder.Ascending); + olvTr.SetObjects(triggerTypes.Items); + + txtLog.Clear(); + foreach (string s in logger) txtLog.AppendText(s + "\n"); + + if(logger.Count > 0) + { + MessageBox.Show("Possibly " + logger.Count + " error(s) while loading. See the Error Log tab for details."); + } + } + + private void mnuLoad_Click(object sender, EventArgs e) + { + string rulesfile = OpenFileDialog("Select Rules", "rules*.ini"); + if (rulesfile == null) return; + string aifile = OpenFileDialog("Select AI", "ai*.ini"); + if (aifile == null) return; + + LoadAI(rulesfile, aifile); + this.Text = "C&C AI Editor " + System.Windows.Forms.Application.ProductVersion + " - " + aifile; + saveFilename = aifile; + tabControl1.Enabled = true; + } + + private void mnuNew_Click(object sender, EventArgs e) + { + string rulesfile = OpenFileDialog("Select Rules", "rules*.ini"); + if (rulesfile == null) return; + + LoadAI(rulesfile, "config/default.ini"); + this.Text = "C&C AI Editor " + System.Windows.Forms.Application.ProductVersion; + saveFilename = null; + tabControl1.Enabled = true; + } + + private void olvST_KeyDown(object sender, KeyEventArgs e) + { + switch(e.KeyCode) + { + case Keys.Insert: + mnuNewST_Click(sender, e); + break; + case Keys.Delete: + mnuDelST_Click(sender, e); + break; + } + } + + private void olvTT_KeyDown(object sender, KeyEventArgs e) + { + switch(e.KeyCode) + { + case Keys.Insert: + mnuTTNew_Click(sender, e); + break; + case Keys.Delete: + mnuTTDelete_Click(sender, e); + break; + } + } + + + private void mnuInfoTF_Click(object sender, EventArgs e) + { + TaskForce tf = SelectedTaskForce(); + var tts = FilterTeamTypes(tf); + object tt = UseInfoBox.Show("Used by Teams", tts); + if(tt != null) + { + tabControl1.SelectedIndex = 2; + olvTT.SelectedObject = tt; + olvTT.EnsureVisible(); + } + } + + private void mnuInfoST_Click(object sender, EventArgs e) + { + ScriptType st = SelectedScriptType(); + var tts = FilterTeamTypes(st); + object tt = UseInfoBox.Show("Used by Teams", tts); + if (tt != null) + { + tabControl1.SelectedIndex = 2; + olvTT.SelectedObject = tt; + olvTT.EnsureVisible(); + } + } + + private void mnuInfoTT_Click(object sender, EventArgs e) + { + TeamType tt = SelectedTeamType(); + var trs = from tre in triggerTypes.Items + where tre.HasTeamType(tt) + select tre; + object tr = UseInfoBox.Show("Used by Triggers", trs); + if (tr != null) + { + tabControl1.SelectedIndex = 3; + olvTr.SelectedObject = tr; + olvTr.EnsureVisible(); + } + } + + private void mnuExit_Click(object sender, EventArgs e) + { + Application.Exit(); + } + + private void mnuAbout_Click(object sender, EventArgs e) + { + string text = "C&C AI Editor v" + Application.ProductVersion + "\nDeveloped by Askeladd"; + string title = "About"; + MessageBox.Show(text, title, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + private void olvLog_FormatRow(object sender, BrightIdeasSoftware.FormatRowEventArgs e) + { + e.Item.SubItems[0].Text = e.Model.ToString(); + } + + public void CopyAIObject(string title, T selected, AITable aitable, BrightIdeasSoftware.ObjectListView olv) + where T:class, IAIObject + { + if (selected == null) return; + InputBox.InputResult res = InputBox.Show(title, "Enter name:", selected.Name); + if (res.ReturnCode == DialogResult.OK) + { + T newai = selected.Copy(nextID(), res.Text) as T; + aitable.Add(newai); + olv.BeginUpdate(); + olv.AddObject(newai); + olv.EndUpdate(); + olv.SelectedObject = newai; + olv.EnsureVisible(); + } + } + + private void mnuCopyTF_Click(object sender, EventArgs e) + { + CopyAIObject("Copy Task Force", SelectedTaskForce(), taskForces, olvTF); + } + + private void mnuCopyST_Click(object sender, EventArgs e) + { + CopyAIObject("Copy Script", SelectedScriptType(), scriptTypes, olvST); + } + + private void mnuCopyTT_Click(object sender, EventArgs e) + { + CopyAIObject("Copy Team", SelectedTeamType(), teamTypes, olvTT); + } + + private void mnuCopyTr_Click(object sender, EventArgs e) + { + CopyAIObject("Copy Trigger", SelectedTriggerType(), triggerTypes, olvTr); + } + + public void JumpToAIObject(IAIObject obj) + { + if (obj is TaskForce) + { + olvTF.SelectedObject = obj; + olvTF.EnsureVisible(); + tabControl1.SelectedIndex = 0; + } + else if (obj is ScriptType) + { + olvST.SelectedObject = obj; + olvST.EnsureVisible(); + tabControl1.SelectedIndex = 1; + } + else if(obj is TeamType) + { + if (obj == noneTeam) return; + olvTT.SelectedObject = obj; + olvTT.EnsureVisible(); + tabControl1.SelectedIndex = 2; + } + } + + private void olvTTSettings_MouseDoubleClick(object sender, MouseEventArgs e) + { + TeamTypeEntry entry = olvTTSettings.SelectedObject as TeamTypeEntry; + JumpToAIObject(entry.Value as IAIObject); + } + + private void olvTrSettings_MouseDoubleClick(object sender, MouseEventArgs e) + { + TriggerTypeEntry entry = olvTrSettings.SelectedObject as TriggerTypeEntry; + JumpToAIObject(entry.Value as IAIObject); + } + + private void olvNameCol_CellEditStarting(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + TextBox txt = new TextBox(); + txt.Text = e.Value as string; + txt.Bounds = e.CellBounds; + txt.SelectAll(); + e.Control = txt; + } + + private void olvNameCol_CellEditFinishing(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + TextBox txt = e.Control as TextBox; + e.NewValue = txt.Text; + } + + private void olvTT_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + olvTT.Sort(); + olvTT.EnsureVisible(); + } + + private void olvTr_CellEditFinished(object sender, BrightIdeasSoftware.CellEditEventArgs e) + { + olvTr.Sort(); + olvTr.EnsureVisible(); + } + + private void aIGuideToolStripMenuItem_Click(object sender, EventArgs e) + { + string key = @"HTTP\shell\open\command"; + string browser = ""; + string appPath = System.AppDomain.CurrentDomain.BaseDirectory; + string helpfile = appPath + "help\\aiguide.html"; + + using(RegistryKey regkey = Registry.ClassesRoot.OpenSubKey(key, false)) + { + browser = ((string)regkey.GetValue(null, null)).Split('"')[1]; + } + try + { + Uri uriFromPath = new System.Uri(helpfile); + string urlLocal = uriFromPath.AbsoluteUri; + Process.Start(browser, urlLocal); + } + catch (Exception ) { } + } + } +} diff --git a/frmMainNewFunctions.cs b/frmMainNewFunctions.cs index 3b1e2e1..1ac6947 100644 --- a/frmMainNewFunctions.cs +++ b/frmMainNewFunctions.cs @@ -6,7 +6,8 @@ using System.Text; using System.Windows.Forms; using System.IO; - +using System.Globalization; +using System.Text.RegularExpressions; namespace AIEdit { @@ -16,6 +17,9 @@ public partial class frmMainNew : Form { private static uint ID_BASE = 0x01000000; private uint idCounter = ID_BASE; + private string idPrefix = null; + private string idSuffix = null; + private HashSet iniIDs; // TECHNOTYPE TABLES private List unitTypes; // sorted by name @@ -50,8 +54,16 @@ public partial class frmMainNew : Form private string nextID() { - uint id = idCounter++; - return id.ToString("X8") + "-G"; + uint id; + string newID; + + do + { + id = idCounter++; + newID = idPrefix + id.ToString("X8") + idSuffix; + } while (iniIDs.Contains(newID)); + + return newID; } private void ParseTechnoTypes(List technos, IniDictionary ini, string type, string editorName) @@ -136,6 +148,10 @@ private List LoadActionTypes(IniDictionary config) if(type.CompareTo("Number") == 0) { actionType = new ActionTypeNumber(code, name, desc); + } + else if(type.CompareTo("NumPlusMinus") == 0) + { + actionType = new ActionTypeNumPlusMinus(code, name, desc); } /* else if (type.CompareTo("ScriptTypes") == 0) @@ -318,18 +334,51 @@ private void LoadData(string rulesPath, string aiPath) IniDictionary rules = IniParser.ParseToDictionary(rulesPath, logger); IniDictionary ai = IniParser.ParseToDictionary(aiPath, logger); IniDictionary config; - string configPath = "config/ts.ini"; + string appPath = ""; + string configPath = ""; + + appPath = System.AppDomain.CurrentDomain.BaseDirectory; + configPath = appPath + "config\\ts.ini"; // autodetect yr - if (rules["General"].Contains("DominatorWarhead")) configPath = "config/yr.ini"; + if (rules["General"].Contains("DominatorWarhead")) configPath = appPath + "config\\yr.ini"; // autodetect ra2 - else if( rules["General"].Contains("PrismType") ) configPath = "config/ra2.ini"; + else if( rules["General"].Contains("PrismType") ) configPath = appPath + "config\\ra2.ini"; + config = IniParser.ParseToDictionary(configPath, logger); idCounter = ID_BASE; - if (ai.ContainsKey("AIEdit")) + if (config.ContainsKey("General")) { - idCounter = uint.Parse(ai["AIEdit"]["Index"] as string); + if (config["General"].Contains("StartIndex")) + { + try + { + idCounter = uint.Parse(config["General"].GetString("StartIndex"), NumberStyles.AllowHexSpecifier); + } + catch (Exception ) + { + idCounter = ID_BASE; + } + } + + string idPrefixTemp = ""; + string idSuffixTemp = ""; + idPrefix = ""; + idSuffix = "-G"; + + if (config["General"].Contains("IDPrefix")) idPrefixTemp = config["General"].GetString("IDPrefix"); + if (config["General"].Contains("IDSuffix")) idSuffixTemp = config["General"].GetString("IDSuffix"); + if (!String.IsNullOrEmpty(idPrefixTemp)) + { + if (Regex.IsMatch(idPrefixTemp, @"^[a-zA-Z0-9_-]+$") && idPrefixTemp.Length < 16) + idPrefix = idPrefixTemp.ToUpper(); + } + if (!String.IsNullOrEmpty(idSuffixTemp)) + { + if (Regex.IsMatch(idSuffixTemp, @"^[a-zA-Z0-9_-]+$")) + idSuffix = idSuffixTemp.ToUpper(); + } } if (ai.ContainsKey("Digest")) digestString = ai["Digest"].GetString("1"); @@ -359,7 +408,8 @@ private void LoadData(string rulesPath, string aiPath) conditionTypes = LoadAITypeList(config, "Conditions"); operatorTypes = LoadAITypeList(config, "Operators"); - taskForces = LoadTaskForces(ai, technoTypes, groupTypes); + // TaskForces being 1st of the 4 types, ID duplicates accross ai(md).ini is not checked. + taskForces = LoadTaskForces(ai, technoTypes, groupTypes); scriptTypes = LoadScriptTypes(ai, actionTypes); @@ -381,6 +431,8 @@ private void LoadData(string rulesPath, string aiPath) { string id = entry.Value as string; + if (id == "") continue; + if(ids.Contains(id)) { logger.Add("Duplicate Task Force [" + id + "] found!"); @@ -399,6 +451,8 @@ private void LoadData(string rulesPath, string aiPath) ids.Add(id); } + iniIDs = new HashSet(); + iniIDs.UnionWith(ids); return new AITable("TaskForces", items); } @@ -413,9 +467,14 @@ private void LoadData(string rulesPath, string aiPath) { string id = entry.Value as string; - if (ids.Contains(id)) + if (id == "") continue; + + if (ids.Contains(id) || iniIDs.Contains(id)) { - logger.Add("Duplicate Script [" + id + "] found!"); + if (iniIDs.Contains(id)) + logger.Add("Duplicate Script [" + id + "] found in other list(s)!"); + else + logger.Add("Duplicate Script [" + id + "] found!"); continue; } @@ -430,7 +489,7 @@ private void LoadData(string rulesPath, string aiPath) items.Add(tf); ids.Add(id); } - + iniIDs.UnionWith(ids); return new AITable("ScriptTypes", items); } @@ -445,9 +504,14 @@ private void LoadData(string rulesPath, string aiPath) { string id = entry.Value as string; - if (ids.Contains(id)) + if (id == "") continue; + + if (ids.Contains(id) || iniIDs.Contains(id)) { - logger.Add("Duplicate Team [" + id + "] found!"); + if (iniIDs.Contains(id)) + logger.Add("Duplicate Team [" + id + "] found in other list(s)!"); + else + logger.Add("Duplicate Team [" + id + "] found!"); continue; } @@ -462,7 +526,7 @@ private void LoadData(string rulesPath, string aiPath) items.Add(tt); ids.Add(id); } - + iniIDs.UnionWith(ids); return new AITable("TeamTypes", items); } @@ -477,6 +541,7 @@ private AITable LoadTriggerTypes(IniDictionary ai) string id = entry.Key as string; string data = entry.Value as string; + // Vanilla TS AITrigger already contains 2 IDs same as TeamType IDs, so skipping other list check here. if (ids.Contains(id)) { logger.Add("Duplicate Trigger [" + id + "] found!"); @@ -491,7 +556,7 @@ private AITable LoadTriggerTypes(IniDictionary ai) ids.Add(id); } } - + iniIDs.UnionWith(ids); return new AITable("AITriggerTypes", items); } @@ -509,9 +574,6 @@ private void WriteAI(string path) stream.WriteLine("1=" + digestString); stream.WriteLine(); - stream.WriteLine("[AIEdit]"); - stream.WriteLine("Index=" + idCounter); - stream.Close(); } diff --git a/help/aiguide.html b/help/aiguide.html new file mode 100644 index 0000000..c756656 --- /dev/null +++ b/help/aiguide.html @@ -0,0 +1,1532 @@ + + + + + AI Guide + + +

AI Guide

+ +

Index

+ + +
+ +

AIEditor Tips:

+
    +
  • AIEditor sorts the entries and removes duplicates, it is safer to make a copy of AI(md).ini before saving and comparing the saved file for differences.
  • +
  • Instead of making new TaskForce/Script/TeamType/AITrigger, it is easier to select a similar entry on the left panel and make a copy of it. This will have the values from the copy, so need only change the desired ones on the right panel.
  • +
  • Use F2 key or left mouse button double click to rename an entry on the left panel.
  • +
+
+

Introduction

+ +

Games of Tiberian Sun, Red Alert 2 and Yuri's Revenge use scripted AI for the computer controlled players. While the rules(md).ini defines three difficulty based flags which influences the AI, the ai(md).ini defines the programming of what teams to form and what action it will perform. To do this, the ai(md).ini consists of 4 sections of TaskForces, ScriptTypes, TeamTypes and AITriggerTypes. TaskForces, ScriptTypes and TeamTypes consists of the list of their respective section IDs, where the IDs have their own sections to define individual TaskForce, ScriptType and TeamTypes. AITriggerTypes section consists of AITriggers defined in single lines. Entries in ai(md).ini are considered global which can be used in maps and maps can also have their own local TaskForces, ScriptTypes, TeamTypes and AITriggerTypes.

+
+

TaskForces

+ +

A TaskForce consists of a set of units to be created to form a team. Each TaskForce can have a maximum of 6 unit definitions which can consist of same or different types of units. Indices for these are fixed from 0 to 5. Game reads the lines indexed from 0 to 5 in ascending order and units defined in lower index are queued first for production. TaskForce section also consists of Name flag which holds a string for readable reference. Group flag can hold a number, which is used by the game only when the TeamType referencing this TaskForce has set its Group value set to -1. In ai(md).ini, it is advised to set this value to -1 only.

+ +Example : + +
+[TaskForces]
+0=05C60C4C-G
+1=0D082CFC-G
+
+[05C60C4C-G]
+Name=3 GIs, 3 Guards
+0=3,E1
+1=3,GGI
+Group=-1
+
+ +

Unit list format is defined as +

Index=UnitCount,UnitID
+Index can have values 0 to 5. UnitCount specifies the number of units of type denoted by UnitID. Valid UnitID are from the AircraftTypes, InfantryTypes and VehicleTypes list in rules(md).ini. The -G appended at the end of indices is for readability only, it doesn't have any affect or logic associated with it. Vanilla game's ai(md).ini has -G to consider it as global and entries in maps are considered as local which don't have -G appended.

+ +
+

ScriptTypes

+ +

A ScriptType consists of a set of script actions for the team to perform. Game uses only a max of first 50 script actions, the index is 0-based and is limited with 0 to 49. Script actions perform actions like attack enemy structure or move to a building or load onto transport etc. Script actions apply to all units in the team, they perform their task individually (usually units occupy different cells, so they may take different path to its target and may also choose different target) but when a script action is completed, it is synchrinized so that all units in the team move together on to execute the next script action. In cases where a target that the team is seeking for, is not found in the map, that script action is assumed as completed and the team moves on to execute its next script action. On completion of all the script actions defined in a script, the team is disbanded and units assume their default stance of guard mode.

+ +Exanple : + +
+[ScriptTypes]
+0=0C9C878C-G
+1=0CE4CC8C-G
+
+[0C9C878C-G]
+Name=Allied Refinery Guard
+0=58,1
+1=5,10
+2=58,196609
+3=5,10
+4=58,196609
+5=5,10
+6=6,1
+
+ +

Script action format is +

Index=ScriptAction,Parameter
+Index can have values from 0 to 49 in ascending order. Game is coded with various tasks to perform, those are referred here as ScriptAction. A list detailing the script action types and its parameter follows.

+ +

Script Actions

+Individual script actions are programmed to do specific action in the game. Whichever script/option is not available in Tiberian Sun is marked as (not in TS), these are available in RA2 and YR. If it is mentioned as (YR only, not in TS/RA2), then it is not available in Tiberian Sun or Red Alert 2, but is available in Yuri's Revenge only. + +

0,n = Attack Target Type, n = target type to attack
+This instructs the TeamType to use the TaskForce to approach and attack the target specified by the second parameter. These attack script actions are inherently self repeating. For example, when executing script action attack structure (0,2), the task force will attack the next structure when the current structure being attacked is destroyed and will continue to destroy enemy buildings until there are no more left. When no more target is left to attack, the script action is complete and the task force moves on to execute its next script action. The completion of this script action could get cut-short in cases the task force gets destroyed or runs out of ammo.

+ +These script actions use TargetDistanceCoefficientDefault (or overriden by TechnoType's TargetDistanceCoefficient) to determine the threat rating scan range for target selection. Vanilla value of -10 in this flag gives a range of approximately 39 cells whereas a value of -1 covers almost the entire map. When the enemy objects are within the scan range, nearest object is selected as target. When enemy objects are outside this scan range, the first object of that TargetType built by the enemy becomes the target. For Attack Anything (0,1), when the enemy objects are outside the scan range, the precedence for target selection of first built object by the enemy is given by units first, then aircrafts, then infantry and the last for buildings.

+ +The following are the target types which can be used:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterTarget TypeMeaning
0
n/aCancel attack mission
1
AnythingAnything [VehicleTypes], [AircraftTypes], [InfantryTypes] and [BuildingTypes]
2
StructuresAny enemy [BuildingTypes]
3
Ore Miners / HarvestersAny enemy [VehicleTypes] with Harvester=yes set
4
InfantryAny enemy [InfantryTypes]
5
VehiclesAny enemy [VehicleTypes]
6
FactoriesAny enemy [BuildingTypes] with a Factory= setting
7
Base DefensesAny enemy [BuildingTypes] with IsBaseDefense=yes set. In YR, also buildings defined in AlliedBaseDefenses, SovietBaseDefenses and ThirdBaseDefenses
8
Base ThreatsAny enemy objects approaching (or already in) its base and which are in an attack mission
9
Power PlantsAny enemy [BuildingTypes] with positive Power= values set
10
OccupiableAny [BuildingTypes] with CanBeOccupied=yes set (usually neutral structures) (not in TS)
11
Tech BuildingsAny [BuildingTypes] with NeedsEngineer=yes set (usually NeutralTechBuildings=) (not in TS)
+ +

NOTE: in Yuri's Revenge, Occupiable structures are defined by having CanOccupyFire=yes set instead of CanBeOccupied=yes.

+ +

1,n = Attack Waypoint, n = waypoint number to attack
+This instructs the TeamType to use the TaskForce to attack the waypoint number specified by the second parameter. If any members have Infiltrate=yes set they will enter the structure at the waypoint. Members with Engineer=yes set will capture the structure provided it does not have Capturable=no set or if it has NeedsEngineer=yes set. Members with Agent=yes set will spy on the structure if it has Spyable=yes set. Members that do not have Assaulter=no set will garrison the structure if it has CanBeOccupied=yes set. Members with C4=yes set will blow up the structure if does not have CanC4=no set. If there is no building at the specified waypoint, the TaskForce will attack the ground when reaching in range of the waypoint. Refer Waypoints for details on waypoint.

+ +

2,0 = Go Berzerk
+Forces infantry units with Cyborg=yes set to go berserk (they consider all objects, including friendly units, equally in their threat scan).(Doesn't seem to work).

+ +

3,n = Move To Waypoint, n = waypoint number to move to
+This instructs the TeamType to use the TaskForce to move to the waypoint number specified by the second parameter. Refer Waypoints for details on waypoint. TIP: you could use this script action to get a TeamType to move to Waypoint= number 99 (just about every map has this defined as the center point) - that will mean it will always strive to get to the center of the map, providing a good vantage point from which to perform further script actions and giving the impression that the computer is scouting for enemies.

+ +

4,n = Move Into Specific Celltag, n = celltag to move into
+This instructs the TeamType to use the TaskForce to move into the CellTag specified by the second parameter. This is used when you want the TeamType to trigger a specific Action (when the game tests for the CellTag being entered). CellTags are attached to cells and are used to trigger Events and thus fire Actions when that cell is entered by a unit (or any unit from the TaskForce). The CellTag parameter should be the waypoint parameter for that CellTag from the [CellTags]listing in the map file, hence this script action is only of use on specific map files. Refer CellTags for details on celltag.

+ +

5,n = Guard Area, n = time to guard area in tenths of a minute (multiples of 6 seconds)
+This instructs the TeamType to put the TaskForce into Guard Mode (same effect as selecting a group of units and pressing the Guard Mode key as defined in KEYBOARD.INI or clicking the relevant button on the Advanced Command Bar). Units will move to attack enemy units that fall within their Sight= range.

+ +

6,n = Jump To Script Action, n = line number of script action to jump to.
+ This is used to repeat actions within the ScriptType. The second parameter is the action line number of the ScriptType that you want to jump to. Script Action index starts at 0 whereas the line number starts at 1. So, to jump to the first Script Action whose index is 0, use n=6,1 for this script. Jump to line number could be specified to any of the preceding line numbers, not just to the first Script Action to create a loop of Script Actions.

+ +

7,0 = Force Player Win
+ Forces a game win condition for the owner of the TeamType (they win the game).

+ +

8,n = Unload, n = type of unloading
+ If the TaskForce contains a unit or units that have a valid Passengers= value set, and those units contain passengers, this command will make the units inside the transport(s) disembark. Note that once the passengers have disembarked, the transport itself is suspended until given a new mission and is therefore no longer considered a part of this TaskForce - this means that you cannot, for example, get units to disembark, do something, then get back into the transport in the same script. The second parameter can be used to control what happens to the transport after it 'deploys' its cargo:

+ + + + + + + + + + + + + + + + + + + + + + +
ParameterMeaning
0
Keep transports and units - all remain in the team and execute the remainder of the script
1
Keep transport and lose the units - only the transport will execute the remainder of the script
2
Lose transport and keep units - only the units will execute the remainder of the script
3
Lose transports and lose units - nothing executes the remainder of the script
+ +

9,0 = Deploy
+If the TaskForce contains a unit or units that are able to deploy (for example a unit which DeploysInto= a [BuildingType] or has any of Deployer=yes, DeployFire=yes, DeployToFire=yes set) then this action causes them to deploy at the current cell they are occupying (same effect as selecting a unit and pressing the Deploy key as defined in KEYBOARD.INI or clicking the relevant button on the Advanced Command Bar). Units that deploy into buildings doesn't remain units, so can't execute any more script actions.

+ +

10,0 = Follow friendlies
+This command causes the TaskForce to follow the nearest friendly unit when it moves although it will not function as if it is 'guarding' the unit. The following is not permanent, when the TaskForce is assigned another mission it abandons the following. TIP: If the support TeamType has this as the first line in its ScriptType, then it will escort the first TeamType.

+ +

11,n = Assign New Mission, n = new mission type
+The objects in the TaskForce are all assigned the new mission defined by the second parameter. The actions such as Sleep/Sticky/Guard/Area Guard/Hunt etc. changes the state/mission in which the units are and those remain in that state until those units are destroyed or recruited into another team and given a different command. Such actions are never completed so as to move on to execute the next script action, so these are given as the last script action in their scripts. The following are valid settings for the second parameter:

+ +For Red Alert 2/Yuri's Revenge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GameParameterActionMeaning
RA2/YR  
0
Sleepobject sits around and plays dead, will not acquire targets
RA2/YR  
1
Attackspecial attack mission used by AI team types (utilizes threat rating logic)
RA2/YR  
2
Movesimply moving to destination
RA2/YR  
3
QMovespecial move to destination after other queued moves occur
RA2/YR  
4
Retreatobject runs away (may even leave the map)
RA2/YR  
5
Guardobject sits around and will engage an enemy that falls within its weapon range
RA2/YR  
6
Stickyjust like guard mode, except the object will engage enemies but not pursue them
RA2/YR  
7
Enterenter building or transport
RA2/YR  
8
Captureengineer entry logic used by MultiEngineer
RA2/YR  
9
Eatenwhen object is being repaired (applies only to structures)
RA2/YR  
10
Harvestthe loop controlling harvesting of Ore and dumping at a Refinery
RA2/YR  
11
Area Guardguard the general area where the object starts at
RA2/YR  
12
Returnreturn to co-ordinating object (e.g. spawned object returns to the spawner)
RA2/YR  
13
Stopstop moving or firing at the first available opportunity
RA2/YR  
14
Ambushforce fire (units with Infiltrate=yes will enter target if possible)
RA2/YR  
15
Huntscan for and attack enemies wherever they may be on the map
RA2/YR  
16
Unloadwhile dropping off cargo (e.g. Landing Craft unloading passengers)
RA2/YR  
17
Sabotageunit runs to place C4 on a building or Ivan goes to place bomb on object
RA2/YR  
18
Constructionstructures use this when building up after initial placement
RA2/YR  
19
Sellingstructures use this for deconstruction after being sold
RA2/YR  
20
Repairused when repairing an object (e.g. Service Depot)
RA2/YR  
21
Rescuespecial team over-ride mission
RA2/YR  
22
MissileNuke Silo special launch missile mission
RA2/YR  
23
Harmlessobject doesn't fire and is not considered in any threat scan
RA2/YR  
24
Openwhile opening or closing a gate to allow passage
RA2/YR  
25
Patrolpatrol a series of waypoints
RA2/YR  
26
Paradrop Approachobject is approaching the paradrop site
RA2/YR  
27
Paradrop Overflyobject is flying over the paradrop site (i.e. dropping the paratroopers)
RA2/YR  
28
Waitpaused and awaiting next mission
RA2/YR  
29
Move(special duplicate) used when Chrono units are moving to destination
RA2/YR  
30
Attack(special duplicate) used when units are deployed to fire (e.g. weapons with an area fire effect)
YR
31
Spyplane Approachobject is flying towards target
YR
32
Spyplane Overflyobject is flying over the target
+
+For Tiberian Sun + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GameParameterActionMeaning
TS
0
Sleepobject sits around and plays dead, will not acquire targets
TS
1
Attackspecial attack mission used by AI team types (utilizes threat rating logic)
TS
2
Movesimply moving to destination
TS
3
QMovespecial move to destination after other queued moves occur
TS
4
Retreatobject runs away (may even leave the map)
TS
5
Guardobject sits around and will engage an enemy that falls within its weapon range
TS
6
Stickyjust like guard mode, except the object will engage enemies but not pursue them
TS
7
Enterenter building or transport
TS
8
Captureengineer entry logic used by MultiEngineer
TS
9
Harvestthe loop controlling harvesting of tiberium and dumping at a Refinery
TS
10
Area Guardguard the general area where the object starts at
TS
11
Returnreturn to co-ordinating object (e.g. spawned object returns to the spawner)
TS
12
Stopstop moving or firing at the first available opportunity
TS
13
Ambushforce fire (units with Infiltrate=yes will enter target if possible)
TS
14
Huntscan for and attack enemies wherever they may be on the map
TS
15
Unloadwhile dropping off cargo
TS
16
Sabotageunit runs to place C4 on a building
TS
17
Constructionstructures use this when building up after initial placement
TS
18
Sellingstructures use this for deconstruction after being sold
TS
19
Repairused when repairing an object (e.g. Service Depot)
TS
20
Rescuespecial team over-ride mission
TS
21
MissileNuke Silo special launch missile mission
TS
22
Harmlessobject doesn't fire and is not considered in any threat scan
TS
23
Openwhile opening or closing a gate to allow passage
TS
24
Patrolpatrol a series of waypoints
+ +

12,n = Set Global, n = global number to be set
+The global number specified in the second parameter is defined as being 'set' (it is allocated a value of '1' or 'true'). This should be employed in specific map files only. This is part of the boolean logic employed by the global variables system in the game engine.

+ +

13,n = Play Idle Anim Sequence, n = sequence number
+If the TaskForce contains a unit or units that are SHPs (i.e. infantry) then the relevant idle SHP sequence is displayed as defined by the frame numbering system in ART.INI.

+ +

14,0 = Load Onto Transport
+If the TaskForce contains a unit or units that have a valid Passengers= value set, and units whose Size= and PhysicalSize= settings allow them to be carried by that transport, this command will make the units enter the transport.

+ +

15,n = Enter Structure At Waypoint, n = waypoint number
+This instructs the TaskForce to enter the structure at the waypoint number specified by the second parameter. In RA2/YR, could be used for units with Infiltrate=yes and Agent=yes set and spy on the structure if it has Spyable=yes set. In TS, this is used for entering a building at waypoint, like engineer to enter a bridge repair hut at a given waypoint to repair that bridge.

+ +

16,n = Patrol To Waypoint, n = waypoint number
+This is similar to Move to waypoint. This instructs the TeamType to use the TaskForce to move to the waypoint number specified by the second parameter. The difference is that the units in the TaskForce will move out of their patrol route to actively go and engage any enemy objects that are within their Sight= as they move to the waypoint. NOTE: this action eats up processor time, because the TaskForce will scan for enemy objects with each movement. If you have a lot of TaskForces (or lots of units in them) engaged in this action, you will experience slowdown in the game - this is one reason why the single player missions are comparatively slow, they use this action a lot. The rate at which the scanning for targets whilst in this mission is controlled by the PatrolScan= statement in the [AI]section of RULES.INI.

+ +

17,n = Change Script, n = script number to execute
+This instructs the TaskForce to execute another ScriptType. The second parameter specifies the number of the ScriptType to execute as listed in the [ScriptTypes] table (consider the table as being numbered starting at 0 for this purpose).

+ +

18,n = Change Team, n = team number to join
+This instructs the TaskForce to join another TeamType. The second parameter specifies the number of the TeamType to join as listed in the [TeamTypes] table (consider the table as being numbered starting at 0 for this purpose). In TS, vanilla FS expansion single player maps use this a lot, so any change in the number in the list of TeamTypes, affects those mission maps.

+ +

19,0 = Panic
+If the TaskForce contains a unit or units that have Fraidycat=yes set then they will run around aimlessly, using the Panic animation from their sequence as defined in ART.INI. Normally used for the civilian units. Units that do not fulfil this criteria lie down and act as if prone.

+ +

20,n = Change House Ownership, n = house number of new owner
+Used in single player missions on specific map files only, this changes ownership of the entire TeamType to the house number specified by the second parameter.

+ +

21,0 = Scatter
+This instructs the TaskForce to scatter (same effect as selecting a group of units and pressing the Scatter key as defined in KEYBOARD.INI).

+ +

22,0 = Afraid & Run To Shroud
+This instructs the TaskForce to behave in a scared manner and it will run to the nearest shrouded cell. The TaskForce will not actively engage in combat, will not acquire targets and will not retaliate (it will scatter instead if attacked).

+ +

23,0 = Force Player Loss
+Forces a game loss condition for the owner of the TeamType (they lose the game).

+ +

24,n = Play Speech, n = number of speech to play
+This instructs the TaskForce to play one of the Sofia or EVA voices from EVA.INI (depending upon the ParentCountry= or the owner of this TaskForce). The second parameter is the number of the sound to be played from the [DialogList] in the EVA.INI file (note that you should consider this list as being numbered from 0 instead of 1 to get the correct numbering convention). In TS, it the voice clips from SPEECH.INI.

+ +

25,n = Play Sound, n = number of sound to play
+This instructs the TaskForce to play one of the generic in game sounds from the [SoundList] in the SOUND.INI file (note that for all in game Action and Trigger purposes this number is from an internal table.

+ +

26,n = Play Movie, n = number of movie to play
+This instructs the TaskForce to play one of the movies from the [Movies] list in the ART.INI file (note that for all in game Action and Trigger purposes this number is from an internal table.

+ +

27,n = Play Theme, n = number of theme to play
+This instructs the TaskForce to play one of the game soundtracks from the [Themes] list in the THEME.INI file (note that for all in game Action and Trigger purposes this number is from an internal table.

+ +

28,0 = Reduce Ore
+Reduces the amount of Ore in the cell that the TeamType is occupying. Used by the special 'weapon' that is inherent with Ore Miners.

+ +

29,0 = Begin Production
+Forces the owner of the TeamType to begin the auto-production process (the AI's behaviour in skirmish games). Should only be used on AI controlled houses.

+ +

30,0 = Force Sale
+Forces the 'fire sale' of all remaining structures owned by the House= to which the TeamType belongs.

+ +

31,0 = Suicide
+This instructs the TaskForce to destroy itself. In effect it commits suicide, usually accompanied by an explosion.

+ +

32,n = Start Weather Storm In (in TS, Ion Storm), n = number of seconds
+This initiates the Weather Storm intro effect (when the screen goes dark prior to the clouds appearing) and is set to be delayed by the number of seconds specified by parameter 2.

+ +

33,0 = End Weather Storm (in TS, Ion Storm)
+This forces an end to the Weather Storm intro effect (when the screen goes dark prior to the clouds appearing).

+ +

34,n = Center Map On Team
+This will center the screen on the TeamType. The same effect as hitting the Home key as defined in KEYBOARD.INI when the screen centers on your MCV (or the unit defined by the BaseUnit= statement in RULES.INI). The second parameter determines the speed at which the 'camera' switches view to the TaskForce with 0 being instant.

+ +

35,n = Shroud Map For Time Interval, n = time to remain shrouded
+This action will shroud the entire map except for the area around the players MCV's (if they have one). The second parameter determines the number of frames for which the map should remain shrouded (1 second = approximately 15 frames) after which the explored areas are revealed again.

+ +

36,n = Reveal Map For Time Interval, n = time to remain revealed
+This action will reveal the entire map. The second parameter determines the number of frames for which the map should remain revealed (1 second = approximately 15 frames) after which the map is shrouded again.

+ +

37,0 = Delete Team Members
+This forces dissolved members of the TaskForce to leave the map after which they are deleted (for example aerial transports after their passengers have disembarked).

+ +

38,n = Clear Global, n = Global number to be cleared
+The global number specified in the second parameter is defined as being 'clear' (it is allocated a value of '0' or 'false'). This should be employed in specific map files only in which the global variable has been defined. This is part of the boolean logic employed by the global variables system in the game engine.

+ +

39,n = Set Local, n = Local number to be set
+The local variable number specified in the second parameter is defined as being 'set' (it is allocated a value of '1' or 'true'). This should be employed in specific map files only in which the local variable has been defined. This is part of the boolean logic employed by the local variables system in the game engine.

+ +

40,n = Clear Local, n = Local number to be cleared
+The local variable number specified in the second parameter is defined as being 'cleared' (it is allocated a value of '0' or 'false'). This should be employed in specific map files only in which the local variable has been defined. This is part of the boolean logic employed by the local variables system in the game engine.

+ +

41,n = Unpanic
+If the TaskForce contains a unit or units that have Fraidycat=yes set which are currently assigned the Panic= sequence then this action nullifies that effect and the unit(s) adopt their default behaviour.

+ +

42,n = Change Facing, n = new direction to face
+This instructs the TaskForce to turn and face the new direction specified by the second parameter. The facings are as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterFacing
0
North
1
North East
2
East
3
South East
4
South
5
South West
6
West
7
North West
+ +

43,0 = Wait Until Fully Loaded
+This is always used after members of the TaskForce have entered a transport in the same TaskForce and serves two purposes. The effect of this is that the transport will be used to carry out any subsequent movement or deploy actions but after that it is no longer considered a part of this TaskForce and as such is available to be recruited into new TeamTypes. It is this action which enables use of the TransportsReturnOnUnload=yes statement in the corresponding TeamType entry. The second purpose is to flag the transport as being 'loaded' with passengers and thus is considered in the AI's targeting logic as a potential threat (see the ContentScan= entry in the RULES.INI). This action also orders the transport to wait until it is fully loaded before executing any subsequent script actions.

+ +

44,0 = Unload TRUCKB > TRUCKA
+Used purely for a graphical effect and applicable uniquely to the [TRUCKB] unit, this has the effect of converting [TRUCKB] into [TRUCKA] to give the impression that the unit has unloaded its cargo. NOTE: this is residual from Tiberian Sun and as such may not work correctly since [TRUCKA] refers to the Demo Truck image in Red Alert 2 which has no 'unloaded' image. Changing the image for the Demo Truck and assigning new units to [TRUCKA] and [TRUCKB] enables use of this logic.

+ +

45,0 = Load TRUCKA > TRUCKB
+Used purely for a graphical effect and applicable uniquely to the [TRUCKA] unit, this has the effect of converting [TRUCKA] into [TRUCKB]to give the impression that the unit has been loaded with cargo. NOTE: this is residual from Tiberian Sun and as such may not work correctly since [TRUCKA] refers to the Demo Truck image in Red Alert 2 which has no 'unloaded' image. Changing the image for the Demo Truck and assigning new units to [TRUCKA] and [TRUCKB] enables use of this logic.

+ +

46,n = Attack Enemy Structure, n = structure number (see note below)
+Members of this TaskForce attack the enemy structure specified by the second parameter. This action depends upon the type of units in the TaskForce and if certain members have Infiltrate=yes set. Members with Engineer=yes set will capture the structure provided it does not have Capturable=no set or if it has NeedsEngineer=yes set. Members with Agent=yes set will spy on the structure if it has Spyable=yes set. Members that do not have Assaulter=no set will garrison the structure if it has CanBeOccupied=yes set. Members with C4=yes set will blow up the structure if does not have CanC4=no set.

+ +

47,n = Move To Enemy Structure, n = structure number (see note below)
+Members of this TaskForce move and stay adjacent to the enemy structure specified by the second parameter.

+ +

48,0 = Scout
+Causes members of this TaskForce to move to a pre-determined point on the map in an attempt to scout an area. The effect is that the TaskForce will move in one randomly chosen direction until it is no longer able to do so which can make it very useful or a waste of time depending on the direction chosen. If you want to continually scout the map, you should loop this script action.

+ +

49,0 = Register Success For AITrigger Weight Adjustment.
+Executing this script action even once in a script by its task force is considered as a success. A script not containing this script action is a fail for its task force. A script containing this script action but the task force being unable to reach and execute this script action even once is a fail. These success and failure are used to adjust the current weight defined in AITriggers. Refer AITriggerType's weights.

+ +

50,n = Flash (visual effect), n = number of flashes
+This causes the TaskForce to 'flash', the visual effect you get on an object when you order something to attack it. The second parameter is the number of times to flash the unit 'white'.

+ +

51,n= Play Animation, n = animation number
+This instructs the TaskForce to play one of the animations from the [Animations] in the RULES.INI.INI file (note that for all in game Action and Trigger purposes this number is from an internal table).

+ +

52,n = Display Talk Bubble, n = talk bubble number
+Should be used for single-unit TaskForces only, this causes a 'talk bubble' to appear above the unit. The second parameter determines which type of talk bubble to display:

+ + + + + + + + + + + + + + + + + + + + + +
ParameterSymbolMeaning
1
*
general speech
2
?
question
3
!
shouting or statement
+ +

Note that the length of time for which the talk bubble is displayed is controlled through the TalkBubbleTime= statement in RULES.INI - refer to the RULES.INI Guide for details of this and the steps to take to enable its inclusion in Red Alert 2 as this remains residual from Tiberian Sun:Firestorm.

+ +

53,0 = Gather (at enemy base) (not in TS)
+This causes the TaskForce to gather together (sometimes used when members of the TaskForce move at different speeds and you want the faster ones to stop while the slower ones catch up) after the previous action has been executed. If the TaskForce is in an attack mission and moving towards an enemy base, this command is usually executed when the first member of the TaskForce reaches the distance from that base defined by the AISafeDistance= statement in RULES.INI.

+ +

54,0 = Regroup (at friendly base) (not in TS)
+This causes the TaskForce to regroup, if for example any of its members have become engaged in a base defense mission or strayed away whilst in guard mode, or even the TeamType itself has been suspended for whatever reason. The members regroup directly next to each other leaving no 'gaps' at the nearest available point with sufficient space, and is used, for example, prior to activating the Iron Curtain so that all applicable members are affected (i.e. they fall within its range of effect).

+ +

55,0 = Activate Iron Curtain on TaskForce (not in TS)
+If the owner of the TaskForce to which this ScriptType is attached also has the Iron Curtain fully charged then it will be fired at this TaskForce. Note that the use of the Iron Curtain in this manner depends on the percentage chance of the AI incorporating them into its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI.

+ +

56,n = ChronoSphere TaskForce (not in TS), n = structure number to be Chronoshifted to (see note below)
+If the owner of the TaskForce to which this ScriptType is attached also has the Chronosphere fully charged then it will be used on the TaskForce before moving on to the next action. Note that the use of the Chronosphere in this manner depends on the percentage chance of the AI incorporating them into its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI.

+ +

57,n = ChronoWarp TaskForce (not in TS), n = target number to be Chronoshifted to (see note below)
+If the owner of the TaskForce to which this ScriptType is attached has been Chronosphered then it will be used on the same TaskForce to shift them to the enemy structure number specified in the second parameter before moving on to the next action. Note that the use of the Chronosphere in this manner depends on the percentage chance of the AI incorporating them into its actions as defined by the AIMinorSuperReadyPercent= statement in RULES.INI.

+ +

58,n = Move To Friendly Structure (not in TS), n = structure number (see note below)
+Members of this TaskForce move and stay adjacent to the friendly structure specified by the second parameter. The structure can be one owned by the owner of the TaskForce or any of its allies.

+ +

59,n = Attack Structure At Waypoint (YR only, not in TS/RA2)
+Members of this TaskForce attack the structure at the waypoint specified by the second parameter. This action is very similar to action number 43 although this action does not test for ownership of the structure itself - thus the inclusion of this action allows, for example, InfantryTypes with Engineer=yes set to enter structures owned by the same side for the purposes of repair. This would be the most appropriate action to use to get the AI to repair bridges. Use of this also means that the TaskForce will attack the structure with one of its weapons meaning, for example, that units with C4=yes set will not C4 the building but shoot at it instead. This is useful if you want to get a TaskForce to destroy a nearby occupiable structure instead of entering it in a bid to prevent the enemy getting hold of it - a tactic used in the Yuri's Revenge AI. +

+ +

60,0 = Enter Grinder (YR only, not in TS/RA2)
+Members of this TaskForce will enter the nearest structure with Grinding=yes set if it is owned by the owner of the TaskForce or any of its allies.

+ +

61,0 = Occupy Tank Bunker (YR only, not in TS/RA2)
+Any VehicleType members of this TaskForce which do not have Bunkerable=no set will enter the nearest vacant structure with Bunker=yes set if it is owned by the owner of the TaskForce or any of its allies.

+ +

62,0 = Enter Bio Reactor (YR only, not in TS/RA2)
+Any InfantryType members of this TaskForce will enter the nearest structure with InfantryAbsorb=yes set if it is owned by the owner of the TaskForce or any of its allies and has space available.

+ +

63,0 = Occupy Battle Bunker (YR only, not in TS/RA2)
+Any InfantryType members of this TaskForce with Occupier=yes set will enter the nearest structure (which they own) with CanOccupyFire=yes set.

+ +

64,0 = Garrison Structure (YR only, not in TS/RA2)
+Any InfantryType members of this TaskForce with Occupier=yes set will enter the nearest (neutral) structure with CanOccupyFire=yes set. This action is used specifically for this purpose due to action #59 (see above) since the logic in Yuri's Revenge has changed so that the units weapon is transferred to the structure. Use of this action also allows the computer to repair those structures by sending an InfantryType with Engineer=yes set into them and also allows the AI to differentiate between attacking such a structure and entering it, which is useful if you want the AI to use infantry to destroy an occupiable structure thus preventing its enemy from using it.

+ +

Note On Structure Number

+ +

Structure number allows the AI to target a specific instance of a building. For example, if there are 5 instances of a power plant in enemy base, AI can choose one of them as target depending on its distance or threat value. By itself several instances of the same building doesn't have different threat value, but threat is cumulative. For example, if there are some units nearby a specific building, its threat rating becomes higher with the additional threat values of the nearby units.

+ +

Building index used in computation is the position of that building in the [BuildingTypes] list, counting from 0.

+ +Logic for target selection:

+ +0 + index = select building with least threat
+65536 + index = select building with highest threat
+131072 + index = select nearest building
+196608 + index = select farthest building
+ +

Reference to 262144 or higher number makes it a do nothing script action and the next action in the script, if it exists is executed.

+ +

In cases where there is only one instance of a specific building then all the four options would result in selecting the same target.

+ +

In cases where multiple instances of the building have equal threat, AI will choose the one which was constructed first by the target side. If the first was destroyed/sold etc., then next constructed building becomes target. Friendlies doesn't pose threat, so it becomes a case of equal threat.

+ +

Even though the script is specified for a team/task force, every unit in the team executes it individually. This may result in team members choosing a different building as target in cases where multiple instances of a building seem to be equidistant.

+ +
+ +

TeamTypes

+

TeamTypes section lists all the TeamType IDs available in the ai(md).ini. Maps can have their own local TeamTypes. Each TeamType is a set of attributes of a team which includes the TaskForce it forms and the ScriptType it will execute.

+ +Example : + +
+[TeamTypes]
+0=06175EFC-G
+1=0CE4CEFC-G
+
+[06175EFC-G]
+Name=Allied Base Guard - Refine
+VeteranLevel=1
+MindControlDecision=0
+Loadable=no
+Full=no
+Annoyance=no
+GuardSlower=no
+House=<none>
+Recruiter=no
+Autocreate=yes
+Prebuild=no
+Reinforce=yes
+Droppod=no
+UseTransportOrigin=no
+Whiner=yes
+LooseRecruit=no
+Aggressive=yes
+Suicide=no
+Priority=5
+Max=2
+TechLevel=0
+Group=-1
+OnTransOnly=no
+AvoidThreats=no
+IonImmune=no
+TransportsReturnOnUnload=no
+AreTeamMembersRecruitable=no
+IsBaseDefense=yes
+OnlyTargetHouseEnemy=no
+Script=0C9C878C-G
+TaskForce=05C60C4C-G
+
+ +Generic:
+ +

Name
+Name flag which holds a string for readable reference. Name strings are truncated to 23 characters maximum regardless of how long of a string you enter.

+ +

VeteranLevel
+Specifies the rank that all units in this team should have when the team is created. Only works for reinforcement-type teams (created by map trigger action #7 or #80). Accepted values are 1 for Rookie, 2 for Veteran and 3 for Elite.

+ +

TechLevel
+Minimum TechLevel needed for this team to be built. 0 is used to make it available for all tech levels. +

+ +

House
+The House this team belongs to. <none> is used to make it available to all. +

+ +

Max
+Maximum count of teams of a TeamType produced through AITriggers. -1 is unlimited. Usually when all members of a team are either destroyed or recruited into other teams then the total count of that team is decreased. Game still maintains the total count of a team even when that team has finished its script actions but the units are not yet recruited into other teams or not yet destroyed. Max count is subject to TotalAITeamCap restrictions. When teams are created through Create Team map action, Max count is not considered.

+ +

Prebuild
+Set with yes/no. If a copy of a taskforce be created before it is actually requested. (need testing)

+ +

Reinforce
+Set with yes/no. For if this team type is formed as reinforcement. Used in single player maps. The team is created and given to the house free of cost.

+ +

GuardSlower
+With yes, it increases the value of BaseDefenseDelay= (in the rules(md).ini) for this team. The team will respond slower to attacks in its base. (need testing)

+ +

Annoyance
+Set with yes/no. AI will replace any destroyed team members. (need testing) +

+ +

IsBaseDefense
+IsBaseDefense=yes on a TeamType makes it a base defense team which responds to attacks on its base. These type of teams could be produced even without AI choosing an enemy. Total of such teams is subject to the limits set by MinimumAIDefensiveTeams and MaximumAIDefensiveTeams under [General] section. This team could be chosen along with free units to protect the units with ToProtect=yes when those are under attack.

+ +

Whiner
+Set with yes/no. Used on base defense teams, to replace any destroyed team members. If Whiner=yes is set, members of the team taking any damage are treated as an attack on the AI's base and base defense operations kick in.

+ +

MindControlDecision
+Specifies what this team should do with mind-controlled enemy units. The team must have at least one unit capable of mind-controlling for this to have any effect.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ValueDescription
0
Don't use this logic
1
Recruit
2
Send to Grinder
3
Send to Bio Reactor
4
Assign to hunt
5
Do nothing
+ +

IonImmune
+Set with yes/no. On yes, team is immune to Ion Storm.

+ +

Essential:
+Script and TaskForce are essential to defining a team.

+ +

Script
+The associated ScritpType from the ScriptTypes list which gives the script actions to perform for this team.

+ +

TaskForce
+The associated TaskForce from the TaskForces list to create this team.

+ +Recruitment related: + +

During team formation the units could be recruited from the available units on the map or could be produced from factories or a combination of these two. Teams formed through AITriggers or by Create Team Map Action etc. use recruitment. Reinforcement teams are formed on the spot, so those don't use recruitment.

+ +

Game doesn't recruit units that are busy in system generated activities. Like when unit comes out of factory it still is running around and hasn't yet settled into a cell. Or unit automatically tries to regroup with its team members (not the regroup script action) before performing a script action but is still running around and hasn't yet reached its regroup destination.

+ +

When a unit belongs to a team its behavior is according to its TeamType attributes. TeamType attributes involved in recruitment are AreTeamMembersRecruitable Priority Recruiter Group and Autocreate.

+ +

AreTeamMembersRecruitable
+AreTeamMembersRecruitable=yes means that the units in this team can be recruited into other teams. When set to no the team members are not available for recruitment. When the team members finish their script actions they loose their AreTeamMembersRecruitable value and become available for recruitment into other teams.

+ +

Priority
+A TeamType with higher Priority value can recruit team members from a TeamType with lower Priority value even if the lower Priority value team hasn't yet completed its script actions. A lower Priority TeamType cannot recruit from a TeamType with higher Priority value. TeamTypes with equal Priority values cannot recruit from one another. When the team members finish their script actions they loose their Priority value and can be recruited into teams with any Priority value.

+ +

Because of the equal Priority mechanism, similar teams with same Priority don't recruit from one another and also if Max count is more than 1, the next team won't recruit from its previous team. Teams with low Priority are used as pool teams, typically doing base defense jobs and when attack teams are formed which has a higher Priority value then units get recruited from the pool teams to form the attack teams quickly.

+ +

Vanilla AI INI uses values in multiples of 4 (in TS) or 5/7 (in RA2/YR). In-between and other numbers (in 0-50) are used in single player maps which gives granular recruitment control based on the priority status.

+ +

Recruiter
+A TeamType with Recruiter=yes disregards the unit's Group value when recruiting which makes inter-Group recruitment possible. When set to no the TeamType cannot recruit units that have different group value than itself (Group=-2 teamtypes are exception).

+ +

As global AI can be enabled in maps, Recruiter=yes and Group numbers 0 to 9, -2 and -40094 (-40094 is used in TS only) which are used in vanilla SP maps should be avoided in AI INI so that unknowingly the hero units in SP maps don't get recruited into generic/global AI teams.

+ +

Group
+A unit always has a Group value whether it is in a team or not. Produced units are assigned to the group defined in its TeamType/TaskForce. Units get their Group value from its TeamType except when it has Group=-1 where they get their Group value from its task force's group. When the team members finish their script actions they still retain their group value. Group value of a unit only changes when it gets recruited into a TeamType with a different Group value. Pre-placed units on maps have their Group defined as part of their format.

+ +

Group=-1 is No Group case. Pre-placed units with Group set to -1 and units in its TeamType/TaskForce's Group set to -1 get assigned to Group=-1. Starting units Freeunits that come with buildings droppod/paradrop units units from crates escaping units from destroyed buildings etc. have their Group set to -1. AI auto-produced units like harvesters which doesn't have a TeamType/TaskForce are also assigned with Group -1.

+ +

Group=-2 is Any Group case. TeamType having Group=-2 can recruit units of any Group value even with Recruiter=no set on the recruiting team. Units with Group=-2 are like any other group other than -1.

+ +

Main usage of Group is for recruiting specific pre-placed units on maps for specific missions we call those as hero/RPG/mission units. Vanilla SP maps uses Group numbers like 0 to 9-2 and -40094 (-40094 is used in TS only) in conjunction with Recruiter=no to recruit specific pre-placed units into the specific teams.

+ +

TeamTypes produced from factories with Groups other than -1/-2 whether in SP or MP maps fail to execeute their script when Recruiter=no is used. For example vanilla TS using -40094 in AI INI are such cases. It is not clear how it is coded in the game. After coming out of the factory these units are kind of busy doing nothing and cannot be recruited further. When TeamTypes produced from factories with Group other than -1/-2 are using Recruiter=yes then such teams are able to execute its script actions and can be recruited further into other TeamTypes with same Group and are able to execute their script actions with Recruiter=no also.

+ +

Unexpected job queuing happen in some cases. Like when a first TeamType with Group other than -1 and Recruiter=no produce units from factory it fails to execute its script. A next TeamType with Group other than -1 and Recruiter=yes produces units from factory the game is unable to recruit the first team units but uses those units for the 2nd team and gives replacement for the first teams units. In such case if the 2nd team units finishes their script it executes the first team's script also after that.

+ +

Autocreate
+Autocreate in TeamTypes is used to check whether a unit should be recruited from the pre-placed unit on the map or it should be produced from a factory. This has less relevance on multiplayer/skirmish maps as it is not expected to have pre-placed units in the maps belonging to the playing house. It becomes relevant in single player maps when either the global AI is enabled or local TeamTypes are defined and there are pre-placed units on the map which can be recruited into teams for the same house.

+ +Pre-Placed unit formats on the map: + +
+[Infantry] 
+Index=Owner,ID,Health,X,Y,Sub_Cell,Mission,Facing,Tag,Veterancy,Group,High,Autocreate_no_recruitable,Autocreate_yes_recruitable 
+
+[Units] 
+Index=Owner,ID,Health,X,Y,Facing,Mission,Tag,Veterancy,Group,High,Follows_Index,Autocreate_no_recruitable,Autocreate_yes_recruitable 
+
+[Aircraft] 
+Index=Owner,ID,Health,X,Y,Facing,Mission,Tag,Veterancy,Group,Autocreate_no_recruitable,Autocreate_yes_recruitable
+
+ +

When a TeamType has Autocreate=no then the units with Autocreate_no_recruitable as 0 are not considered for recruitment. If there are units with Autocreate_no_recruitable as 1 then recruit those and form the team. If it falls short to form the team then produce remaining units from the factory to complete the team. If it fails to recruit the units on the map with Autocreate_no_recruitable as 1 because of any reason like Group mismatch along with Recruiter=no then it cannot produce replacement for such units from the factory so the team formation is interrupted.

+ +

When a TeamType has Autocreate=yes then the units with Autocreate_yes_recruitable as 0 are not considered for recruitment. If there are units with Autocreate_yes_recruitable as 1 then recruit those and form the team. If it fails to recruit available units on the map because of any reason like Group mismatch along with Recruiter=no then produce those units from the factory only when Autocreate_no_recruitable is 0 and complete the team; if in this case Autocreate_no_recruitable is 1 then can't produce from factory so team formation is interrupted. If it falls short to form the team then produce remaining units from the factory to complete the team.

+ +

Example: Consider that the concerned house has required factory (barracks/war factory etc.) and has credits to produce units. Map has 2 pre-placed units with same relevant parameters and a TeamType to be formed also requires those 2 units only. Combinations are listed as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Pre-placed Unit's GroupAutocreate_no_recruitableAutocreate_yes_recruitableTeamType's GroupAutocreateRecruiterOutcome
No needed units on mapn/an/aany numberyes/nonoProduce from factory
-100any numberyes/nonoProduce from factory
-101-1yesnoRecruit the pre-placed units
-301-1yesnoRecruitment fails, produce from factory
-101-1nonoProduce from factory
-110-1yesnoCan't produce from factory, can't recruit, team not formed
-110-1nonoRecruit the pre-placed units
-310-1nonoCan't produce from factory, recruitment fails, team not formed
-111-1yesnoRecruit the pre-placed units
-311-1yesnoCan't produce from factory, recruitment fails, team not formed
-111-1nonoRecruit the pre-placed units
-311-1nonoCan't produce from factory, recruitment fails, team not formed
+ +

In the above example with a team of 2 units, if the map has one additional pre-placed unit that can be recruited into the team successfully then also the team cannot be formed completely, so the above combinations apply. If there are 2 or more of the additional pre-placed units which can be recruited successfully then if the team formation fails in the above combinations then the team will be formed with the additional units.

+ +

FA2/FinalSun creates units with Autocreate_no_recruitable (1), Autocreate_yes_recruitable (0) by default and in TeamTypes with Autocreate=yes. When you find that the pre-placed units are not getting recruited into the expected TeamType, then uncheck the Autocreate checkbox to make it Autocreate=no.

+ +

LooseRecruits
+It doesn't seem to have any effect so don't know what it does. When the team members finish their script actions those units could be recruited immediately into other teams regardless of LooseRecruits being yes or no.

+ +Enroute/Engagement related:
+Behaviour associated with a team when a team travels towards its destination. + +

AvoidThreats
+Set with yes/no. When set to yes, the units of this team chooses a path with least threat. This is done by re-evaluating the cumulative threat posed on the paths from its current cell to its destination and then choosing the path with least threat. The re-evaluation is not done on every cell the unit travels but at regular time intervals, so faster units may travel for a few cells with old intel. +

+ +

OnlyTargetHouseEnemy
+Set with yes/no. When set to yes, the team will not attack neutral side objects.

+ +

Aggressive and Suicide
+Aggressive entry in TeamTypes pertains to initiating an attack when a threat posing enemy comes in range. Suicide entry in TeamTypes pertains to response to an attack. These can be set to yes/no. Depending on the current script action being executed and the combination of these two entries, the behavior differs. For some script actions, these two flags don't have any relevance. Variation are seen in the script actions where movement is involved. Typically, attack script actions are not affected by Aggressive entry and the team does not initiate attack while on the move to its target when the threat-posing enemy comes in range. In move script actions, Aggressive=yes favors attacking when the threat-posing enemy comes in range which results in the team losing its current script action, and when the team resumes it executes the next script action in its script. Suicide=yes tries to suppress the retaliation when attacked in favor of completing the current script action.

+ +Movement-related script action cases + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScriptActionAggressiveSuicide
Response when...
...enemy in range
...under attack
0 Attack target type
+ 1 Attack waypoint
+ 46 Attack enemy structure
+ 59 Attack structure at waypoint
yes
yes
Does not initiate attack; continues its script action.Does not respond to attack; continues the script action.
yes
no
Responds to attack and continues the script action.
no
yes
Does not respond to attack; continues the script action.
no
no
Responds to attack and continues the script action.
3 Move to waypoint
+ 47 Move to enemy structure
+ 53 Gather at enemy base
yes
yes
Does not initiate attack; continues its script action.Does not respond to attack; continues the script action.
yes
no
Abandons the current script action and attacks the enemy. Once attack is over, executes the next script action.Responds to attack. If the engagement is only response or if the enemy moves out of range, continues the current script action. If the engagement turns into an attack, it abandons the current script action. Once the attack is over, executes the next script action.
no
yes
Does not initiate attack when enemy comes in range; continues its script action.Does not respond to attack; continues the script action.
no
no
16 Patrol to waypoint
yes
yes
Attacks the enemy, then resumes the script action.Does not respond to attack; continues the script action.
yes
no
Abandons the current script action and attacks the enemy. Once attack is over, executes the next script action.Responds to attack. If the engagement is only response or if the enemy moves out of range, continues the current script action. If the engagement turns into an attack, it abandons the current script action. Once the attack is over, executes the next script action.
no
yes
Attacks the enemy, then resumes the script action.Does not respond to attack; continues the script action.
no
no
Attacks the enemy while moving to given waypoint.Moves back to retaliate. Attacks if in range, otherwise ignores the enemy. Continues the script action.
+
+ +Transport related:
+Transport related behaviour of the team. + +

Loadable
+Typically set to no. Used if the team members need to reload by docking when units run out of Ammo=. (need testing)

+ +

Full
+For use in map files with yes/no. Should any units with PipScale in the team initially be full. Applies to harvesters/weed eaters/ore miners/transport units. If the teams contains a transport and other units, the other units are placed in the transport for reinforcement purposes. (need testing)

+ +

Droppod
+Set with yes/no. Typically set to no. Whether the team arrives in droppod. (need testing).

+ +

TransportWaypoint
+Specifies the waypoint where a team type with transport and UseTransportOrigin=yes will spawn at. This tag expects a waypoint in the notation known from map actions: A = 0, B = 1, .. AA = 26. The maximum value is ZZ = 701.

+ +

UseTransportOrigin
+Specifies whether a team type with transport will spawn at the waypoint specified by TransportWaypoint. Otherwise the transport will spawn on a random cell on the owning player's edge of the map.

+ +

TransportsReturnOnUnload
+When set to yes, after the first unload script action is completed, it will send away units in the team with Passengers= value.

+ +

OnTransOnly
+Set with yes/no. Check when executing its script if it has transport load/unload script actions, otherwise end the script. When OnTransOnly=yes is used, the units won't get associated with the Tag attributes of this TeamType. (need testing)

+ +

Map related:
+Pertains to map definitions.

+ +

Tag
+Tags can be attached to many objects in maps including TeamType. Here each team member gets tagged with the associated Tag value, unless team is set with OnTransOnly=yes. +

+ +

Waypoint
+This associates the team with the given waypoint. Used in creating team at waypoint location, also used in other flags like TransportWaypoint and UseTransportOrigin. It is also considered as home cell when looking for units to recruit. +

+ +
+ +

AITriggerTypes

+As with other sections of ai(md).ini, entries in ai(md).ini are considered as global and the entries defined in maps are considered as local to the map. AITriggerTypes doesn't have separate section for list and details, but defines its AITrigger entries in single lines. AITriggers when triggered, forms the associated TeamType(s) which in turn has the TaskForce to form the team and Script to executes its activities. These AITriggers have fields for which side it belongs to, difficulty settings, conditions in which this is available for triggering. It also has weight computation to give some randomness in firing the triggers based on the previous performance of the associated teams.

+ +Example:

+[AITriggerTypes]
+0CAD0DCC-G=Allied Anti-Nuke 1 ,08DA125C-G,<all>,9,0,NAMISL,0100000003000000000000000000000000000000000000000000000000000000,70.000000,10.000000,70.000000,1,0,1,0,0CB246CC-G,0,1,1
+ +

Description of the individual fields are as follows:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Sub-string
Meaning
IDThis AITrigger's ID.
NameA plain string used as a name. Must not contain commas, will be truncated to 47 characters for internal representation.
Team1The first TeamType that will be created when this AI Trigger gets triggered.
OwnerHouseThe Country(RA2)/House(TS) that should use this AI Trigger. Defaults to <none>, can be set to an individual country's/house's name or to <all> indicating that all countries/houses of the appropriate Side can use this AI Trigger.
TechLevelMinimum TechLevel required for this AI Trigger. It is recalculated internally to be the minimum TechLevel required to build all the units in this AI Trigger's first and second TeamTypes.
ConditionTypeSpecifies a number to use as a Condition. This ConditionType along with ComparisonObject and Comparator desribed below, defines a logical comparison like "enemy house has more than 0 rhino tanks". In this example, "enemy house has this technotype" is the ConditionType, "rhino tanks" is the ComparisonObject and "more than 0" is the Comparator. See below for Condition check segment examples.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ValueMeaning
-1
No condition check, always true.
0
Enemy house owns (the technotype given in ComparisonObject)
1
Self house owns (the technotype given in ComparisonObject)
2
Enemy house in low power in yellow
3
Enemy house in low power in red
4
Enemy house has (amount of given in Comparator) credits
5
OwnerHouse has an Iron Curtain charged to at least [General] AIMinorSuperReadyPercent= percentage. (not in TS)
6
OwnerHouse has a ChronoSphere charged to at least [General] AIMinorSuperReadyPercent= percentage. (not in TS)
7
Neutral/civilian house owns (the technotype given in ComparisonObject). (The first Side with Side=Civilian set in the Countries list) (not in TS)
+
ComparisonObjectSpecifies the object that will be used as the Comparison Object. IDs of BuildingTypes, AircraftTypes, InfantryTypes and VehicleTypes are accepted here. See below for Condition check segment examples.
ComparatorDefines the comparator for the ConditionType. This sub-string is composed of eight chunks of eight hexadecimal characters each (64 characters in total). Each octet contains a textual representation of a little-endian hexadecimal number. The first operand/octet is dependant on the ConditionType (typically amount of objects owned, or credits owned). The second operand/octet is the comparison operator. The next six octets are unused. See below for Condition check segment examples.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Second OctetMeaning
00000000
Less than
01000000
Less than or equal to
02000000
Equal to
03000000
Greater than or equal to
04000000
Greater than
05000000
Not equal to
+
StartingWeightSpecifies a floating point value that will be set as this AI Trigger's Starting Weight when the game starts. See the section on Trigger Weights for more info.
MinimumWeightSpecifies a floating point value that will be interpreted as this AI Trigger's Minimum Weight. See the section on Trigger Weights for more info.
MaximumWeightSpecifies a floating point value that will be interpreted as this AI Trigger's Maximum Weight. See the section on Trigger Weights for more info.
IsForSkirmishEnables or disables this AITrigger for game modes. 0 for single player. 1 or more for skirmish and multiplayer.
UnusedUnused value always set to 0.
SideIndicates the Side that may use this AI Trigger. 0 means available for all sides. Positive value indicates the specific AI playable side. For RA2/YR, 1 for Allied, 2 for Soviet, 3 for Yuri and so on. For TS, 1 for GDI, 2 for Nod and so on.
IsBaseDefenseUnused, usually set to 0.
Team2The second TeamType that will be created when this AI Trigger is triggered.
EnabledInEasy0 means not available and 1 means available in easy difficulty.
EnabledInMedium0 means not available and 1 means available in normal difficulty.
EnabledInHard0 means not available and 1 means available in hard difficulty.
+ +

Condition Check Segment Examples

+For simplicity only the segments of ConditionType, ComparisonObject and first octet (amount) and second octet (Comparator) are shown. An octet consists of 8 bytes, 2 bytes form a word here. Values are in hexadecimal and represented in little endian format. For a decimal value of 3, its hex value is 0x3, its octet representation becomes 03000000. For a decimal value of 500, its hex value is 0x1F4, its octet representation becomes F4010000.

+ + + + + + + + + + + + + + + + + + + + + + +
SegmentMeaning
-1,<none>,0000000000000000no condition check, always true. TechnoType and the two octets are irrelevant and can hold any valid values.
0,GAREFN,0400000003000000when AI's enemy owns greater or equal to 4 allied ore refineries.
1,SHK,0300000001000000when AI's own troops has less than or equal to 3 shock troopers.
4,<none>,8813000003000000when AI's enemy has greater or equal to 5000 credits, hex value 0x1388, octet 88130000.
+ +

AITrigger Weights

+AI Triggers are given weights to define how important they are. Larger current weight makes that AI Trigger more likely to get triggered. When the game starts, the starting weight is the current weight. Later when it is recomputed, the current weight changes within the given MinimumWeight and MaximumWeight.

+ +

Each time an AI controlled TeamType is dissolved (when they complete their ScriptType or are destroyed), all AI Triggers using that TeamType as their primary (Team1) get their current weight modified:

+ +

If the Team has executed a Script Action 49, 0 in its lifetime, [General] AITriggerSuccessWeightDelta= is added to its current weight, otherwise, [General] AITriggerFailureWeightDelta= multiplied by [General] AITriggerTrackRecordCoefficient= (the former is usually negative) is added. Care is taken not to push the weight outside the limits set by MinimumWeight and MaximumWeight while doing so.

+ +

A Weight equivalent to 5000.0, triggers this AITigger as soon as its conditions are met. In RA2, it is originally used for Teams utilising minor SuperWeapons, the Iron Curtain or the ChronoSphere.

+ +

A constant weight given for StartingWeight, MinimumWeight and MaximumWeight like 50.0,50.0,50.0 is not altered by the weight computations.

+ + +
+
Version: 1.0.2 (2018.11.01)
+ + +