Mission Scripting

From FA Forever Wiki
Revision as of 19:24, 6 June 2015 by Speed2 (talk | contribs) (First part of this mega mission tutorial, still needs more than lot of love.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


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

Source 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 heightmap. Its not perfect but it is enough to see how it works.

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

Original Missions
Campaign Folder Name Mission Name
FA X1CA_001 Black Day
FA X1CA_002 Dawn
FA X1CA_003 Red Flag
FA X1CA_004 Meltdown
FA X1CA_005 Mind Games
FA X1CA_006 Overlord
Aeon SCCA_A01 Jous
Aeon SCCA_A02 Machine Purge
Aeon SCCA_A03 High Tide
Aeon SCCA_A04 Operation Entity
Aeon SCCA_A05 Shining Star
Aeon SCCA_A06 Beginnings
UEF SCCA_E01 Black Earth
UEF SCCA_E02 Snow Blind
UEF SCCA_E03 Metal Shark
UEF SCCA_E04 Vacinne
UEF SCCA_E05 Forge
UEF SCCA_E06 Stone Wall
Cybran SCCA_R01 Liberation
Cybran SCCA_R02 Artifact
Cybran SCCA_R03 Defrag
Cybran SCCA_R04 Mainframe Tango
Cybran SCCA_R05 Unlock
Cybran SCCA_R06 Freedom

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 map with extra files for AI. On 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 mission

Missions can be tested offline. In order to test your mission start FA from



ForgedAlliance.exe /init init_coop.lua
  • Make sure you have Coop patch downloaded if its different from FAF patch.
  • 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 game log for debug. Default hotkey for log is Ctrl + F9. It can be opened during map loading screen. If you do mistake in any of the files, log will show you what you did wrong, 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.

Creating AI lua file

We need to create new lua file. Name this file same as your folder name plus specifix name for this file. It's good to follow some simple format to know what this file is on 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. 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.
Available Templates
File Child
AirAttacks Interceptors
AirAttacks Bombers
AirAttacks Gunships
AirAttacks CombatFighters
AirAttacks TorpedoBombers
AirAttacks AirSuperiority
AirAttacks StratBombers
AirAttacks HeavyGunships
BasicLandAttack LightBots
BasicLandAttack LightTanks
BasicLandAttack LightArtillery
BasicLandAttack MobileAntiAir
BasicLandAttack HeavyTanks
BasicLandAttack AmphibiousTanks
BasicLandAttack MobileBombs
BasicLandAttack MobileFlak
BasicLandAttack MobileMissiles
BasicLandAttack MobileShields
BasicLandAttack MobileStealth
BasicLandAttack SiegeBots
BasicLandAttack HeavyBots
BasicLandAttack MobileHeavyArtillery
BasicLandAttack MobileMissilePlatforms
EngineerAttack T1Transports
EngineerAttack T2Transports
EngineerAttack T3Transports
EngineerAttack T1Engineers
EngineerAttack T2Engineers
EngineerAttack T3Engineers

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
  • We can have some description of our attack, everything after # sign will game take as a comment
  • Next several lines are creating the actuall 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