Productionsite Programs

Productionsites have programs that will be executed by the game engine. Each productionsite must have a program named main, which will be started automatically when the productionsite is created in the game, and then repeated until the productionsite is destroyed.

Programs are defined as Lua tables. Each program must be declared as a subtable in the productionsite’s Lua table called programs and have a unique table key. The entries in a program’s subtable are the translatable descname and the table of actions to execute, like this:

programs = {
   main = {
      -- TRANSLATORS: Completed/Skipped/Did not start working because ...
      descname = _("working"),
      actions = {
         <list of actions>
      }
   },
},

The translations for descname can also be fetched by pgettext to disambiguate. We recommend that you do this whenever workers are referenced, or if your tribes have multiple wares with the same name:

programs = {
   main = {
      -- TRANSLATORS: Completed/Skipped/Did not start recruiting soldier because ...
      descname = pgettext("atlanteans_building", "recruiting soldier"),
      actions = {
         <list of actions>
      }
   },
},

A program can call another program, for example:

programs = {
   main = {
      -- TRANSLATORS: Completed/Skipped/Did not start working because ...
      descname = _("working"),
      actions = {
         "call=produce_ration",
         "call=produce_snack",
         "return=skipped"
      }
   },
   produce_ration = {
      -- TRANSLATORS: Completed/Skipped/Did not start preparing a ration because ...
      descname = _("preparing a ration"),
      actions = {
         <list of actions>
      }
   },
   produce_snack = {
      -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
      descname = _("preparing a snack"),
      actions = {
         <list of actions>
      }
   },
},

A program consists of a sequence of actions. An action is written as <type>=<parameters>:

produce_snack = {
   -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ...
   descname = _("preparing a snack"),
   actions = {
      "return=skipped unless economy needs snack",
      "sleep=duration:2s500ms",
      "consume=barbarians_bread fish,meat beer",
      "playsound=sound/barbarians/taverns/inn 100",
      "animate=working duration:22s",
      "sleep=duration:10s",
      "produce=snack"
   }
},

For general information about the format, see Syntax.

Available actions are:

return

return=completed|failed|skipped \[\<\condition\>\]

The return action determines how the program’s result will update the productivity statistics when any of its steps can’t be completed:

  • completed: Counts as a success for the productivity statistics.

  • failed: Counts as a failure for the productivity statistics.

  • skipped: Will be ignored by the productivity statistics.

Note

If the execution reaches the end of the program, the return value is implicitly set to completed.

If condition is specified, this will cause an immediate termination of the program if the condition can’t be satisfied. There are two types of conditions, using Boolean arithmetic:

when <statement1> [and <statement2> …]:

If any of these statements is false, the program will terminate immediately.

unless <statement1> [or <statement2> …]:

If none of these statements is true, the program will terminate immediately.

The individual statements can also be negated:

when not <statement1> and <statement2>:

If <statement1> is true or <statement2> is false, the program will terminate immediately.

unless not <statement>:

If <statement> is false, the program will terminate immediately.

The following statements are available:

site has <ware_types>|<worker_types>:

Checks whether the building’s input queues are filled with a certain amount of wares/workers. A ware or worker type may only appear once in the command. You can specify more than one ware. For example, site has fish,meat:2 is true if the building has at least 1 fish or if the building has at least 2 meat.

workers need experience:

This is true if a worker working at the building can currently gain some experience.

economy needs <ware_type>|<worker_type>:

The result of this condition depends on whether the economy that this productionsite belongs to needs a ware or worker of the specified type. How this is determined is defined by the economy. A ware or worker type may only appear once in the command.

Examples for return=failed:

-- If the building has no 'ax_sharp' in its input queues, the program will fail immediately.
return=failed unless site has ax_sharp

-- If the building has less than 2 items of 'barbarians_bread' in its input queues, the program
-- will fail immediately.
return=failed unless site has barbarians_bread:2

-- The building needs 1 item of 'bread_frisians', 'beer', 'smoked_fish' or 'smoked_meat' in its
-- input queues. Otherwise, the program will fail immediately.
return=failed unless site has bread_frisians,beer,smoked_fish,smoked_meat

-- The building needs 1 item of 'fish' or 2 items of 'meat' in its input queues. Otherwise, the
-- program will fail immediately.
return=failed unless site has fish,meat:2

Examples for return=skipped:

-- If any subsequent step fails, don't cause a hit on the statistics.
return=skipped

-- Only run this program if the economy needs an 'ax_sharp'.
return=skipped unless economy needs ax_sharp

-- Only run this program if the economy needs a 'beer' or if any of the workers working at the
-- building can gain more experience.
return=skipped unless economy needs beer or workers need experience

-- Only run this program if the economy needs at least one of the listed wares: 'clay', 'fish' or
-- 'coal'.
return=skipped unless economy needs clay or economy needs fish or economy needs coal

-- Only run this program if the economy needs at least one of the listed wares: 'iron' or 'gold'.
-- If the economy has sufficient 'coal', run anyway even if none of these two wares are needed.
return=skipped unless economy needs iron or economy needs gold or not economy needs coal

-- If the building has no 'fur_garment_old' in its input queues, skip running this program.
return=skipped unless site has fur_garment_old

-- If the building has 'wheat' in its input queue and if the economy needs the ware
-- 'flour' but does not need the ware 'cornmeal', skip running this program so we can run another
-- program for producing 'flour' rather than 'cornmeal'.
return=skipped when site has wheat and economy needs flour and not economy needs cornmeal

-- If the building has at least 2 items of 'fish' in its input queues and if the economy needs
-- any 'smoked_fish', skip running this program because we will want to produce some
-- 'smoked_fish' instead of whatever this program produces.
return=skipped when site has fish:2 and economy needs smoked_fish

-- If the building has at least one item of 'fruit' or 'bread_frisians' and at least one item of
-- 'smoked_fish' or 'smoked_meat', skip running this program. We want to do something more useful
-- with these wares with another program.
return=skipped when site has fruit,bread_frisians and site has smoked_fish,smoked_meat

call

call=\<program_name\> \[on failure|completion|skip fail|complete|skip|repeat\]
Parameters:
  • program_name (string) – The name of a program defined in this productionsite.

  • on (string) –

    Defines what to do if the program fails, completes or skips.

    • complete: The failure is ignored, and the program returns as successful.

    • fail: The command fails, with the same effect as executing the return program with return=failed.

    • repeat: The command is repeated.

    • skip: The failure is ignored, and the program is continued. This is the default setting if on is ommitted.

Calls another program of the same productionsite. Example:

-- Productionsite program that will mine marble 1 out of 3 times
programs = {
   main = {
      -- TRANSLATORS: Completed/Skipped/Did not start working because ...
      descname = _("working"),
      actions = {
         "call=mine_granite on failure fail",
         "call=mine_granite on failure fail",
         "call=mine_marble on failure fail",
      }
   },
   mine_granite = {
      -- TRANSLATORS: Completed/Skipped/Did not start quarrying granite because ...
      descname = _("quarrying granite"),
      actions = {
         "callworker=cut_granite",
         "sleep=duration:17s500ms"
      }
   },
   mine_marble = {
      -- TRANSLATORS: Completed/Skipped/Did not start quarrying marble because ...
      descname = _("quarrying marble"),
      actions = {
         "callworker=cut_marble",
         "sleep=duration:17s500ms"
      }
   },
},

callworker

callworker=\<worker_program_name\> \[on failure fail|complete|skip\]
Parameters:
  • worker_program_name (string) – The name of a worker program defined in the productionsite’s main worker.

  • on (string) – Defines what to do if the worker program fails. The production program is always terminated immediately when callworker fails; this parameter specifies what result status the production program should report. Default is fail.

Calls a program of the productionsite’s main worker. Example:

-- Productionsite program actions
actions = {
   -- Send the farmer out to harvest wheat from a wheat field
   "callworker=harvest",
   "animate=working duration:3s",
   "sleep=duration:1s"
}

-- Corresponding worker program for harvesting wheat from a wheat field
harvest = {
   "findobject=attrib:ripe_wheat radius:2",
   "walk=object",
   "playsound=sound/farm/scythe priority:70% allow_multiple",
   "animate=harvest duration:10s",
   "callobject=harvest",
   "animate=gather duration:4s",
   "createware=wheat",
   "return"
}

sleep

sleep=duration:\<duration\>
Parameters:

duration (duration) – The time Duration for which the program will wait before continuing on to the next action. If 0, the result from the most recent command that returned a value is used.

Blocks the execution of the program for the specified duration. Example:

actions = {
   "consume=ration",
   -- Do nothing for 30 seconds
   "sleep=duration:30s",
   "callworker=scout"
}

animate

Runs an animation. See animate.

consume

consume=ware_name\{,ware_name\}\[:count\] \[ware_name\{,ware_name\}\[:amount\]\]...\]
Parameters:
  • ware_name (string) – a list of ware types to choose from for consumption. A ware type may only appear once in the command.

  • amount (int) – The amount of wares of the chosen type to consume. A positive integer. If omitted, the value 1 is used.

Consumes wares from the input storages. For each ware group, the number of wares specified in amount is consumed. The consumed wares may be of any type in the group.

If there are not enough wares in the input storages, the command fails (with the same effect as executing return=failed). Then no wares will be consumed.

Selecting which ware types to consume for a group so that the whole command succeeds is a constraint satisfaction problem. The implementation does not implement an exhaustive search for a solution to it. It is just a greedy algorithm which gives up instead of backtracking. Therefore the command may fail even if there is a solution.

However it may be possible to help the algorithm by ordering the groups carefully. Suppose that the input storage has the wares a:1, b:1 and a consume command has the parameters a,b:1 a:1. The algorithm tries to consume its input wares in order. It starts with the first group and consumes 1 ware of type a (the group becomes satisfied). Then it proceeds with the second group, but there are no wares of type a left to consume. Since there is no other ware type that can satisfy the group, the command will fail. If the groups are reordered so that the parameters become a:1 a,b:1, it will work. The algorithm will consume 1 ware of type a for the first group. When it proceeds with the second group, it will not have any wares of type a left. Then it will go on and consume 1 ware of type b for the second group (which becomes satisfied) and the command succeeds.

Note

It is not possible to reorder ware types within a group. a,b is equivalent to b,a because in the internal representation the ware types of a group are sorted.

Examples:

actions = {
   "return=skipped unless economy needs shield_advanced",
   -- Try to consume 2x iron, then 2x coal, then 1x gold
   "consume=iron:2 coal:2 gold",
   "sleep=duration:32s",
   "animate=working duration:45s",
   "produce=shield_advanced"
},

actions = {
   "checksoldier=soldier:evade level:0",
   "return=failed unless site has empire_bread",
   "return=failed unless site has fish,meat",
   "sleep=duration:30s",
   "checksoldier=soldier:evade level:0",
   -- Try to consume 1x empire_bread, then 1x fish or 1x meat
   "consume=empire_bread fish,meat",
   "train=soldier:evade level:1"
}

produce

produce=\<ware_name\>\[:\<amount\>\] \[\<ware_name\>\[:\<amount\>\]...\]
Parameters:
  • ware_name (string) – The name of a ware type. A ware type may only appear once in the command.

  • amount (int) – The amount of wares of this type to produce. A positive integer. If omitted, the value 1 is used.

Produces wares. For each group, the number of wares specified in amount is produced and then placed on the building’s flag to be carried where they are needed. The produced wares are of the type specified by ware_name in the group. Example:

actions = {
   "return=skipped unless economy needs fur",
   "consume=barley water",
   "sleep=duration:15s",
   "animate=working duration:20s",
   -- Produce 2x fur and 1x meat
   "produce=fur:2 meat"
}

recruit

recruit=\<worker_name\>\[:\<amount\>\] \[\<worker_name\>\[:\<amount\>\]...\]
Parameters:
  • worker_name (string) – The name of a worker type. A worker type may only appear once in the command.

  • amount (int) – The amount of workers of this type to create. A positive integer. If omitted, the value 1 is used.

Produces workers. For each group, the number of workers specified in amount is produced, which then leave the site looking for employment. The produced workers are of the type specified by worker_name in the group. Example:

actions = {
   "return=skipped unless economy needs atlanteans_horse",
   "consume=corn water",
   "sleep=duration:15s",
   "playsound=sound/farm/horse priority:50% allow_multiple",
   "animate=working duration:15s",
   -- Create 2 horses
   "recruit=atlanteans_horse:2"
}

mine

mine=\<resource_name\> radius:\<number\> yield:\<percent\> when_empty:\<percent\>
\[experience_on_fail:\<percent\>\] [no_notify]
Parameters:
  • resource_name (string) – The name of the resource to mine, e.g. ‘coal’ or ‘water’.

  • radius (int) – The workarea radius that is searched for resources. Must be >0.

  • yield (percent) – The Percent of resources that the mine can dig up before its resource is depleted.

  • when_empty (percent) – The Percent chance that the mine will still find some resources after it has been depleted.

  • experience_on_fail (percent) – The Percent chance that the mine’s workers will still gain some experience when mining fails after its resources have been depleted.

  • no_notify (empty) – Do not send a message to the player if this step fails.

Takes resources from the ground. A building that mines will deplete when the percentage of resources given in resources has been dug up, leaving a chance of depleted that it will still find some resources anyway. Examples:

actions = {
    "return=skipped unless economy needs iron_ore",
    "consume=ration",
    "sleep=duration:45s",
    "animate=working duration:20s",
     -- Search radius of 2 for iron. Will always find iron until 33.33% of it has been dug up.
     -- After that, there's still a chance of 5% for finding iron.
     -- If this fails, the workers still have a chance of 17% of gaining experience.
    "mine=resource_iron radius:2 yield:33.33% when_empty:5% experience_on_fail:17%",
    "produce=iron_ore"
}

actions = {
    "sleep=duration:20s",
    "animate=working duration:20s",
     -- Search radius of 1 for water. Will always find water until 100% of it has been drawn.
     -- After that, there's still a chance of 65% for finding water.
    "mine=resource_water radius:1 yield:100% when_empty:65%",
    "produce=water"
}

checksoldier

checksoldier=soldier:attack|defense|evade|health level:\<number\>
Parameters:
  • soldier (string) – The soldier training attribute to check for.

  • level (int) – The level that the soldier should have for the given training attribute.

Note

This action is only available to training sites.

Returns failure unless there is a soldier present with the given training attribute at the given level.

Note

The program’s name must match the attribute to be trained and the level checked for, in the form upgrade_soldier_<attribute>_<level>.

Example:

upgrade_soldier_attack_3 = {
   -- TRANSLATORS: Completed/Skipped/Did not start upgrading ... because ...
   descname = _("upgrading soldier attack from level 3 to level 4"),
   actions = {
      -- Fails when there aren't any soldiers with attack level 3
      "checksoldier=soldier:attack level:3",
      "return=failed unless site has sword_long",
      "return=failed unless site has honey_bread,mead",
      "return=failed unless site has smoked_fish,smoked_meat",
      "sleep=duration:10s800ms",
      "animate=working duration:12s",
      -- Check again because the soldier could have been expelled by the player
      "checksoldier=soldier:attack level:3",
      "consume=sword_long honey_bread,mead smoked_fish,smoked_meat",
      "train=soldier:attack level:4"
   }
},

train

train=soldier:attack|defense|evade|health level:\<number\>
Parameters:
  • soldier (string) – The soldier training attribute to be trained.

  • level (int) – The level that the soldier will receive for the given training attribute.

Note

This action is only available to training sites.

Increases a soldier’s training attribute to the given level. It is mandatory to call ‘checksoldier’ before calling this action to ensure that an appropriate soldier will be present at the site. Example:

actions = {
   "checksoldier=soldier:attack level:1",
   "return=failed unless site has ax_broad",
   "return=failed unless site has fish,meat",
   "return=failed unless site has barbarians_bread",
   "sleep=duration:30s",
   -- This is called first to ensure that we have a matching soldier
   "checksoldier=soldier:attack level:1",
   "consume=ax_broad fish,meat barbarians_bread",
   -- Now train the soldier's attack to level 2
   "train=soldier:attack level:2"
}

playsound

Plays a sound effect. See playsound.

script

Runs a Lua function. See script.

construct

construct=\<immovable_name\> worker:\<program_name\> radius:\<number\>
Parameters:
  • immovable_name (string) – The name of the immovable to be constructed, e.g. barbarians_shipconstruction.

  • worker (string) – The worker’s program that makes the worker walk to the immovable’s location and do some work.

  • radius (radius) – The radius used by the worker to find a suitable construction spot on the map.

Sends the main worker to look for a suitable spot on the shore and to perform construction work on an immovable. Example:

-- Production program actions
actions = {
   "construct=barbarians_shipconstruction worker:buildship radius:6",
   "sleep=duration:20s",
}

-- Corresponding worker program
buildship = {
   "walk=object-or-coords",
   "plant=attrib:barbarians_shipconstruction unless object",
   "playsound=sound/sawmill/sawmill priority:80% allow_multiple",
   "animate=work duration:500ms",
   "construct",
   "animate=work duration:5s",
   "return"
},