Difference between revisions of "Mission Scripting"

From FA Forever Wiki
Jump to navigation Jump to search
Line 376: Line 376:
* '''function UEFM1WestBaseAirAttacks()''' - Our function that we're calling from out base.
* '''function UEFM1WestBaseAirAttacks()''' - Our function that we're calling from out base.
* '''local opai = nil''' - Adds variable to our function
* '''local opai = nil''' - Adds variable to our function. Needs to be set once in each function with platoons.
* We can have some description of our attack, everything after # sign will game take as a comment
* Description of our attack, everything after '''#''' sign will game take as a comment.
* Next several lines are creating the actuall attack.
* Next several lines are creating the actual attack.
* '''opai = UEFM1WestBase:AddOpAI''' Creates function for our attack
* '''opai = UEFM1WestBase:AddOpAI''' Creates function for our attack
** '''UEFM1WestBase''' - Will define in which base will be this platoon created.
** '''UEFM1WestBase''' - Will define in which base will be this platoon created.

Revision as of 00:20, 7 June 2015


Currently there is no campaign editor for creating custom missions for Supreme Commander, but every mission is written in lua and it's easy to edit. You don't need to have too much experience with code since most of it is already used in the official campaign missions. In this tutorial I will explain how to create a mission and as an example we will use Prothyon - 16 DEMO.

Tools we need

Sources of inspiration

You can always look in one of the original campaign files to find the right code. There is a list of them. In order to open them in Map Editor, use files from this link. Maps from Forged Alliance missions couldn't be opened directly so I used only the heightmap. Its not perfect but it is enough to see how it works. Don't forget you can also look at custom map scripts for useful code snippets, some of which aren't present in the original campaign. Additionally, you can look at in game lua files, and take apart the functions there for your own uses.

It is better to look at Forged Alliance missions because the code there is simpler and easier to read and understand. Also AI was improved a lot there. So for creating AI we will use FA missions.

Map Editor sees only maps located in this folder.

C:\Program Files (x86)\THQ\Gas Powered Games\Supreme Commander\maps

All functions used in missions are defined in lua files that are in your FA installation. You can study then to find out more option you can use in your missions. They are commented and easy to understand.

Supreme Commander - Forged Alliance\gamedata\lua.scd
Supreme Commander - Forged Alliance\gamedata\mohodata.scd

How it works

Each mission is basically a map with extra files for AI. In our example we can see several files. Always name these files same as the name of the folder they're in.

  • Prothyon16_DEMO.scmap - This file is missing since map Shards was used instead.
  • Prothyon16_DEMO_m1uefai.lua - File controling UEF AI from first objective.
  • Prothyon16_DEMO_m2uefai.lua - File controling UEF AI from second objective.
  • Prothyon16_DEMO_m3uefai.lua - File controling UEF AI from third objective.
  • Prothyon16_DEMO_save.lua - Armies and markers are saved here.
  • Prothyon16_DEMO_scenario.lua - Basic information are stored here. Path to other files, mission name, armies, etc...
  • Prothyon16_DEMO_script.lua - Main file that is in control of everything.
  • Prothyon16_DEMO_strings.lua - Voice overs and taunts.

How to test missions

You can test your mission offline, which allows restarting and even saving, so its usually faster. In order to test your mission start the FAF version of FA from


You can create a shortcut on your desktop of that executable, go into its properties (right click) and change the target to include a command line switch:

ForgedAlliance.exe /init init_coop.lua
  • Make sure you have the Coop patch downloaded if its different from FAF patch - to do this simply host a coop game and close the dialog as soon as its finished patching.
  • You don't need to restart FA each time you modify a script. You can just restart the map inside FA.
  • Run FA in windowed mode and use the game log for debug. The default hotkey for showing the log window is: Ctrl + F9 (in some cases, just F9). It can be opened during the map loading screen. If you make a mistake in any of the files, the log will show you what you did wrong, giving the file and line where the error is.

Creating AI

Base template in editor

Base will be designed in Map Editor. Go to Armies tab. Create new unit group in your army. It's better to have several subgroups so you always find the right one fast.

  • Enable View - Debug - Skirts to see how much space buildings take.
  • For building placement use also Options - AutoSnap to o-grid. You need to 'shake' every building you place to be properly alligned in the grid.

With group selected, right click on map and add structures.

  • Units can be copy pasted
  • Make sure that buildings and units are in the right group.
  • Units can be rotated by holding R key and moving cursor.
  • Building can be rotated only by setting Abs Yaw in Armies tab. (0-360)
  • Units are grouped by their ID's
    • First letter indicates unit pack
      • d - Units added in one of the Supreme Commander patches
      • o - Units for objectives in Supreme Commancder
      • u - Units from Supreme Commancder
      • x - Units added in Forged Alliance
      • z - Units added in FAF
    • Second letter is faction
      • a - Aeon
      • e - UEF
      • r - Cybran
      • s - Seraphim
    • Third letter for type
      • a - Air
      • b - Base
      • c - Civilian
      • l - Land
      • o - Operation
      • s - Naval

Once you have your base ready we can move to next part which will be putting the code together.

Creating AI lua file

We need to create new lua file. Name this file same as your folder name plus specific name for this file. It's good to follow some simple format to know what this file is on the first sight. For example:

  • m1 - First mission.
  • uef - Army the AI belongs to.
  • ai - So we know its file for AI.

At the beginning of this file we will import other lua files.

This one will manage our base. Build and rebuild buildings, assembly attack platoons and send then on the field.

local BaseManager = import('/lua/ai/opai/basemanager.lua')

We will use functions from this file to give out platoons orders. Attack, patrol etc...

local SPAIFileName = '/lua/scenarioplatoonai.lua'

Next step is setting locals, here we will give index to our army, it's the same on as in script file.

local UEF = 2

Now we will create base managers to all of our bases. Every base needs it's base manager. In Prothyon there are two bases in first missions. The name of base managers doesn't matter but it's better to stick to one format. I't using similar name format as in FA missions.

  • UEF - Faction of the base
  • M1 - Mission number
  • Westbase - Name of the base
  • BaseManager.CreateBaseManager() - will call CreateBaseManager() function from file we imported at the beginning.
local UEFM1WestBase = BaseManager.CreateBaseManager()
local UEFM1EastBase = BaseManager.CreateBaseManager()


Next step is to set up specific base. This function will be called from out script file.

function UEFM1WestBaseAI()
   # ----------------
   # UEF M1 West Base
   # ----------------
   UEFM1WestBase:Initialize(ArmyBrains[UEF], 'M1_WestLand_Base', 'M1_West_Base_Marker', 40, {M1_WestBase = 100})
   UEFM1WestBase:StartNonZeroBase({8, 5})
   UEFM1WestBase:SetActive('AirScouting', true)
   UEFM1WestBase:SetActive('LandScouting', true)
   UEFM1WestBase:SetBuild('Defenses', true)

   UEFM1WestBase:AddBuildGroup('M1_WestBaseExtended', 90, false)

  • For each base we need to set several values.
  • First line initializes our base
    • ArmyBrains[UEF] - Army that will control this base
    • 'M1_WestLand_Base' - Name of out base, it can be whatever.
    • 'M1_West_Base_Marker' - Marker in save file. AI will use only factories, and send units, that are around this marker in radius we set as next.
    • 40 - Radius around our marker in game units.
    • {M1_WestBase = 100} - Name of unit group as we wrote in Map Editor / save.lua file and priority AI will rebuild buildings with.
  • Second line starts the base
    • StartNonZeroBase - Means that base will spawn, all units that are in M1_WestBase group.
      • StarEmptyBase - If you want this base to be build later by other base manager.
    • ({8, 5}) - First number is total count of engineers AI will maintain in base, second number is count of permanent assisting engineers. This means in out example there are 3 construction engineers. They are also assisting unit production if there are no more structures to build.
  • Next 3 lines will activates some base functionality that are disabled by default.
  • This base was designed so only bigger part of it is spawned (M1_WestBase) and rest is build during missions.
    • AddBuildGroup - adds group created in map editor to base manager
      • 'M1_WestBaseExtended' - Name of the group as it is in Map Editor / save.lua file.
      • 90 - priority
      • false - This means that the group will not be spawned at the beginning. Use true if you want this group spawned from the beginnig.
  • Last lines are for functions that will assembly attacks.
    • UEFM1WestBaseAirAttacks() - All air attacks in that will be build in this base.
    • All attacks could be in one function but that would be terrible mess and it would be really hard to find specific attack for you and everyone else who would be trying to learn from it.
    • You can group your attacks as your want, for example Air, Land, Naval, Drops, etc...


Now, when we have base working we want to set up attack that will be built and sent from this base. There are two way to set up platoons. We either use already existing platoon from lua files or create completely new one. For basic attacks like, group of tanks or bombers we can use the easy variation and using already created platoon. I didn't manage to get naval platoons working properly so I'm using custom ones.

Existing Platoon Templates

Files with templates we can use are located in:

Supreme Commander - Forged Alliance\gamedata\lua.scd\lua\AI\OpAI

If we want to used unit types from these files, only thing we need is to set which file to use and child type

  • AI will keep this platoon alive, this platoon will be rebuilt once every unit from it is destroyed.

There is an example of simple attack. AI will build platoon of 4 bombers and send them on patrol over selected marker chain.

function UEFM1WestBaseAirAttacks()
   local opai = nil

   # ------------------------------------
   # UEF M1 Land Base Op AI, Air Attacks
   # ------------------------------------

   # Builds platoon of 4 Bombers
   opai = UEFM1WestBase:AddOpAI('AirAttacks', 'M1_WestAirAttack1',
           MasterPlatoonFunction = {SPAIFileName, 'PatrolThread'},
           PlatoonData = {
               PatrolChain = 'M1_Land_Attack_Chain'
           Priority = 100,
   opai:SetChildQuantity('Bombers', 4)
  • function UEFM1WestBaseAirAttacks() - Our function that we're calling from out base.
  • local opai = nil - Adds variable to our function. Needs to be set once in each function with platoons.
  • Description of our attack, everything after # sign will game take as a comment.
  • Next several lines are creating the actual attack.
  • opai = UEFM1WestBase:AddOpAI Creates function for our attack
    • UEFM1WestBase - Will define in which base will be this platoon created.
    • AddOpAI - calls for the function that creates the platoon
    • 'AirAttacks' - Name of the file we use to create platoon where the template is stored.
    • 'M1_WestAirAttack1' - Our name for our platoon. Make sure you don't have two platoons with same name!
    • MasterPlatoonFunction - What should this platoon do.
      • SPAIFileName - our file with orders we imported at the beginning.
      • 'PatrolThread' - Function from the file we are going to use.
        • Most of the attacks are set as a patrol.
        • 'PatrolThread' - Patrol over the defined chain.
        • 'PatrolChainPickerThread' - Randomly picks one chain from out table of chains.
        • 'RandomDefensePatrolThread' - Assign random patrol route for each unit from platoon using defined chain.
    • PlatoonData - Table with data that our function requires.
      • PatrolChain = 'M1_Land_Attack_Chain' - Name of our chain as it is in Map Editor / save.lua file.
        • If we are using PatrolChainPickerThread function, we need to give more chains in a table.
        • Make sure you change PatrolChain to PatrolChains
    • Priority = 100 - Platoons with higher priority will be build first, obviously.
  • opai:SetChildQuantity('Bombers', 4) - Type and number of units we want to be built.
    • There can be more unit types at once.
    • opai:SetChildQuantity({'Bombers', 'Interceptors'}, 8) - Platoon of 4 Bombers and 4 Interceptors

We can also add build condition. In this example, platoon will be built only if player has more than 20 air mobile units.

opai:AddBuildCondition('/lua/editor/otherarmyunitcountbuildconditions.lua', 'BrainGreaterThanOrEqualNumCategory',
       {'default_brain', 'Player', 20, categories.ALLUNITS * categories.MOBILE})
  • '/lua/editor/otherarmyunitcountbuildconditions.lua' - path to file with build condition
  • 'BrainGreaterThanOrEqualNumCategory' - when is this condition met
  • 'default_brain' - our AI army
  • 'Player' - target army
  • 20 - number of units
  • categories.ALLUNITS * categories.MOBILE - units we're looking for

Lua files with all build conditins available are in this folder:

Supreme Commander - Forged Alliance\gamedata\lua.scd\lua\editor

Custom Unit Platoons

In our custom template we can set as many unit types and unit count as we want. We will need to know ID's of the units so Unit Database will come in handy.

   Temp = {
       { 'ues0201', 1, 4, 'Attack', 'GrowthFormation' },   # Destroyers
       { 'ues0202', 1, 2, 'Attack', 'GrowthFormation' },   # Cruisers
       { 'xes0205', 1, 2, 'Attack', 'GrowthFormation' },   # Shield Boat
   Builder = {
       BuilderName = 'NavyAttackBuilder2',
       PlatoonTemplate = Temp,
       InstanceCount = 1,
       Priority = 400,
       PlatoonType = 'Sea',
       RequiresConstruction = true,
       LocationType = 'SouthNavalBase',
       BuildConditions = {
           { '/lua/editor/otherarmyunitcountbuildconditions.lua', 'BrainGreaterThanOrEqualNumCategory',
       {'default_brain', 'Player', 20, categories.NAVAL * categories.MOBILE + categories.uel0203}},
       PlatoonAIFunction = {SPAIFileName, 'PatrolChainPickerThread'},     
       PlatoonData = {
           PatrolChains = {'M3_Air_Base_NavalAttack_Chain2', 'M3_Air_Base_NavalAttack_Chain4'}
   ArmyBrains[UEF]:PBMAddPlatoon( Builder )
  • If this is our first custom template in function then we need to put local = in front of Temp and Builder
  • Temp = {} - Our custom template.
    • 'NavalAttackTemp2' - Name of our template, make sure it's unique in your mission!
    • 'NoPlan' - We will specify what platoon will do few lines below.
    • { 'ues0201', 1, 4, 'Attack', 'GrowthFormation' }, # Destroyers - table for one unit
      • 'ues0201' - Unit ID
      • 1 -
      • 4 - Number of units to be built
      • 'Attack' -
      • 'GrowthFormation' - There are 2 formations used in FA, this one is more compact. AttackFormation is more wide open.
      • # Destroyers - Note to keep track on units.
  • Builder = {} - This will build our template.
    • BuilderName = 'NavyAttackBuilder2' - Name of our builder, make sure it's unique in your mission!
    • PlatoonTemplate = Temp - Using template we created few lines above.
    • InstanceCount = 1 - How many of these platoon we want.
    • PlatoonType = 'Sea' - Specify factory type that this template should be sent it.
      • Other types are Land, Air, Gate
    • RequiresConstruction = true, - True since we need to platoon to be built by AI.
    • LocationType = 'SouthNavalBase' - Name of our base as it is in Map Editor / save.lua file.
    • BuildConditions - This is optional if we want the platoon to be built only if certain conditions are met.




















Supported Objective Types:

  • Kill
  • Capture
  • KillOrCapture
  • Reclaim
  • Locate
  • SpecificUnitsInArea
  • CategoriesInArea
  • ArmyStatCompare
  • UnitStatCompare
  • CategoryStatCompare
  • Protect
  • Timer
  • Unknown
  • Camera
  • Basic
ACU Upgrades
Aeon.pngAeon Cybran.pngCybran Uef.pngUEF Seraphim.pngSeraphim
  • AdvancedEngineering
  • T3Engineering
  • ChronoDampener
  • CrysalisBeam (Range)
  • EnhancedSensors
  • HeatSink (Fire Rate)
  • ResourceAllocationAdvanced
  • Shield
  • ShieldHeavy
  • ResourceAllocation
  • Teleporter
  • AdvancedEngineering
  • T3Engineering
  • CloakingGenerator
  • CoolingUpgrade (Gun)
  • MicrowaveLaserGenerator
  • NaniteTorpedoTube
  • StealthGenerator
  • ResourceAllocation
  • Teleporter
  • AdvancedEngineering
  • T3Engineering
  • DamageStabilization (Nano)
  • HeavyAntiMatterCannon (Gun)
  • LeftPod
  • RightPod
  • Shield
  • ShieldGeneratorField
  • TacticalMissile
  • TacticalNukeMissile
  • ResourceAllocation
  • Teleporter
  • AdvancedEngineering
  • T3Engineering
  • AdvancedRegenAura
  • BlastAttack (Splash Gun)
  • DamageStabilization (Nano)
  • DamageStabilizationAdvanced
  • Missile
  • RateOfFire (Gun)
  • RegenAura
  • ResourceAllocationAdvanced
  • ResourceAllocation
  • Teleporter
sACU Upgrades
Aeon.pngAeon Cybran.pngCybran Uef.pngUEF Seraphim.pngSeraphim
  • EngineeringFocusingModule
  • ResourceAllocation
  • Shield
  • ShieldHeavy
  • StabilitySuppressant (Gun)
  • SystemIntegrityCompensator (Nano)
  • Sacrifice
  • Teleporter
  • CloakingGenerator
  • EMPCharge
  • FocusConverter (Gun)
  • NaniteMissileSystem (AA)
  • ResourceAllocation
  • SelfRepairSystem
  • StealthGenerator
  • SwitchBack (Engineering)
  • AdvancedCoolingUpgrade (Rate of Fire)
  • HighExplosiveOrdnance (Splash)
  • Pod
  • RadarJammer
  • ResourceAllocation
  • SensorRangeEnhancer
  • ShieldGeneratorField
  • Shield
  • DamageStabilization (Nano)
  • EngineeringThroughput
  • EnhancedSensors
  • Missile
  • Overcharge
  • Shield
  • Teleporter