Lua Event Macro Specification
GOAL: Provide a template events.lua file and associated "library" files such that all a scenario maker has to do is fill in tables in events.lua in order to achieve functionality. This library should provide similar functionality to the "Test of Time Macro Language," but the functionality might not be exactly the same. This will also seek to expand "macro" functionality to take advantage of features enabled by Lua.
Specification overview:
An event will be defined by a table that has "trigger conditions" and "action details" described by entries in a table. Not all keys will be used for all events (in fact, most events will probably only use a small part of available conditions and actions), so events should always do sensible things when an event key is missing.
Events will be divided into "categories" based on when they are checked for triggering.
Most event categories will be based on the "civ.scen" function that triggers them
https://forums.civfanatics.com/threads/totpp-lua-function-reference.557527/#civ.scen
but some triggers might be broken up into multiple categories if that makes more sense (e.g. it might be reasonable to split key press events into several categories).
The first order of business is to specify the functionality that the "Lua Macro" will have. It makes sense to split the specification of trigger checking into the different "categories," but we shouldn't duplicate the "action details" effort for every category.
So we have two classes of specifications to make:
1. Trigger Checks for each desired Category
2. Action Details for each Action Type (display text, create unit, etc.)
Which leaves the question of where to specify Action Details that only apply to a single category, such as "create unit at location of combat." I'm not sure of the answer to that.
Here is my proposed specification for Unit killed event triggers:
Each unit killed event will be specified by its own table, with the following possible keys
======================================================================================
Trigger condition keys
defeatedUnit
Possible Values
absent (i.e. nil), true, --> any defeated unit fires the trigger
integer --> i.d. number of the unittype that fires the trigger
unittype (lua object) --> lua unittype object of the unit that fires the trigger
string --> name of the unittype that fires the trigger
table of integers, unittypes, strings --> everything in table fires the trigger
killingUnit
Possible Values
absent (i.e. nil), true ==>> any attacking unit fires the trigger
integer ==>> i.d. number of the unittype that fires the trigger
unittype (lua object) ==>> lua unittype object of the unit that fires the trigger
string ==>> name of the unittype that fires the trigger
table of integers, unittypes, strings ==>> everything in table fires the trigger
defeatedDefenderOnly
Possible Values
absent ==>> same as false
true ==>> The defeated unit must have been the defender in combat
false ==>> The defeated unit can be either attacker or defender
defeatedAttackerOnly
Possible Values
absent ==> same as false
true ==> The defeated unit must have been the attacker in combat
false ==> The defeated unit can be either attacker or defender
defeatedUnitTribe
Possible Values
absent (i.e. nil), true ==> The defeated unit can be from any tribe
integer ==> defeated unit must be from tribe with this id number
tribe (lua object)==> tribe object of the tribe that must be defeated
string ==> defeated unit's tribe must have this name
table of integers, tribes, strings ==> everything in table fires the trigger
killingUnitTribe
Possible Values
absent (i.e. nil), true ==> The killing unit can be from any tribe
integer ==> killing unit must be from tribe with this id number
tribe (lua object) ==> tribe object of the tribe that must be killing
string ==> killing unit's tribe must have this name
table of integers, tribes, strings ==> everything in table fires the trigger
beforeTurn
Possible Values
absent (i.e. nil), true ==> event can be triggered until end of scenario
integer ==> event can only be triggered on this turn or before it
afterTurn
Possible Values
absent (i.e. nil), true ==>event can be triggered since the start of the scenario
integer ==> event can only be triggered on this turn or later
justOnce
Possible Values
absent(i.e. nil) ==> same as false
true ==> this event can happen only once (separate tribes need separate events)
false ==> this event happens every time the conditions are met
oncePerTurn
Possible Values
absent (i.e. nil) ==> same as false
true ==> this event can happen only once per turn (separate tribes need separate events)
false ==> this event happens every time the conditions are met
flagTable
Possible Values
absent (i.e. nil) ==> no flags to be checked
table ==> This is the table where flags for this event are stored
allFlags
let thisFlagTable be the table specified by the flagTable parameter
Possible Values
absent (i.e. nil) ==> nothing to check, so event happens as other conditions dictate
string ==> event happens if thisFlagTable[string] is true
table of strings ==> event happens if thisFlagTable[stringInAllFlagsTable] is true for all strings in the table
map
Possible Values
absent (i.e. nil), true ==> The battle can take place on any map
0,1,2,3 ==> number of the map the battle can take place on
table of 0,1,2,3 ==> battle can take place on any map specified
locationAttacker
Possible Values
absent (i.e. nil) ==> same as false
true ==> location must be true for the tile the attack was made from
false ==> battle location can be true for either attacker's tile or defender's tile
locationDefender
Possible Values
absent (i.e. nil) ==> same as false
true ==> location must be true for the defender's tile
false ==> battle location can be true for either attacker's tile or defender's tile
location
Possible Values
absent (i.e. nil) ==> The battle can take place on any tile (subject to map restriction)
tile (lua object) ==> The battle must take place on this tile
{integer X,integer Y} ==> The battle must be on tile (X,Y), but for any allowable map
{integer X, integer Y, integer Z} ==> battle must take place on tile (X,Y,Z)
{integer xMin, integer xMax, integer yMin, integer yMax}
==> a battle tile must satisfy xMin <= x <= xMax and yMin <= y <= yMax
table of (other specification types) ==> battle must satisfy one of the specified locations
function (attackerTile (lua object),defenderTile (lua object)) --> boolean
==> if true, location conditions satisfied, if false, they are not. Overrides locationAttacker and locationDefender
defeatedUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
killingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
defendingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
attackingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
specialCondition
Possible Values
absent (i.e. nil) ==> no special conditions
function(killingUnit,defeatedUnit)--> boolean ==> trigger only works if this function returns true
I would like the input both of those likely to make (or convert to lua) scenarios as well as those willing to help write this library. At the moment I'm assuming that the Lua Macro Library will have similar functionality to the ToT Macro Language, but might differ on exact details (since it may be more straightforward to program something slightly different). If any scenario maker/converter feels that the idiosyncrasies of the ToT Macro Language are important, please speak up, specify exactly what the idiosyncrasies are, and preferably cite the use case.
I would like everyone interested to help design these specifications, so that they reflect what people actually want, not what I think they might want (and my "lua time" at the moment is focused on Over the Reich anyway).
What kind of functionality should be included? At the moment I'm thinking functionality likely to apply to a wide range of scenarios. For example, I won't be including the carrier and radar functionality I'm making for Over the Reich, since they only apply to modern scenarios, but I'll consider including my 'help key' functionality, since a lot of people might want that (but it might be better to leave it as a stand alone library). 'K'-Units functionality will probably be included, since that's applicable to a lot of scenarios.
GOAL: Provide a template events.lua file and associated "library" files such that all a scenario maker has to do is fill in tables in events.lua in order to achieve functionality. This library should provide similar functionality to the "Test of Time Macro Language," but the functionality might not be exactly the same. This will also seek to expand "macro" functionality to take advantage of features enabled by Lua.
Specification overview:
An event will be defined by a table that has "trigger conditions" and "action details" described by entries in a table. Not all keys will be used for all events (in fact, most events will probably only use a small part of available conditions and actions), so events should always do sensible things when an event key is missing.
Events will be divided into "categories" based on when they are checked for triggering.
Most event categories will be based on the "civ.scen" function that triggers them
https://forums.civfanatics.com/threads/totpp-lua-function-reference.557527/#civ.scen
but some triggers might be broken up into multiple categories if that makes more sense (e.g. it might be reasonable to split key press events into several categories).
The first order of business is to specify the functionality that the "Lua Macro" will have. It makes sense to split the specification of trigger checking into the different "categories," but we shouldn't duplicate the "action details" effort for every category.
So we have two classes of specifications to make:
1. Trigger Checks for each desired Category
2. Action Details for each Action Type (display text, create unit, etc.)
Which leaves the question of where to specify Action Details that only apply to a single category, such as "create unit at location of combat." I'm not sure of the answer to that.
Here is my proposed specification for Unit killed event triggers:
Spoiler Unit Killed Event Trigger Specification :
Each unit killed event will be specified by its own table, with the following possible keys
======================================================================================
Trigger condition keys
defeatedUnit
Possible Values
absent (i.e. nil), true, --> any defeated unit fires the trigger
integer --> i.d. number of the unittype that fires the trigger
unittype (lua object) --> lua unittype object of the unit that fires the trigger
string --> name of the unittype that fires the trigger
table of integers, unittypes, strings --> everything in table fires the trigger
killingUnit
Possible Values
absent (i.e. nil), true ==>> any attacking unit fires the trigger
integer ==>> i.d. number of the unittype that fires the trigger
unittype (lua object) ==>> lua unittype object of the unit that fires the trigger
string ==>> name of the unittype that fires the trigger
table of integers, unittypes, strings ==>> everything in table fires the trigger
defeatedDefenderOnly
Possible Values
absent ==>> same as false
true ==>> The defeated unit must have been the defender in combat
false ==>> The defeated unit can be either attacker or defender
defeatedAttackerOnly
Possible Values
absent ==> same as false
true ==> The defeated unit must have been the attacker in combat
false ==> The defeated unit can be either attacker or defender
defeatedUnitTribe
Possible Values
absent (i.e. nil), true ==> The defeated unit can be from any tribe
integer ==> defeated unit must be from tribe with this id number
tribe (lua object)==> tribe object of the tribe that must be defeated
string ==> defeated unit's tribe must have this name
table of integers, tribes, strings ==> everything in table fires the trigger
killingUnitTribe
Possible Values
absent (i.e. nil), true ==> The killing unit can be from any tribe
integer ==> killing unit must be from tribe with this id number
tribe (lua object) ==> tribe object of the tribe that must be killing
string ==> killing unit's tribe must have this name
table of integers, tribes, strings ==> everything in table fires the trigger
beforeTurn
Possible Values
absent (i.e. nil), true ==> event can be triggered until end of scenario
integer ==> event can only be triggered on this turn or before it
afterTurn
Possible Values
absent (i.e. nil), true ==>event can be triggered since the start of the scenario
integer ==> event can only be triggered on this turn or later
justOnce
Possible Values
absent(i.e. nil) ==> same as false
true ==> this event can happen only once (separate tribes need separate events)
false ==> this event happens every time the conditions are met
oncePerTurn
Possible Values
absent (i.e. nil) ==> same as false
true ==> this event can happen only once per turn (separate tribes need separate events)
false ==> this event happens every time the conditions are met
flagTable
Possible Values
absent (i.e. nil) ==> no flags to be checked
table ==> This is the table where flags for this event are stored
allFlags
let thisFlagTable be the table specified by the flagTable parameter
Possible Values
absent (i.e. nil) ==> nothing to check, so event happens as other conditions dictate
string ==> event happens if thisFlagTable[string] is true
table of strings ==> event happens if thisFlagTable[stringInAllFlagsTable] is true for all strings in the table
map
Possible Values
absent (i.e. nil), true ==> The battle can take place on any map
0,1,2,3 ==> number of the map the battle can take place on
table of 0,1,2,3 ==> battle can take place on any map specified
locationAttacker
Possible Values
absent (i.e. nil) ==> same as false
true ==> location must be true for the tile the attack was made from
false ==> battle location can be true for either attacker's tile or defender's tile
locationDefender
Possible Values
absent (i.e. nil) ==> same as false
true ==> location must be true for the defender's tile
false ==> battle location can be true for either attacker's tile or defender's tile
location
Possible Values
absent (i.e. nil) ==> The battle can take place on any tile (subject to map restriction)
tile (lua object) ==> The battle must take place on this tile
{integer X,integer Y} ==> The battle must be on tile (X,Y), but for any allowable map
{integer X, integer Y, integer Z} ==> battle must take place on tile (X,Y,Z)
{integer xMin, integer xMax, integer yMin, integer yMax}
==> a battle tile must satisfy xMin <= x <= xMax and yMin <= y <= yMax
table of (other specification types) ==> battle must satisfy one of the specified locations
function (attackerTile (lua object),defenderTile (lua object)) --> boolean
==> if true, location conditions satisfied, if false, they are not. Overrides locationAttacker and locationDefender
defeatedUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
killingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
defendingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
attackingUnitHomeCity
absent (i.e. nil), true ==> the unit can have any home city
tile (lua object) ==> the unit's home city must be on this tile
integer ==> the unit's home city must have this id number
{integer X, integer Y} ==> the unit's home city must be at (X,Y) but on any map
{integer X, integer Y, integer Z} ==> the unit's home city is at tile (X,Y,Z)
string ==> the unit's home city must have exactly this name
false ==> the unit must have no home city
table of (other specification types)
specialCondition
Possible Values
absent (i.e. nil) ==> no special conditions
function(killingUnit,defeatedUnit)--> boolean ==> trigger only works if this function returns true
I would like the input both of those likely to make (or convert to lua) scenarios as well as those willing to help write this library. At the moment I'm assuming that the Lua Macro Library will have similar functionality to the ToT Macro Language, but might differ on exact details (since it may be more straightforward to program something slightly different). If any scenario maker/converter feels that the idiosyncrasies of the ToT Macro Language are important, please speak up, specify exactly what the idiosyncrasies are, and preferably cite the use case.
I would like everyone interested to help design these specifications, so that they reflect what people actually want, not what I think they might want (and my "lua time" at the moment is focused on Over the Reich anyway).
What kind of functionality should be included? At the moment I'm thinking functionality likely to apply to a wide range of scenarios. For example, I won't be including the carrier and radar functionality I'm making for Over the Reich, since they only apply to modern scenarios, but I'll consider including my 'help key' functionality, since a lot of people might want that (but it might be better to leave it as a stand alone library). 'K'-Units functionality will probably be included, since that's applicable to a lot of scenarios.