Difference between revisions of "Mission Scripting"

From FA Forever Wiki
Jump to: navigation, search
m (Scenario)
m (How to test missions)
Line 144: Line 144:
 
* 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.
 
* 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.
 
* 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.
+
* 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.
  
 
== Scenario ==
 
== Scenario ==

Revision as of 08:58, 7 June 2015

Introduction

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

C:\ProgramData\FAForever\bin\

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.

Scenario

This file contains basic information about map. Name, path to other files, armies, etc. It is created with map, once you save your map. You can edit these information.

  • name = - Name of your map that will be displayed in game lobby.
  • description = - Description of your map that will be displayed in game lobby.
  • type = - Change this value to campaign_coop.
  • preview = - Keep this empty to have working map preview in FAF lobby.
  • size = {} - Size of the map, do not change it.
  • map = - Path to map file.
  • save = - Path to save file.
  • script = - Path to script file.
  • norushradius = 0.000000 - Keep this value at 0
  • norushoffsetX_Player = 0.000000 - Each army has to have this value
  • norushoffsetY_Player = 0.000000 - Each army has to have this value

All armies have to be listed here. This part is created once Games configuration is set in Map Editor. Coop armies are the last ones. Example:

Configurations = {
       ['standard'] = {
           teams = {
               { name = 'FFA', armies = {'Player','UEF','UEFAlly','Objective','Seraphim','Coop1','Coop2','Coop3',} },
           },
           customprops = {
           },
       },
   }}

Script

Creating AI

Campaign AI is different from skirmish AI. Everything that AI will do is scripted, from base design, expantions to every attack platoon. Each army AI has it's own file for every mission unless it survives to another mission. In that case, platoons will get different orders in each mission.

Things to do in Map Editor

We need to use Map Editor to design base and set up markers and chains AI will use. Lets start with base template

Base template

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

Markers and Chains

Base Markers
Rally point on the left and Base Marker in the middle.

Each base requires two markers to work and at other more for sending units. There are two marker types we are going to use. Rally Point and Blank Marker.

Base Marker

First thing to to is to set up Base Marker around which the base will be defined.

  • AI will use factories and units only in radius around this marker.
  • Go to Markers layer and place Blank Marker in the middle of your base.
    • It's highly recommended to rename your markers to keep track on them. In our case: M1_West_Base_Marker.
    • Radius of base markers should not be overlapping!
Rally Point

Another one is Rally Point.

  • You can put different rally points for each factory types.
  • Rally Point marker needs to be in Base Marker radius
    • If you have platoon of many units and some of them will get outside of the Base Marker while waiting on the Rally Point, these units won't be sent by AI on attack and will stay on that place untill they are destroyed.
Marker Chains

Next step is set up all kinds of chains for units. Clikc on Chains tab and create a new chain New map icon.PNG. While having this chain selected, put Blank Markers on the map and they will create a chain. You can also add existing marker to chain by clicking on MarkerToChain.PNG. Marker can be also deleted from chain, but save your map first before doing so, editor might sometimes crash during it!

  • Set up as many chains as you want, with more chains AI will be harder to predict where it'll send units.
  • Don't forget to rename your chains, that can be done by double clicking on chain name. Markers can be renamed only in Markers tab.
  • First marker of the chain should be relatively close to rally point. It's not necessary but without that AI won't stop to attack enemy units if set on patrol and just go to first marker.
  • Markers in chain for land and naval attacks should not be too close together, since units are moving in formation and they tend to regroup at every marker.


Once you have your base and markers 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:

Prothyon16_DEMO_m1uefai.lua
  • 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()

Base

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)

   UEFM1WestBaseAirAttacks()
   UEFM1WestBaseLandAttacks()
end
  • 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.
      • Radius of base markers should not be overlapping!
    • {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...

Attacks

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)
end
  • 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 = {
       'NavalAttackTemp2',
       'NoPlan',
       { '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' - Basic unit function. Other typer are Support, Scout, Artillery
      • '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 the 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.
  • On last line our custom platoon will get finally assembled
    • ArmyBrains[UEF] - Army that will use this template
    • PBMAddPlatoon( Builder ) - Adds our platoon builder that contains our template.

Usage

Now when we have our AI ready, we need to import it's file to the beginning of script to use it.

local M1UEFAI = import('/maps/Prothyon16_DEMO/Prothyon16_DEMO_m1uefai.lua')

Next step is to activate it. This line will handle that:

M1UEFAI.UEFM1WestBaseAI()
  • This calls for UEFM1WestBaseAI() function in M1UEFAI that we imported at the beginning of script file.
  • Every base is usually defined by it's own function. So to activate them all, you need to call for all functions.

Voice Overs

Voice overs are a table of several variables. They could be defined it script file but to keep better track on them, they have their own file called _string.lua and are imported into script. In our example it is.

Prothyon16_DEMO_strings.lua

Right now there in no other way where to have videos and sound files than in Forged Alliance installation folder:

Supreme Commander - Forged Alliance\movies
Supreme Commander - Forged Alliance\sounds\Voice\us

Format

One VO can contain more than one videos, they will be played one after another. The format is:

VOname = {
  {text = , vid = , bank = , cue = , faction = },
  {text = , vid = , bank = , cue = , faction = },
  {text = , vid = , bank = , cue = , faction = },
}

And in our example:

# Third objective intro 1 / Actor: Gyle / Update 22/05/2015 / VO Ready
airbase1 = {
  {text = '[Gyle]: The island is now secure.', vid = 'Pro_16_airbase1.sfd', bank = 'G_VO1', cue = '21airbase1', faction = 'UEF'},
}
  • First line is description of our VO.
  • airbase1 - is unique name for this VO that will be called in script.
    • text = '[Gyle]: The island is now secure.' - This will be displayed in VO box in game.
    • vid = 'Pro_16_airbase1.sfd' - Name of VO's video file.
    • bank = 'G_VO1' - Name of VO's sound file.
    • cue = '21airbase1' - Specific track inside of the sound file.
    • faction = 'UEF' - Faction displayed with VO. Options are: UEF, Aeon, Cybran, Seraphim, NONE.

Usage

In order to use VO's we created in string file, we need to import this file at the beginning of the script

local OpStrings = import('/maps/Prothyon16_DEMO/Prothyon16_DEMO_strings.lua')

Function with VO is called Dialogue and it's defined in ScenarioFramework.lua so we need to import this file as well.

local ScenarioFramework = import('/lua/ScenarioFramework.lua')
  • If you want to get more detailed information what excatly this function do, look inside ScenarioFramework

Now we have everything ready to use VOs in our code. The format for is following:

ScenarioFramework.Dialogue(OpStrings.VOname, callback, critical)
  • ScenarioFramework.Dialogue - Calls for Dialogue function in ScenarioFramework that we imported at the beginning
  • OpStrings.VOname - calls for our specific VO we created in string.lua file.
  • callback - Callback function that this VO will start. If there is no, then type nil
  • critical - true or false / nothing. If set to true, this will make sure this VO will be always played. WIll not be blocked by some other VO.
    • Story VO's are usually set to true, while taunts are not that important.

Example without and with callback fucntion:

ScenarioFramework.Dialogue(OpStrings.intro1, nil, true)
ScenarioFramework.Dialogue(OpStrings.airbase1, IntroMission3)

Video

Audio

Tables

Categories

UEF AEON CYBRAN SERAPHIM

ALLUNITS STRUCTURE

LAND AIR NAVAL

ENERGYPRODUCTION MASSEXTRACTION MASSFABRICATION ORBITALSYSTEM ECONOMIC HYDROCARBON AIRSTAGINGPLATFORM WALL

TECH1 TECH2 TECH3 EXPERIMENTAL

INDIRECTFIRE DIRECTFIRE MOBILE BUILTBYQUANTUMGATE

PRODUCTFA SELECTABLE REPAIR RECLAIM CAPTURE VISIBLETORECON PATROLHELPER ABILITYBUTTON SHOWQUEUE OVERLAYOMNI OVERLAYDIRECTFIRE OVERLAYINDIRECTFIRE

ARTILLERY TACTICALMISSILEPLATFORM ANTIAIR STRATEGIC NUKE MISSILE SHIELD DEFENSE ANTIMISSILE SILO

COMMAND SUBCOMMANDER ENGINEER CONSTRUCTION OPERATION FACTORY

RADAR SONAR OMNI INTELLIGENCE COUNTERINTELLIGENCE OPTICS

SCOUT BOT

GROUNDATTACK TRANSPORTATION TRANSPORTFOCUS BOMBER ANTINAVY

LIGHTBOAT FRIGATE T1SUBMARINE T2SUBMARINE DESTROYER CRUISER BATTLESHIP NAVALCARRIER NUKESUB MOBILESONAR DEFENSIVEBOAT



'attack'

'support'

'artillery'

'scout'



Supported Objective Types:

  • Kill
  • Capture
  • KillOrCapture
  • Reclaim
  • Locate
  • SpecificUnitsInArea
  • CategoriesInArea
  • ArmyStatCompare
  • UnitStatCompare
  • CategoryStatCompare
  • Protect
  • Timer
  • Unknown
  • Camera
  • Basic
Enhancements
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