.. _productionsite_programs: Productionsite Programs ======================= Productionsites have :ref:`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 = { } }, }, 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 = { } }, }, 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 = { } }, produce_snack = { -- TRANSLATORS: Completed/Skipped/Did not start preparing a snack because ... descname = _("preparing a snack"), actions = { } }, }, A program consists of a sequence of actions. An action is written as ``=``:: 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" } }, .. highlight:: default For general information about the format, see :ref:`map_object_programs_syntax`. Available actions are: - `animate`_ - `call`_ - `callworker`_ - `checksoldier`_ - `construct`_ - `consume`_ - `mine`_ - `playsound`_ - `recruit`_ - `produce`_ - `return`_ - `sleep`_ - `train`_ .. _productionsite_programs_act_return: return ------ .. function:: 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 \ \[and \ ...\]: If any of these statements is false, the program will terminate immediately. :unless \ \[or \ ...\]: If none of these statements is true, the program will terminate immediately. The individual statements can also be negated: :when not and : If ```` is true or ```` is false, the program will terminate immediately. :unless not : If ```` is false, the program will terminate immediately. The following statements are available: :site has |: 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 |: 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``: .. code-block:: lua -- 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``: .. code-block:: lua -- 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 ---- .. function:: call=\ \[on failure|completion|skip fail|complete|skip|repeat\] :arg string program_name: The name of a :ref:`program ` defined in this productionsite. :arg string on: 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 :ref:`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: .. code-block:: lua -- 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 ---------- .. function:: callworker=\ \[on failure fail|complete|skip\] :arg string worker_program_name: The name of a :ref:`worker program ` defined in the productionsite's main :ref:`worker `. :arg string on: 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: .. code-block:: lua -- 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 ----- .. function:: sleep=duration:\ :arg duration duration: The time :ref:`map_object_programs_datatypes_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: .. code-block:: lua actions = { "consume=ration", -- Do nothing for 30 seconds "sleep=duration:30s", "callworker=scout" } animate ------- Runs an animation. See :ref:`map_object_programs_animate`. consume ------- .. function:: consume=ware_name\{,ware_name\}\[:count\] \[ware_name\{,ware_name\}\[:amount\]\]...\] :arg string ware_name: a list of :ref:`ware types ` to choose from for consumption. A ware type may only appear once in the command. :arg int amount: 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: .. code-block:: lua 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 ------- .. function:: produce=\\[:\\] \[\\[:\\]...\] :arg string ware_name: The name of a :ref:`ware type `. A ware type may only appear once in the command. :arg int amount: 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: .. code-block:: lua 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 ------- .. function:: recruit=\\[:\\] \[\\[:\\]...\] :arg string worker_name: The name of a :ref:`worker type `. A worker type may only appear once in the command. :arg int amount: 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: .. code-block:: lua 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 ---- .. function:: mine=\ radius:\ yield:\ when_empty:\ \[experience_on_fail:\\] [no_notify] :arg string resource_name: The name of the resource to mine, e.g. 'coal' or 'water'. :arg int radius: The workarea radius that is searched for resources. Must be ``>0``. :arg percent yield: The :ref:`map_object_programs_datatypes_percent` of resources that the mine can dig up before its resource is depleted. :arg percent when_empty: The :ref:`map_object_programs_datatypes_percent` chance that the mine will still find some resources after it has been depleted. :arg percent experience_on_fail: The :ref:`map_object_programs_datatypes_percent` chance that the mine's workers will still gain some experience when mining fails after its resources have been depleted. :arg empty no_notify: 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: .. code-block:: lua 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 ------------ .. function:: checksoldier=soldier:attack|defense|evade|health level:\ :arg string soldier: The soldier training attribute to check for. :arg int level: The level that the soldier should have for the given training attribute. .. note:: This action is only available to :ref:`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__``. Example: .. code-block:: lua 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 ----- .. function:: train=soldier:attack|defense|evade|health level:\ :arg string soldier: The soldier training attribute to be trained. :arg int level: The level that the soldier will receive for the given training attribute. .. note:: This action is only available to :ref:`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: .. code-block:: lua 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 :ref:`map_object_programs_playsound`. construct --------- .. function:: construct=\ worker:\ radius:\ :arg string immovable_name: The name of the :ref:`immovable ` to be constructed, e.g. ``barbarians_shipconstruction``. :arg string worker: The :ref:`worker's program ` that makes the worker walk to the immovable's location and do some work. :arg 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: .. code-block:: lua -- 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" },