Event Scripting Common Tasks

== Event that happens only once ==
You may use the turn callback and react to a particular turn / year number for a unique event
function begin_ancient_era()
 -- Event that happens at 2000 BC here
end
function turn_cb(turn, year)
 if year == -2000 then
 begin_ancient_era()
 end
end
signal.connect('turn_started', 'turn_cb')
You can save a flag if an event was already performed
function city_was_lost(city, loser, winner)
 if winner:is_human() and not did_win_first_city then
 -- remember that we did this
 did_win_first_city = true
 -- now handle the event
 notify.player(winner, "Congratulations, you have taken your first city")
 end
end
signal.connect('city_lost', 'city_was_lost')
-- NOTE: We don't use the 'local' word in front of the did_win_first_city variable, because this variable
-- is a global variable (will be saved in the savegame)
== Equality test ==
As of Freeciv 2.2, you may not use the equality operator == to directly compare API objects such as players, cities, units etc. Instead you must compare objects by the id field or rule name (if applicable).
For example:
-- let us pretend we know that id #110 is the city of Paris
paris_city_id = 110
function city_was_lost(city, loser, winner)
 -- see if Paris was lost
 if city.id == paris_city_id then
 notify.all("Paris lost!")
 end
 -- NOTE: we can't use city == find.city(paris_city_id)
end
function unit_was_moved(unit, src_tile, dst_tile)
 if unit.utype:rule_name() == "Archers" then
 -- handle archers moved
 end
 -- NOTE: we can't use unit.utype == find.unit_type("Archers")
end
== Terrain Class ==
You can use a lookup table to check which class of terrain a tile has
function unit_was_moved(unit, src_tile, dst_tile)
 local bad_terrain = {
 Glacier = true,
 Desert = true,
 }
 
 local oceanic_terrain = {
 Ocean = true,
 Lake = true,
 ["Deep Ocean"] = true,
 }
 if bad_terrain[dst_tile.terrain:rule_name()] then
 notify.player(unit.owner, "This place is not so welcoming") 
 end
end
== Iteration ==
It can be practical to go through every object of a kind in a scenario script. Freeciv includes lookup functions by default in the API but no looping constructs (As of Freeciv 2.2). Here is how to define looping constructs for iteration in scripts.
The following code defines
* players_iterate
* whole_map_iterate
* unit_types_iterate
* cities_iterate
* units_iterate
Example use:
local nunits = 0
for player in players_iterate() do
 nunits = nunits + player:num_units()
end
notify.all("There are " .. nunits .. " units in the game")
Implementation: (to be copied into your scenario or ruleset script)
do
 -- iterate over the values returned by lookup
 -- until nil is returned:
 -- lookup(0), lookup(1), lookup(2), etc
 local function index_iterate(lookup)
 local index = -1
 local function iterator(lookup)
 index = index + 1
 return lookup(index)
 end
 return iterator, lookup
 end
 -- Iterate over all players of the game
 -- NOTE: This function needs Freeciv 2.1 or 2.2.1 (not 2.2.0) due to bugs in find.player
 -- In 2.2.0, it returns all 32 players of the game.
 function players_iterate()
 return index_iterate(find.player)
 end
 -- Iterate over all tiles of the game
 -- NOTE: This function needs Freeciv 2.2.1 due to bugs in find.tile
 function whole_map_iterate()
 return index_iterate(find.tile)
 end
 function unit_types_iterate()
 return index_iterate(find.unit_type)
 end
 -- NOTE: Identical further definitions can be made for
 -- governments, tech_types, building_types etc
end
do
 -- Iterate over a player objects (cities or units)
 -- lookup function takes two arguments: lookup(player, index)
 local function player_object_iterate(player, nobjs, lookup)
 local found_objs = 0
 local index = -1
 local function iterator()
 if found_objs == nobjs then
 return nil
 end
 local obj = nil
 repeat
 index = index + 1
 obj = lookup(player, index)
 until obj ~= nil
 found_objs = found_objs + 1
 return obj
 end
 return iterator, nil
 end
 -- Iterate over all cities of 'player'
 -- if player is nil, iterate over all cities
 function cities_iterate(player)
 local ncities = 0
 if player then
 ncities = player:num_cities()
 else
 for plr in players_iterate() do
 ncities = ncities + plr:num_cities()
 end
 end
 return player_object_iterate(player, ncities, find.city)
 end
 -- Iterate over all units of 'player'
 -- if player is nil, iterate over all units
 function units_iterate(player)
 local nunits = 0
 if player then
 nunits = player:num_units()
 else
 for plr in players_iterate() do
 nunits = nunits + plr:num_units()
 end
 end
 return player_object_iterate(player, nunits, find.unit)
 end
end
Category:Event scripting