charges each player for tile extras within the radius of the player's cities. I'm still experimenting with the costs (in gold) per tile-extra-type. Here's the current list:
Code: Select all
--##############################################################################
function Lua_ExtrasUpkeep(turn, year)
if ( ExtrasUpkeep == nil ) then ExtrasUpkeep=true end
if not ( ExtrasUpkeep ) then return end
if ( debugLuaScripts == nil ) then debugLuaScripts=false end
if ( debugLuaScripts ) then log.error("%s","ExtrasUpkeep BEGIN") end
if ( _G.xSize == nil ) then
-- declare local variables
local i, topology, count, field, topoFields
topology=(server.setting.get("topology"))
_G.xSize=tonumber(server.setting.get("xsize"))
_G.ySize=tonumber(server.setting.get("ysize"))
_G.dispersion=(server.setting.get("dispersion"))
_G.citymindist=(server.setting.get("citymindist"))
_G.topo="classic"
_G.wrapX=false
_G.wrapY=false
topoFields={}
-- Split topology field (from scenario settings) to a table
local count=1
for field in string.gmatch(topology, "[^|]+") do
topoFields[count]=field
count=(count+1)
end
-- Evaluate topology settings
if ( #topoFields > 0 ) then
for i=1,#topoFields,1 do
if ( topoFields[i] == "WRAPX" ) then _G.wrapX=true
elseif ( topoFields[i] == "WRAPY" ) then _G.wrapY=true
elseif ( topoFields[i] == "ISO" ) then _G.topo="ISO"
elseif ( topoFields[i] == "HEX" ) then _G.topo="HEX" end
end
end
end
-- Declare global function
function _G.is_XY_map_location_valid(x,y)
if ( _G.wrapX and _G.wrapY )
or ( _G.wrapX and ( y >= 0 ) and ( y < _G.ySize ) )
or ( _G.wrapY and ( x >= 0 ) and ( x < _G.xSize ) )
or ( y >= 0 and y < _G.ySize and x >= 0 and x < _G.xSize ) then
return true
else
return false
end
end
local i, h, v, x, y, player, cityTile, city, tile, label, value, upkeepCostTotal, upkeepCost, payment, previousDebtBalance
local cityExtras={}
if ( _G.Debt == nil ) then _G.Debt={} end
-- Skip turn 0
if ( turn < 1 ) then
if ( debugLuaScripts ) then log.error("%s","\tExtrasUpkeep Not active yet END") end
return
end
-- Upkeep cost per tile extra
cityExtraCosts={
["Airbase"]=1,
["Buoy"]=.1,
["Fallout"]=0,
["Farmland"]=.3,
["Fortress"]=.6,
["Hut"]=0,
["Irrigation"]=.07,
["Mine"]=.05,
["Oil Well"]=.3,
["Pollution"]=0,
["Railroad"]=.03,
["River"]=0,
["Road"]=.01,
["Ruins"]=-.1
} -- Set fee rate per extra, per turn in list above, example Road=.1 (gold)
for player in players_iterate() do
-- Reset some variables for each player
previousDebtBalance=0
payment=0
upkeepCost=0
upkeepCostTotal=0
if ( _G.Debt[player] == nil ) then _G.Debt[player]=0 end
cityExtras={ ["Irrigation"]=0,["Mine"]=0,["Oil Well"]=0,["Pollution"]=0,["Hut"]=0,
["Farmland"]=0,["Fallout"]=0,["Fortress"]=0,["Airbase"]=0,["Buoy"]=0,["Ruins"]=0,
["Road"]=0,["Railroad"]=0,["River"]=0 }
for city in (player):cities_iterate() do
cityTile=(city).tile
tile=cityTile
x=(tile).x
y=(tile).y
-- Check 21 tiles in city radius for tile extras
h={-1,-0, 1,-2,-1, 1, 2, 0,-2, 2,-1, 1,-2,-1, 1, 2, 0,-1,-0, 1, 0}
v={-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 0}
for i=1,#h,1 do
if ( _G.is_XY_map_location_valid( ( h[i] + x ),( v[i] + y ) ) ) then
tile=find.tile( ( h[i] + x ),( v[i] + y ) )
for label, value in pairs(cityExtras) do
if ( (tile):has_extra(label) ) then
cityExtras[label]=( cityExtras[label] + 1 )
end
end
end
end
end
if ( (player):is_human() ) and ( _G.Debt[player] > 0 ) then
log.error("%s","\tCity tile extras upkeep expense for:" .. tostring(player) .. " gold=" .. (player):gold() .. " debt=" .. _G.Debt[player] )
end
for label, value in pairs(cityExtras) do
if ( cityExtras[label] > 0 ) then
upkeepCost=( (cityExtras[label]) * cityExtraCosts[label] )
if ( (player):is_human() ) then
log.error("%s","\t" .. label .. "\tqty:" .. cityExtras[label] .. " @ " .. cityExtraCosts[label] .. "=" .. upkeepCost )
end
upkeepCostTotal=( upkeepCostTotal + upkeepCost )
end
end
-- Add the cost to the player's account
previousDebtBalance=_G.Debt[player]
_G.Debt[player]=( upkeepCostTotal + _G.Debt[player] )
-- If player has gold and debt, deduct gold for debt payment
if ( (player):gold() > 1 ) and ( _G.Debt[player] > 1 ) then
if ( (player):gold() > _G.Debt[player] ) then
payment=math.floor( _G.Debt[player] )
else
payment=math.floor( (player):gold() )
end
_G.Debt[player]=( _G.Debt[player] - payment )
-- the next command uses "change by" amount rather than "change to" amount
edit.change_gold( player, -payment )
end
if ( (player):is_human() ) and ( _G.Debt[player] > 0 ) then
message="\n\tINVOICE - Turn " .. turn .. "- Tile extra upkeep costs for cities owned by: " .. tostring(player) .. " gold=" .. (player):gold() .. " debt=" .. _G.Debt[player] .. "\n\t\tPrior balance:\t\t\t" .. previousDebtBalance .. "\n\t\tNew charges:\t\t\t+" .. upkeepCostTotal .. "\n\t\tPayment extracted:\t-" .. payment .. "\n\t\tNew balance:\t\t\t" .. _G.Debt[player] .. " gold owed.\n"
log.error("%s",message)
--notify.event(player, nil, E.SCRIPT,message.."\n\tItemization available in Chat pane.")
end
end
if ( debugLuaScripts ) then log.error("%s","\tExtrasUpkeep END") end
end
signal.connect("turn_started", "Lua_ExtrasUpkeep")
^ Updated 2023-12-04 -- Set math.floor to ensure that payments extracted are in whole units of gold, since decimals don't actually work!
One issue is that tiles that exist in more than one city's radius are charged against the player once per each city. Instead of specifying cost in gold, it might be interesting to specify it in terms of labor-hours, and then calculate gold per labor hour, while considering government type. So in Despotism, a job that could be done in 1 turn might take 3 turns in Democracy (due to 8 hour workdays) and also might cost 100x as much per labor hour...
Attached is a playable scenario file "RandoMap with ExtrasUpkeep only" for Freeciv 2.6.4 and later for testing the routine, and which contains only this script and no others.