1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Thal's Modding Utilities

Discussion in 'Communitas Expansion Pack' started by Thalassicus, Nov 14, 2010.

  1. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    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 ").

    1. Lua Logger
    2. Events
    3. 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(), rateModturnRate)


    output:
    myModNameINFO:   GiveMilitaristicRewards         Augustus 1.21  6
    myModName
    INFO:   GiveMilitaristicRewards   Nebuchadnezzar 1.76  3
    myModName
    INFO:   GiveMilitaristicRewards        Elizabeth 1.53  4
    To use this utility:

    1. Add TU_LuaLogger.lua to your project
    2. Set "Import Into VFS" to True for TU_LuaLogger.lua.
    3. Include the file at the top of your code.
    4. Create a logger.
    5. Set output level.
    6. Send the logger messages.

    PHP:
    include( "TU_LuaLogger.lua" )
    local logger Game.LuaLogger:New()
    logger:SetLevel("DEBUG")
    logger:Info("Loading ThalsUtilities")
    Valid output levels are similar to log4j:
    1. 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.
    2. 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.
      .
    3. 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.
      .
    4. INFO
      Interesting events like starting a function.
      Example: A map script prints results of natural wonder placement.
      .
    5. 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.
      .
    6. 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 ~= 42then
        logger
    :Warn("someVariable is not the answer to life.");
      
    end
    end
    If the logger level is set to DEBUG and the condition holds true, this will display in the Live Tuner console:

    PHP:
    myModNameDEBUG:  someVariable 10
    myModName
    WARN:   someVariable is not the answer to life.
    When you're ready to release your mod, you can change setLevel("DEBUG") to setLevel("ERROR") and nothing will display but critical error messages.

    - 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)
     
  2. robk

    robk Chieftain

    Joined:
    Sep 8, 2006
    Messages:
    210
    Location:
    Santa Monica, CA
    mmmm, delicious. Thanks for taking the time to do this :goodjob:
     
  3. Deep_Blue

    Deep_Blue Knight

    Joined:
    Aug 2, 2005
    Messages:
    750
    Thanks for these very useful utilities.

    About Lua Logger what is it different from using print function in the code itself? it seems to me similar a print to tuner function.
     
  4. bryanw1995

    bryanw1995 Chieftain

    Joined:
    Oct 10, 2006
    Messages:
    1,457
    Location:
    San Antonio, TX
    I don't do any modding, but I definitely take advantage of your great mods. I'm not exaggerating when I say that you've made a HUGE difference in this game. Firaxis should hire you full time!
     
  5. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    @Deep_Blue
    The difference is these methods provide an easy way to disable all the print statements (by changing the output level). Otherwise you'd have to comment out every single print statement, or do an if-then for each one, either of which would be more time consuming. Leaving lots of print statements in one's mod makes it more difficult for other modders to use the tuner (have to disable yours to stop output clutter).
     
  6. Zyxpsilon

    Zyxpsilon Running Spider

    Joined:
    Oct 29, 2009
    Messages:
    3,057
    Gender:
    Male
    Location:
    On Earth
    A tricky "request", please.

    FireTuner is kinda useful when some analysis must be done while we're testing our mods and yet, as usual, it must be ALT_tabbed back & forth to get anything done.

    So, you may just know how such a feature could be added to the InGame assets or controllable panels;

    -- Minimize it to an always_on_top_Floating_Icon (possibly hovering underneath the Diplo tab in the right corner) & simply click to re-use or de-activate when done.

    Any chance you might find time to look into this issue - for me or anyone else interested?

    PS; Actually, there are a number of additional functionality that could be integrated in such a "virtual" button, if you can extrapolate - as i do - some extra (but weird!) principles based on the fact it would be there only to exploit.
     

    Attached Files:

  7. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    I'm not really as familiar with the UI as I am with data edits and lua scripting in general. There's a lot of odd design patterns the developers followed when creating the UI.
     
  8. Deep_Blue

    Deep_Blue Knight

    Joined:
    Aug 2, 2005
    Messages:
    750
    When using tuner run civ5 in windowed mode it will be easier to switch between the two applications. I also reduce graphics to minimum while testing to make things faster.
     
  9. Zyxpsilon

    Zyxpsilon Running Spider

    Joined:
    Oct 29, 2009
    Messages:
    3,057
    Gender:
    Male
    Location:
    On Earth
    On a 1680x1050 monitor, it's almost painful to be forced into some low-res windowed-mode either by choice or obligation... which i've used already-duh... i'd rather find (or recommend) an indirect solution such as the minimize_to_button described above.
     
  10. Zyxpsilon

    Zyxpsilon Running Spider

    Joined:
    Oct 29, 2009
    Messages:
    3,057
    Gender:
    Male
    Location:
    On Earth
    Shouldn't the compatibility util be applied to DiploCorner.LUA as well since InfoAddict & DK's CivRanking slots are conflicting?
     
  11. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    Well, all UI mods require merging but that's something a little more complicated. The thing about ingame / notifications is you just append new material without any coding expertise required.
     
  12. marekb

    marekb Chieftain

    Joined:
    Jun 4, 2006
    Messages:
    229
  13. Zyxpsilon

    Zyxpsilon Running Spider

    Joined:
    Oct 29, 2009
    Messages:
    3,057
    Gender:
    Male
    Location:
    On Earth
    Shooottsss... but, when dust settles (and the new patch is finally out!) we'll probably gain better opportunities to look deeper into such issues. Patience is key, i guess. Knowledge, an absolute must have.
     
  14. robk

    robk Chieftain

    Joined:
    Sep 8, 2006
    Messages:
    210
    Location:
    Santa Monica, CA
    Hiya Thal,

    The latest version of Info Addict removes the lua context from InGame.xml. Thanks for putting the reference in there but, from v8 on, it won't be necessary :D
     
  15. gruven

    gruven Chieftain

    Joined:
    May 12, 2010
    Messages:
    75
    That would be handy. I tried using them both together without merging and now I get no growth notifications at all. :( I personally didn't look into how to merge them yet, but I may be able to this weekend.
     
  16. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    For now, you can just remove the NotificationPanel.lua file from this mod and they should be compatible. I'm not actually using it yet... haven't gotten around to sitting down and working out that notification system.
     
  17. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    I've updated these utilities significantly in the past month, and now updated the documentation here in this thread. You can also see the same usage examples in the ThalsUtilities.lua file itself.

    Something that might be helpful are events to run through all units/plots/etc once per turn.
     
  18. tyetibbs

    tyetibbs Chieftain

    Joined:
    Mar 24, 2011
    Messages:
    1
    is it just me or are colloseums only giving 1 happiness? EDIT: lol nevermind, happiness limit of the population my bad.
     
  19. Thalassicus

    Thalassicus Bytes and Nibblers

    Joined:
    Nov 9, 2005
    Messages:
    11,057
    Location:
    Texas
    I've updated the documentation and download for this utility library.
     
  20. apollyon

    apollyon Chieftain

    Joined:
    Dec 24, 2001
    Messages:
    11
    How do I re-enable animated combat? I just discovered I've been creamed by air attacks the last 5-10 turns. I thought it was a new stealth unit. I love the mod and and all but where is the goddamn toggle
     

Share This Page