FOCS Scripting Tutorial

From FreeOrionWiki
Revision as of 00:00, 17 March 2016 by Dbenage-cx (Talk | contribs) (Ship Parts: clarify class and primary/secondary stats)

Jump to: navigation, search

Template:WIP This tutorial covers how to modify FreeOrion Content Script (FOCS) files. For details on all of the possible values, see Effects.

Getting Started

All FOCS files are plain text files, though some contain extended characters, especially the language files.
Template:FOCS Notepad Notice

When a reference is made to the default/ directory, this refers to the Resources Files directory.
This directory varies on different systems and can be manually changed.
If you are unsure where this directory is:
Start FreeOrion → OptionsDirectories (next to last) → Resource Files.

Creating a new entry

Create a new file in the default/scripting/buildings/ directory, name it TUTORIAL_ONE.focs.txt
    name = "BLD_TUTORIAL_ONE"
    description = "BLD_TUTORIAL_ONE_DESC"
    buildcost = 15
    buildtime = 1
    icon = ""

It is good practice to make sure the file ends with a blank line.

This creates a very basic building type that could be built anywhere but has no effect.

No player would be able to build this building however, as their empire does not know how.
For now, we will just give the knowledge to everyone at the start of the game:

Edit default/scripting/starting_unlocks/items.inf
Add the following line at the top
Item type = Building name = "BLD_TUTORIAL_ONE"

If you start the game now and select the production screen at your home planet, you will see:


Hover over that and the tooltip shows:


This is because we have not told the game what our building should be labelled as, just to use the key reference of BLD_TUTORIAL_ONE.
Just like the filename, key references could be named anything, regardless of what label we want to use.
The name entry in the definition needs to be unique, but description can be shared among other entries if needed.

The key references are looked up based on the language selected, in one of the stringtables.
You can start with the file that suits you best, for this example we will use the english file.

Edit default/stringtables/en.txt
On the next blank line enter the following
A new building type from the scripting tutorial.

This is a brand new building type we just created.

Make sure there are blank lines before and after these new entries.

If you were going to share this entry with others, create the same entries in each of the other stringtable files as well. Few people are fluent in all of these languages, so simply copy the same text into the same spot in each file. If you can provide a translated version, please do as it cuts down on work others would need to do.

You now have a very basic building in the game, though it has no purpose.

Keep in mind that this is just for demonstration. Building definitions should not be common structures built on every planet or more than once on any planet, in general. Structures like power plants or medical facilities would be covered by the infrastructure mechanic.

Entry Files

All of the FOCS entry files have a double extension of .focs.txt.
These files will be loaded regardless of the rest of their filename, or how deeply nested in the sub-directory they are.

Some special entry files have the extension .inf.
While most of these files can be freely edited, they can not be renamed or moved.

Any other file extension is not loaded into the game, unless an entry file specifically includes it.
The extension .macros is commonly used to denote scripting macros used in various entry files.
Entries that are not wanted in the game currently, but kept around for reference, are typically given the extension .disabled.

Entry files should never #include a file with another entry definition in it.

Directory Structure

Entry files are categorized by their type and should remain within the directory for that type (nested sub-directories are ok).
For example Tech entries can be anywhere in default/scripting/techs/, but should never be in default/scripting/fields/.
This only applies to the actual definition files, those with the extension .focs.txt.

The following directories within default/scripting are for .focs.txt entries:

alignments/ Alignment entries
buildings/ Building entries
empire_statistics/ Empire statistics entries
encyclopedia/ Encyclopedia topic entries
fields/ Field entries
monster_designs/ Ship loadout designs for space monsters
ship_designs/ Ship loadout design entries
ship_hulls/ Ship hull designs
ship_parts/ Ship part entries
specials/ Entries for specials
species/ Species entries
techs/ Tech entries

Required files

These are relative to default/scripting/:

keymaps.inf To Be Determined - Default keymap values
monster_fleets.inf Entries for monster fleets
starting_unlocks/buldings.inf Buildings pre-built on every starting homeworld.
starting_unlocks/fleets.inf Entries for fleets every player starts the game with.
starting_unlocks/items.inf Blueprints available at the start of the game to every player. For techs this means they are completed, for other types it allows the player to produce them.
techs/Categories.inf Categories that a tech must belong to. For now these should not be changed or added to, aside from possibly the graphic or colour definitions.

Additionally, definitions listed in any starting_unlocks/ file or monster_fleets.inf need to be avaiable.
The default AI may assume any or all of the default entries to exist.


A basic macro definition looks like this:


The three apostrophies denote preformatted text, meaning any newlines are part of the macro.
Macro names should be in all uppercase, with underscores in place of spaces. They should also be uniquely named.

References to a macro are done by adding double brackets:

buildtime = [[FIRST_ONE]]

The game will end up seeing this as buildtime = 2

Macros may also use arguments:

'''@[email protected] * @[email protected]'''
Multiplies the first argument by the second.
Results in 6 (2 * 3)

You can pass other macros for the arguments:

Results in 8 (2 * 4)

Macros are mainly used to keep consistant values for multiple definitions.
When this is the case, it is best to have the macro definition in a file by itself, so other files can include it.
Sometimes macros are used for a complicated formula to help the readablity of the file. There is no need for these macro definitions to be separated if they are never used in another definition.

Including other files

Files are usually included for macro definitions.
You can include another file with the #include directive:

#include "some_file.macros"
Includes the file named some_file.macros

The directive should by on a line by itself, without any spaces before #include. There is no restriction on what files are included, however you should not include files containing another FOCS entry in it. This would lead to a conflict when the entry is loaded twice.


If the entry is in the game, but does not show the name or the description correctly, check the stringtable entry for your selected language.

Typically if there is a problem with the game parsing an entry, it will show the error in the console window. The error will also be in the log file freeorion.log, which is located in your user directory (Options > Directories > Save files (parent directory))

If there are no errors shown, you can make sure the file is loading by setting the log level to TRACE.
Either edit the config.xml file in your user directory or launch the game with the --log-level TRACE argument.
The client log file (freeorion.log) will now show each file as it was loaded in, as well as any files that were skipped.

If you need further help, post a question in the forums.

Adding New Content

Linking a Tech and a Building

Create a new file in default/scripting/techs/
We will save this file as TUTORIAL_ONE.focs.txt

    name = "TECH_TUTORIAL_ONE"
    description = "TECH_TUTORIAL_ONE_DESC"
    short_description = "BUILDING_UNLOCK_SHORT_DESC"
    category = "DEFENSE_CATEGORY"
    researchcost = 4 * [[TECH_COST_MULTIPLIER]]
    researchturns = 1
    prerequisites = "DEF_ROOT_DEFENSE"
    unlock = Item type = Building name = "BLD_TUTORIAL_TWO"
    effectsgroups =
            scope = And [
                OwnedBy empire = Source.Owner
            effects = SetTroops value = Value + 1
    graphic = ""

#include "techs.macros"

#include "../common/shared.macros"

This tech:

  • Requires DEF_ROOT_DEFENSE to be researched first (which every player starts with)
  • Allows a player to build BLD_TUTORIAL_TWO (we have not created this yet)
  • Increases the speed of new troop recruitment on the planet by an additional 1 per turn, as long as combat is not occurring.

The short description is for the hover text on the tech screen, as well as the brief description at the top of the 'pedia entry.
Techs all belong to one tech category, these are defined in Categories.inf. It is recommended to use one of the existing categories.

Notice researchcost uses the macro TECH_COST_MULTIPLIER, which is defined in default/scripting/common/shared.macros So we also #include that file at the bottom.
The ../ means to go back one directory, in this case to default/scripting (because our file is in default/scripting/techs).
This definition also uses the CANDIDATE_BATTLE_CHECK macro, so the techs.macros file is needed for that.

For the first building, we will reuse the earlier BLD_TUTORIAL_ONE

For this next building, we will be showing alternate ways to reach a desired effect. If you just want a workable version without the back and forth, scroll to the end of this section.

Let's go ahead and add the second building in, create the file default/scripting/buildings/TUTORIAL_TWO.focs.txt

    name = "BLD_TUTORIAL_TWO"
    description = "BLD_TUTORIAL_TWO_DESC"
    buildcost = 20
    buildtime = 3
    location = And [
        Not Contains Building name = "BLD_TUTORIAL_TWO"
        OwnedBy empire = Source.Owner
        TargetPopulation low = 1
    EnqueueLocation = [[ENQUEUE_BUILD_ONE_PER_PLANET]]
    effectsgroups = [
            scope = And [
                Object id = Source.PlanetID
            effects = SetMaxTroops value = Value + 3
            scope = And [
                Ownedby empire = Source.Owner
                Contains Building name = "BLD_TUTORIAL_TWO"
                Contains Building name = "BLD_TUTORIAL_ONE"
            effects = SetMaxDefense value = Value + 5
    icon = ""

#include "../common/shared.macros"

This building can only be built on a planet with at least 1 population, and is limited to one per planet.
It also has a couple of effects, the first allows an additional 3 troops on the planet
The second allows an extra defense of 5, but only if there is also a BLD_TUTORIAL_ONE on the planet.

location tells the game where this building can be constructed.

  • check all of the planets
  • for each planet that is without a BLD_TUTORIAL_TWO
  • that is also owned by the player
  • that also has a population of at least 1

EnqueueLocation restricts when a building can be placed into the production queue.

The effectsgroups contains any effects and the conditions of when and where to apply them.
There are a number of different ways to construct these, so we will show two different methods.

Looking at the first EffectsGroup, the scope defines the Target of our effect:

  • check all of the planets
  • for each one that has an ID that is the same as the sources(this building) planet ID. ID is a unique identifier, so this will only match one result.

For the second EffectsGroup:

  • check all of the planets
  • for each one with the same owner as the sources(this building) owner.
  • that has a completed BLD_TUTORIAL_TWO
  • and also has a completed BLD_TUTORIAL_ONE

effects define what effects apply. The Target variable can be used here if needed, but it can not be used in scope or activation because they define what the target is.

For a more in-depth look at all of the possible attributes and descriptions of each, see Effects

Remember to add in the stringtable entries for the new tech and building:

Tutorial tech 1

The first tutorial tech.

Tutorial building 2

Second tutorial building, adds troops and defense.

Start a new single player game with 1 AI player and Planet Density set to High.

If you play with this building for awhile, once you have it on multiple planets you may notice an issue.
Wherever we have both buildings constructed, it increases the defense effect for the buildings on all of our planets.
That might be a good feature for some other building, but it is not really what we intend here.

Once you have these two buildings on a couple of planets, save the game and exit before we make further changes.
The game will load the FOCS files into memory, so changes made will not neccesarily take effect until restarted.

One way to try and solve this is by adding a stacking group to the effect.
Change the effectsgroups of BLD_TUTORIAL_TWO so it looks like this:

    effectsgroups = [
            scope = And [
                Object id = Source.PlanetID
            effects = SetMaxTroops value = Value + 3
            scope = And [
                Ownedby empire = Source.Owner
                Contains Building name = "BLD_TUTORIAL_TWO"
                Contains Building name = "BLD_TUTORIAL_ONE"
            stackinggroup = "STACKING_TUTORIAL_TWO_DEFENSE"
            effects = SetMaxDefense value = Value + 5

stackinggroup only allows the first instance of tha effect to apply, ignoring any others. You might create a new building or tech with the same stackinggroup name, and only the first one would apply.

If we gave both effects the same stackinggroup, only the troop effect would apply.

After saving the changes, load the previous game and click on next turn.
The game state is loaded as we left it, once we start a new turn everything is reprocessed.

Now you will see only one defense effect at each planet. While this functionally works how we want, if you hover over a couple of planets they show the effect all coming from the same planet (if they have a supply connection).
What we really want is for the effect to only apply to the planet it is built at.

Our first effect works fine for this. We could combine the effects onto one effect group, saving us from doing the same scope check twice:

effects = [
    SetMaxTroops value = Value + 3
    SetMaxDefense value = Value + (5 * (If condition = ContainedBy Contains Building name = "BLD_TUTORIAL_ONE"))

If returns either a 1 when true, otherwise is returns a 0.
This would show a bonus of 0 for defense when we do not have a BLD_TUTORIAL_ONE constructed. If everything showed a notice for not having an effect, the user interface would be very cluttered.

Instead of showing useless information, we will just modify a copy of the first EffectGroup.

    name = "BLD_TUTORIAL_TWO"
    description = "BLD_TUTORIAL_TWO_DESC"
    buildcost = 20
    buildtime = 3
    location = And [
        Not Contains Building name = "BLD_TUTORIAL_TWO"
        OwnedBy empire = Source.Owner
        TargetPopulation low = 1
    effectsgroups = [
            scope = And [
                Object id = Source.PlanetID
            effects = SetMaxTroops value = Value + 3
            scope = And [
                Object id = Source.PlanetID
                Contains Building name = "BLD_TUTORIAL_ONE"
            effects = SetMaxDefense value = Value + 5
    icon = ""

#include "../common/shared.macros"

Everything should be working as we had before. When you are testing your changes you can destroy a building by right clicking on the icon for it, on the planet side screen.

We have left the icon blank in all of our examples, letting the game decide the default icon to use. Where mentioned, icon or graphic are required fields and wll be relative to the art directory (default/data/art/). If sharing these wih others, you might pick the icon or graphic asset that best suits the entry.


Any single ship is constructed from a ship design, which is a combination of a ship hull and zero or more ship parts.

The previous section introduced a number of errors to show ways to troubleshoot them. The remaining sections will concentrate more on anything specific to them. Stringtable entries will be ommitted to keep the sections briefer, feel free to add them as appropriate.

Ship Parts

Keep in mind, these parts will not be available to an empire until they unlock them either by researching a tech, getting them at the start of the game, or through some other means.
You can see what parts are in the game, but not yet unlocked by your empire, by going to the ship design screen and selecting Unavailable in the parts filter.

A new weapon

    name = "TUT_WEAPON"
    description = "TUT_WEAPON_DESC"
    class = ShortRange
    damage = 4
    shots = 1
    mountableSlotTypes = External
    buildcost = 25 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 2
    location = OwnedBy empire = Source.Owner
    icon = ""

#include "../common/shared.macros"

class defines what kind of part this is: a short range weapon, a fighter weapon, a piece of armor, etc.
For direct fire weapons (ShortRange), there is a primary stat of damage and a secondary stat of shots.
damage refers to the amount of damage for each shot.
shots is how many times this part shoots during each combat round, this may be omitted and defaults to 1.
The FighterHangar class has a primary stat capacity and a secondary damage.

mountableSlotTypes are slots types that this part will fit into. For balancing purposes: weapons, armor, and sensors should usually be limited to the outside of the ship, with other types restricted to the interior. There are exceptions to this, such as troop pods, but the majority stick to this guideline.
For ship designs, the buildcost of each part and the hull will be accumulative. However the buildtime is not, the longest time of all of the parts will be used.
location limits where ships designs with this part may be constructed. Some part might be restricted to planets with access to a specific special, or a certain system type.

A new armor

    name = "TUT_ARMOR"
    description = "TUT_ARMOR_DESC"
    class = Armour
    capacity = 4
    mountableSlotTypes = [External Internal]
    buildcost = 6 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 4
    location = OwnedBy empire = Source.Owner
    effectsgroups = [
            scope = Source
            stackinggroup = "TUT_ARMOR_STACKING"
            effects = SetStealth value = Value + 2
    icon = ""

#include "../common/shared.macros"

Many parts simply have a capacity. What that capacity relates to depends on the class of the part, in this case it is the amount of extra maximum structure a ship design has.
This allows parts to have effects applied on them from other events with the SetCapacity and SetMaxCapacity effects.

Ship Hulls

A new ship hull:

    name = "TUT_HULL"
    description = "TUT_HULL_DESC"
    speed = 50
    fuel = 4
    stealth = 6
    structure = 20
    slots = [
        Slot type = External position = (0.50, 0.35)
        Slot type = External position = (0.50, 0.60)
        Slot type = External position = (0.80, 0.45)
        Slot type = Internal position = (0.30, 0.40)
    buildCost = 40 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildTime = 4
    location = Contains And [
        Building name = "BLD_SHIPYARD_BASE"
        OwnedBy empire = Source.Owner
    effectsgroups = [
    icon = "icons/ship_hulls/basic-large-hull_small.png"
    graphic = "hulls_design/basic-large-hull.png"

#include "ship_hulls.macros"

#include "../common/shared.macros"

speed, fuel, stealth, and structure are all starting values.
slots has an entry for each slot and the coordinates to display that slot on the graphic during ship design.
Since the position of the slots need to line up with the graphic used, we will just use the basic large hull here.

Ship Designs

New ship design

    name = "SD_TUTORIAL"
    description = "SD_TUTORIAL_DESC"
    hull = "TUT_HULL"
    parts = [
    model = "mark1"

parts need to stay in the same order as they are defined in the hull.
The first three are all external slots, and the fourth is an internal slot.
Since our new armor part can fit in an internal or external slot, this is ok.

Ship designs within the Resource Files are available to all empires.
Designs saved from inside the game are saved in the User Directory, and only available to the human client.

There are also designs for space monster ships, which follow the same layout as other designs.
They are in a separate directory as the fleets are handled differently.


Player fleets are typically only defined within default/scripting/starting_unlocks/fleets.inf
These encompass what ships each player starts the game with, and how they are grouped.
A sample fleet:

    name = "FN_TUTORIAL"
    ships = [

This would create a fleet with two ships using our new ship designs, and one of the basic mark 1 ships.

Monster Fleets

Below is an example of the Small Krill space monster:

    name = "SM_KRILL_1"
    ships = [
    spawnrate = 0.5
    spawnlimit = 9999
    location = And [
        Not Contains Monster
        Not WithinStarlaneJumps jumps = 2 condition = Contains And [
            OwnedBy affiliation = AnyEmpire

spawnrate defines how often the space monster might appear. This is factored with other values, including the frequency set by the player.
spawnlimit defines the maximum number allowed in the game. The monster would not spawn anymore during the current turn, if there are more than this limit.