Thalassicus
Bytes and Nibblers
This is a library of Lua utilities I created as part of the Civ V Unofficial Patch. To get the library, download CiVUP by searching the Civ V Mod Browser for the Unofficial Patch and Vanilla Enhanced package (Main Menu > Mods > Browse Mods, search for " civup ").
While working on a mod it's often useful to print information to the console when fixing bugs. This utility is a powerful extension of the standard print function.
To use this utility:
Valid output levels are similar to log4j:
These are listed from most to least important. If the logger level is set to "ERROR", only fatal and error messages will display. At the "TRACE" level, all messages will display. These messages appear in the Tuner console.
Say you want to display someVariable, then check if it equals a test value:
If the logger level is set to DEBUG and the condition holds true, this will display in the Live Tuner console:
When you're ready to release your mod, you can change setLevel("DEBUG") to setLevel("ERROR") and nothing will display but critical error messages.
\TU_LuaEvents.lua
LuaEvents.TU_Initialize()
LuaEvents.ActivePlayerTurnStart_Turn()
LuaEvents.ActivePlayerTurnStart_Player(player)
LuaEvents.ActivePlayerTurnStart_Unit(unit)
LuaEvents.ActivePlayerTurnStart_City(city, owner)
LuaEvents.ActivePlayerTurnStart_Plot(plot)
LuaEvents.ActivePlayerTurnEnd_Turn()
LuaEvents.ActivePlayerTurnEnd_Player(player)
LuaEvents.ActivePlayerTurnEnd_Unit(unit)
LuaEvents.ActivePlayerTurnEnd_City(city, owner)
LuaEvents.ActivePlayerTurnEnd_Plot(plot)
LuaEvents.NewCity(hexPos, playerID, cityID, cultureType, eraType, continent, populationSize, size, fowState)
LuaEvents.NewUnit(playerID, unitID, hexVec, unitType, cultureType, civID, primaryColor, secondaryColor, unitFlagIndex, fogState, selected, military, notInvisible)
LuaEvents.NewImprovement(hexX, hexY, cultureArtID, continentArtID, playerID, engineImprovementTypeDoNotUse, improvementID, engineResourceTypeDoNotUse, resourceID, eraID, improvementState)
LuaEvents.PlotAcquired(plot, newOwnerID)
LuaEvents.PolicyAdopted(policyID, isPolicy)
LuaEvents.CityOccupied(city, player, isForced)
LuaEvents.CityPuppeted(city, player, isForced)
LuaEvents.CityLiberated(city, player, isForced)
LuaEvents.PromotionEarned(unit, promotionType)
LuaEvents.UnitUpgraded(unit)
LuaEvents.BuildingConstructed(player, city, buildingID)
LuaEvents.BuildingDestroyed(player, city, buildingID)
LuaEvents.CheckPlotBuildingsStatus(plot)
\TU_Utils.lua
Game.DoOnce(str)
Game.DeepCopy(object)
Game.Literalize(str)
Game.GetTruthTableResult(truthTable, inputs)
Game.IsBetween(lower, mid, upper)
Game.Constrain(lower, mid, upper)
Game.Round(num, places)
RoundDown(num, idp)
Game.Shuffle(t)
Game.Reverse(t)
Game.Contains(list, value)
Game.GetMaximum(list)
Game.GetRandomWeighted(list, size)
Game.RemoveExtraNewlines(str)
\TU_LoadSave.lua
LoadValue(...)
SaveValue(value, ...)
LoadPlayer(player, ...)
SavePlayer(player, value, ...)
LoadCity(city, ...)
SaveCity(city, value, ...)
LoadUnit(unit, ...)
SaveUnit(unit, value, ...)
LoadPlot(plot, ...)
SavePlot(plot, value, ...)
\TU_Initialize.lua
Events.LoadScreenClose.Add(function() MapModData.VEM.Initialized = true end)
\Core\TU_City.lua
City_GetBestPlotPurchaseCity(city, plot)
City_GetBuildingsOfFlavor(city, flavorType, budget, includeWonders)
City_GetUnitsOfFlavor(city, flavorType, budget)
City_GetBestBuildableUnit(city, flavorType, excludeSea)
City_GetBuildableUnitIDs(city)
City_GetID(city)
Map_GetCity(cityID)
City_GetNumBuilding(city, building)
City_GetNumBuildingClass(city, buildingClass)
City_GetPurchaseCost(city, itemTable, itemID)
City_GetUnitExperience(city, unitType)
City_IsBuildable(city, buildingID, continue, testVisible, ignoreCost)
City_IsPurchaseable(city, testVisible, unitID, buildingID, projectID)
City_SetResistanceTurns(city, turns)
\Core\TU_Misc.lua
Game.GetAverageHumanEra()
Game.GetAverageHumanHandicap()
Game.GetActiveHuman()
Game.GetResourceIDsOfUsage(usageType)
Game.GetSortedResourceList(sort, reverseNames)
Game.GetSpeedYieldMod(yieldID)
UI_StartDeal(arg)
Plots(sort)
Game.HasValue(conditionList, tableName)
Game.GetValue(valueName, conditionList, tableName)
Building_IsWonder(buildingType)
Improvement_GetBuildInfo(improvementType)
\Core\TU_Player.lua
You can use these functions in the format "player:GetBuildingAddonLevel(buildingID)"
PlayerClass.GetBuildingAddonLevel(player, buildingID)
PlayerClass.GetCapitalCity(player)
PlayerClass.GetDeals(player)
PlayerClass.GetPossibleDeals(player)
PlayerClass.GetMinorApproach(player, approachType)
PlayerClass.GetRivalInfluence(player, minorCiv)
PlayerClass.GetPurchaseCostMod(player, baseCost, hurryCostMod)
PlayerClass.GetResourceQuantities(player, resID)
PlayerClass.GetCitiesDemandingResource(player, resourceID)
PlayerClass.GetTraitInfo(player)
PlayerClass.GetPersonalityInfo(player)
PlayerClass.GetTurnAcquired(player, city)
PlayerClass.SetTurnAcquired(player, city, turn)
PlayerClass.GetUniqueUnitID(player, classType)
PlayerClass.GetUniqueBuildingID(player, classType)
PlayerClass.GetMinorYieldString(minorCiv, showDetails)
PlayerClass.GetCitystateThresholdString(minorCiv)
PlayerClass.HasTech(player, tech)
PlayerClass.GetImprovableResources(player)
PlayerClass.ImproveResources(player, plotList)
PlayerClass.SetHasTech(player, tech, isResearched)
PlayerClass.HasBuilding(player, building)
PlayerClass.InitUnitType(player, unit, plot, exp)
PlayerClass.InitUnitClass(player, unitClassType, plot, exp)
PlayerClass.IsAliveCiv(player)
PlayerClass.IsMilitaristicLeader(player)
PlayerClass.IsAtWarWithHuman(player)
PlayerClass.IsAtWarWithAny(player)
PlayerClass.EverAtWarWithHuman(player)
PlayerClass.HasMet(player, otherPlayer)
PlayerClass.IsAtWar(player, otherPlayer)
PlayerClass.IsAtPeace(player, otherPlayer)
PlayerClass.SetFriendship(minorCiv, majorCivID, friendship)
\Core\TU_Plot.lua
Plot_BuildImprovement(plot, improveID)
Plot_Buy(plot, player, city, cost)
Plot_GetCost(city, plot)
Plot_FindPlotType(startPlot, plotType)
Plot_GetCombatUnit(plot)
Plot_GetAreaWeights(plot, minR, maxR)
Plot_GetID(plot)
Plot_GetNearestOceanPlot(centerPlot, maxRadius, minArea)
Plot_GetPlotsInCircle(plot, minR, maxR)
Plot_IsFlatDesert(plot)
\Core\TU_Unit.lua
Unit_GetClass(unit)
Unit_IsCombatDomain(unit, domain)
Unit_IsWorker(pUnit)
Unit_CanUpgrade(unit, newID, budget)
Unit_GetXPStored(unit)
Unit_GetXPNeeded(unit)
GetExperienceForLevel(level)
Unit_Replace(oldUnit, unitClass)
Unit_ReplaceWithType(oldUnit, unitType)
- Lua Logger
- Events
- Helper functions
- Lua Logger -
While working on a mod it's often useful to print information to the console when fixing bugs. This utility is a powerful extension of the standard print function.
- Based on the industry standard log4j testing framework.
- Your mod won't spam the lua console when other modders need to use it.
- Automatically converts invalid variables to strings (nil outputs as "nil"), eliminating the need to tostring(...) variables that might not be initialized.
- Testers of your mod can easily enable specific levels of debug output without any programming knowledge, providing you valuable feedback.
- Built-in support for string.format codes to customize your debug output:
PHP:
logger:Info("GiveMilitaristicRewards %15s rateMod=%.2f turnRate=%i",
player:GetName(), rateMod, turnRate)
output:
myModName: INFO: GiveMilitaristicRewards Augustus 1.21 6
myModName: INFO: GiveMilitaristicRewards Nebuchadnezzar 1.76 3
myModName: INFO: GiveMilitaristicRewards Elizabeth 1.53 4
- Add TU_LuaLogger.lua to your project
- Set "Import Into VFS" to True for TU_LuaLogger.lua.
- Include the file at the top of your code.
- Create a logger.
- Set output level.
- Send the logger messages.
PHP:
include( "TU_LuaLogger.lua" )
local logger = Game.LuaLogger:New()
logger:SetLevel("DEBUG")
logger:Info("Loading ThalsUtilities")
- FATAL
Critical errors where the mod cannot continue execution. Sending a Fatal message to the logger prints the message, terminates execution of the active Lua thread, and prints a trace of function calls which led to the error.
Example: A function expects an integer for one of its parameters but receives a nil value.
- ERROR
Other errors or unexpected conditions, but the mod can continue processing.
Example: A map script attempted to place 10 resources, but could only find locations for 9 resources.
. - WARN
'Almost' errors or undesirable situations, but not necessarily "wrong".
Example: A utility library for save-data warns users of the library that the map cache cannot be shared between mods.
. - INFO
Interesting events like starting a function.
Example: A map script prints results of natural wonder placement.
. - DEBUG
Detailed information on the flow through the system.
Example: A function prints the quantity of each terrain type around a unit before performing actions based on the surrounding terrain.
. - TRACE
Step-by-step execution path of instructions, since the ModBuddy compiler can't do that for Lua.
Example: For every building, a function prints the yield type and quantity of every policy each player has which improves those buildings.
These are listed from most to least important. If the logger level is set to "ERROR", only fatal and error messages will display. At the "TRACE" level, all messages will display. These messages appear in the Tuner console.
Say you want to display someVariable, then check if it equals a test value:
PHP:
include( "ThalsUtilities" )
local logger = Game.LuaLogger:New()
logger:SetLevel("DEBUG")
function someFunction(someVariable)
logger:Debug("someVariable = %s", someVariable);
if (someVariable ~= 42) then
logger:Warn("someVariable is not the answer to life.");
end
end
PHP:
myModName: DEBUG: someVariable = 10
myModName: WARN: someVariable is not the answer to life.
- Events -
\TU_LuaEvents.lua
LuaEvents.TU_Initialize()
LuaEvents.ActivePlayerTurnStart_Turn()
LuaEvents.ActivePlayerTurnStart_Player(player)
LuaEvents.ActivePlayerTurnStart_Unit(unit)
LuaEvents.ActivePlayerTurnStart_City(city, owner)
LuaEvents.ActivePlayerTurnStart_Plot(plot)
LuaEvents.ActivePlayerTurnEnd_Turn()
LuaEvents.ActivePlayerTurnEnd_Player(player)
LuaEvents.ActivePlayerTurnEnd_Unit(unit)
LuaEvents.ActivePlayerTurnEnd_City(city, owner)
LuaEvents.ActivePlayerTurnEnd_Plot(plot)
LuaEvents.NewCity(hexPos, playerID, cityID, cultureType, eraType, continent, populationSize, size, fowState)
LuaEvents.NewUnit(playerID, unitID, hexVec, unitType, cultureType, civID, primaryColor, secondaryColor, unitFlagIndex, fogState, selected, military, notInvisible)
LuaEvents.NewImprovement(hexX, hexY, cultureArtID, continentArtID, playerID, engineImprovementTypeDoNotUse, improvementID, engineResourceTypeDoNotUse, resourceID, eraID, improvementState)
LuaEvents.PlotAcquired(plot, newOwnerID)
LuaEvents.PolicyAdopted(policyID, isPolicy)
LuaEvents.CityOccupied(city, player, isForced)
LuaEvents.CityPuppeted(city, player, isForced)
LuaEvents.CityLiberated(city, player, isForced)
LuaEvents.PromotionEarned(unit, promotionType)
LuaEvents.UnitUpgraded(unit)
LuaEvents.BuildingConstructed(player, city, buildingID)
LuaEvents.BuildingDestroyed(player, city, buildingID)
LuaEvents.CheckPlotBuildingsStatus(plot)
- Helper Functions -
\TU_Utils.lua
Game.DoOnce(str)
Game.DeepCopy(object)
Game.Literalize(str)
Game.GetTruthTableResult(truthTable, inputs)
Game.IsBetween(lower, mid, upper)
Game.Constrain(lower, mid, upper)
Game.Round(num, places)
RoundDown(num, idp)
Game.Shuffle(t)
Game.Reverse(t)
Game.Contains(list, value)
Game.GetMaximum(list)
Game.GetRandomWeighted(list, size)
Game.RemoveExtraNewlines(str)
\TU_LoadSave.lua
LoadValue(...)
SaveValue(value, ...)
LoadPlayer(player, ...)
SavePlayer(player, value, ...)
LoadCity(city, ...)
SaveCity(city, value, ...)
LoadUnit(unit, ...)
SaveUnit(unit, value, ...)
LoadPlot(plot, ...)
SavePlot(plot, value, ...)
\TU_Initialize.lua
Events.LoadScreenClose.Add(function() MapModData.VEM.Initialized = true end)
\Core\TU_City.lua
City_GetBestPlotPurchaseCity(city, plot)
City_GetBuildingsOfFlavor(city, flavorType, budget, includeWonders)
City_GetUnitsOfFlavor(city, flavorType, budget)
City_GetBestBuildableUnit(city, flavorType, excludeSea)
City_GetBuildableUnitIDs(city)
City_GetID(city)
Map_GetCity(cityID)
City_GetNumBuilding(city, building)
City_GetNumBuildingClass(city, buildingClass)
City_GetPurchaseCost(city, itemTable, itemID)
City_GetUnitExperience(city, unitType)
City_IsBuildable(city, buildingID, continue, testVisible, ignoreCost)
City_IsPurchaseable(city, testVisible, unitID, buildingID, projectID)
City_SetResistanceTurns(city, turns)
\Core\TU_Misc.lua
Game.GetAverageHumanEra()
Game.GetAverageHumanHandicap()
Game.GetActiveHuman()
Game.GetResourceIDsOfUsage(usageType)
Game.GetSortedResourceList(sort, reverseNames)
Game.GetSpeedYieldMod(yieldID)
UI_StartDeal(arg)
Plots(sort)
Game.HasValue(conditionList, tableName)
Game.GetValue(valueName, conditionList, tableName)
Building_IsWonder(buildingType)
Improvement_GetBuildInfo(improvementType)
\Core\TU_Player.lua
You can use these functions in the format "player:GetBuildingAddonLevel(buildingID)"
PlayerClass.GetBuildingAddonLevel(player, buildingID)
PlayerClass.GetCapitalCity(player)
PlayerClass.GetDeals(player)
PlayerClass.GetPossibleDeals(player)
PlayerClass.GetMinorApproach(player, approachType)
PlayerClass.GetRivalInfluence(player, minorCiv)
PlayerClass.GetPurchaseCostMod(player, baseCost, hurryCostMod)
PlayerClass.GetResourceQuantities(player, resID)
PlayerClass.GetCitiesDemandingResource(player, resourceID)
PlayerClass.GetTraitInfo(player)
PlayerClass.GetPersonalityInfo(player)
PlayerClass.GetTurnAcquired(player, city)
PlayerClass.SetTurnAcquired(player, city, turn)
PlayerClass.GetUniqueUnitID(player, classType)
PlayerClass.GetUniqueBuildingID(player, classType)
PlayerClass.GetMinorYieldString(minorCiv, showDetails)
PlayerClass.GetCitystateThresholdString(minorCiv)
PlayerClass.HasTech(player, tech)
PlayerClass.GetImprovableResources(player)
PlayerClass.ImproveResources(player, plotList)
PlayerClass.SetHasTech(player, tech, isResearched)
PlayerClass.HasBuilding(player, building)
PlayerClass.InitUnitType(player, unit, plot, exp)
PlayerClass.InitUnitClass(player, unitClassType, plot, exp)
PlayerClass.IsAliveCiv(player)
PlayerClass.IsMilitaristicLeader(player)
PlayerClass.IsAtWarWithHuman(player)
PlayerClass.IsAtWarWithAny(player)
PlayerClass.EverAtWarWithHuman(player)
PlayerClass.HasMet(player, otherPlayer)
PlayerClass.IsAtWar(player, otherPlayer)
PlayerClass.IsAtPeace(player, otherPlayer)
PlayerClass.SetFriendship(minorCiv, majorCivID, friendship)
\Core\TU_Plot.lua
Plot_BuildImprovement(plot, improveID)
Plot_Buy(plot, player, city, cost)
Plot_GetCost(city, plot)
Plot_FindPlotType(startPlot, plotType)
Plot_GetCombatUnit(plot)
Plot_GetAreaWeights(plot, minR, maxR)
Plot_GetID(plot)
Plot_GetNearestOceanPlot(centerPlot, maxRadius, minArea)
Plot_GetPlotsInCircle(plot, minR, maxR)
Plot_IsFlatDesert(plot)
\Core\TU_Unit.lua
Unit_GetClass(unit)
Unit_IsCombatDomain(unit, domain)
Unit_IsWorker(pUnit)
Unit_CanUpgrade(unit, newID, budget)
Unit_GetXPStored(unit)
Unit_GetXPNeeded(unit)
GetExperienceForLevel(level)
Unit_Replace(oldUnit, unitClass)
Unit_ReplaceWithType(oldUnit, unitType)