[TOTPP] Lua Scenario Template

Hello @Prof. Garfield,
I've downloaded your LUA template files and tried to use it for a new scenario. When I'm loading the savefile the LUA console displays the following error messages:
upload_2021-12-30_13-31-57-png.617558


May I ask you for checking this please? I didn't change anything on the template files

It looks like you haven't upgraded to TOTPPv0.17.
 
Just another little question. I'm using your autoCanBuild code generator and unfortunatelly I can't select any cities.
I never had that problem before with my other object.lua files.

I don't think that there are some syntax errors as I used your script for creating the object.lua file.
Could you check them for me please?
 

Attachments

Just another little question. I'm using your autoCanBuild code generator and unfortunatelly I can't select any cities.
I never had that problem before with my other object.lua files.

I don't think that there are some syntax errors as I used your script for creating the object.lua file.
Could you check them for me please?

Load your game and try running makeObjectJS.lua again. It looks like you were still using the 'default' object.lua file (the one that ships with the template) when you ran makeObjectJS.lua, and that file doesn't have cities registered. (It will also give incorrect object keys for the other items as well.)

I'll adjust the template to add a pop up warning in this situation.
 
I updated the template to add integration for my custom music patch. If the player doesn't have it, everything should still work as normal for that player.

Code:
-- The custom music module is not directly included in the Lua Scenario Template
-- because it involves overwriting files in <ToT Directory>\Music,
-- and I think that should be something the end user actively chooses to allow 
-- or not.
--
-- The end user adds some lua files to <ToT Directory>\lua in order to enable
-- custom music, in particular customMusic.lua.  The installation instructions
-- can be found through this link
-- https://forums.civfanatics.com/threads/totpp-custom-music-patch.650161/#post-15555342
--
--  How to Use
--  Create a directory <Main Scenario>\Music
--
--  In Game.txt, find the section @PICKMUSICTOT
--  Change the options provided to the names you wish to give the music
--  (Any option that is not changed will play the original music)
--  There should always be 13 tracks
-- 
--  Add the .mp3 music files to <Main Scenario>\Music.
--  Rename these files to match the track names provided in @PICKMUSICTOT,
--  including spaces, but excluding the " marks at the start and end of the
--  name (if you didn't use " marks at the start and end, that's fine)
--  You can optionally place an underscore (_) at the start of the file, which
--  would enable the end user to easily copy your music to their <ToT Directory>\Music
--  folder to add it to a playlist
--
--  For example
--[[
@PICKMUSICTOT
@width=480
@title=Select Music
@options
"Funeral March"
"Ode to Joy"
"American Revolution"
"Aristotle's Pupil"
"Augustus Rises"
"Gautama Ponders"
"Hammurabi's Code"
"Harvest of the Nile"
"Jihad"
"Tenochitlan Revealed"
"The Civil War"
"The Great War"
"The Shining Path"
--]]
-- would have the following file names
--[[
Funeral March.mp3
Ode to Joy.mp3
American Revolution.mp3
Aristotle's Pupil.mp3
Augustus Rises.mp3
Gautama Ponders.mp3
Hammurabi's Code.mp3
Harvest of the Nile.mp3
Jihad.mp3
Tenochitlan Revealed.mp3
The Civil War.mp3
The Great War.mp3
The Shining Path.mp3
--]]
-- or 
--[[
_Funeral March.mp3
_Ode to Joy.mp3
_American Revolution.mp3
_Aristotle's Pupil.mp3
_Augustus Rises.mp3
_Gautama Ponders.mp3
_Hammurabi's Code.mp3
_Harvest of the Nile.mp3
_Jihad.mp3
_Tenochitlan Revealed.mp3
_The Civil War.mp3
_The Great War.mp3
_The Shining Path.mp3
--]]
-- Note that Funeral March and Ode to Joy would be optional to include, since
-- music with the same name will exist in the base Test of Time Music, which
-- would play if it is missing
-- (Actually, that is true of all the music examples here, since they are files
-- included with the Custom Music Patch)

I also updated makeObjectJS.lua so that it warns you if you run it while the default object.lua is still registered.
 
Hello Prof,

unfortunatelly I have currently an error message where I don't know what I should do to solve it. Could you help me please?
I'm using the following code for a captured city in the consolidatedEvents.lua:
Code:
function events.onCityTaken(city,defender)
    --civ.ui.text(city.name.." captured from the "..defender.name.." by the "..city.owner.name..". Consolidated Events.")

--NORTH AMERICA
--Mannahattan conquered and renamed to New Amsterdam
if city == object.cMannahattan and defender == object.pRebels then
    gen.justOnce("Mannahattan conquered",function ()
    object.cMannahattan.name = "New Amsterdam"
    local dialog = civ.ui.createDialog()
        dialog.title = "Colonization of the New World: Manhattan purchased"
        dialog.width = 600
    local multiLineText = ""..tostring(conqueror.adjective).." merchants purchased the island of Manhattan..."
        text.addMultiLineTextToDialog(multiLineText,dialog)
        dialog:show()
    local tileToChange = civ.getTile(41, 65, 0)
        tileToChange.baseTerrain = object.bVillage
    end)   
end

When conquering the city, the Lua console shows me the following error message:
upload_2022-1-2_19-13-39.png


I'm a little bit confused, because in my old Reformation scenario this code worked well.
 
This is the code, which is located in line 127:
Code:
    gen.justOnce("Mannahattan conquered",function ()

In line 132:
Code:
local multiLineText = ""..tostring(conqueror.adjective).." merchants purchased the island of Manhattan from the Canarsie, a small Lenape..."
 
You haven't defined conqueror. Just above the console message you showed, is an explanation that you've tried to refer to a global variable. Since conqueror wasn't defined as a local variable, the game tries to look in the 'global table', but I've forbidden this so that you get this error instead of something more cryptic, or, worse, no error at all but undesired functionality.

Add a line
Code:
local conqueror = city.owner
 
Again many thanks @Prof. Garfield :thumbsup:
Now that you mention it, I see the explanation. I'm still a poor noob in programming even if I'm able to use easy scripts. But I promise I will try to understand at lesat the basic mechanics in future.
 
I updated the template to add integration for my custom music patch. If the player doesn't have it, everything should still work as normal for that player.

I might need to pick your brain on this one. I've created or sourced a number of sounds I'm quite pleased with but the .wav files are huge and I'd prefer to use them as .mp3 - while I can take the original .wav and convert it to an mp3 easily enough, I can't get the game to actually play it. I'm not sure how to have them keep their .wav extension as suggested in the patch notes. Did you have to explore this as part of your music patch and did you figure out what you had to do to get the mp3s to play in-game, or is music different that sounds?

Edit - and as usually happens, I decide to try google right after and figure it out. Here's the solution in case anyone was wondering:

https://www.softwarert.com/show-change-file-extensions-windows-10/
 
Does attack bonus settings not work for missile units or maybe air by default? I've noticed it is working very well with land units but I can't get the shells to show the bonus in the civilopedia.
 
Does attack bonus settings not work for missile units or maybe air by default? I've noticed it is working very well with land units but I can't get the shells to show the bonus in the civilopedia.

It's supposed to. Try using the 'a' key to activate the shell manually, and see if the correct power is shown in the civlopedia. If it is, then there is some issue with the activation events not running for the newly created (and activated) munitions, and I'll have to take a closer look.

Actually, send me the files anyway, so I can track down the problem, whatever it is.
 
The attack bonus template module is fine, so anyone else using it doesn't need to wait for an updated file. Some code specific to the scenario was undoing the bonus in certain circumstances, and I provided a fix.
 
Can you please point me in the right direction of where to make the following changes, and if achieving what I desire requires me to download the latest version of the template or if it should work with what I sent you?

1. I would like to make it so that air units always defend a stack first when attacked by air units so I can avoid having super tanks defend against fighters.
2. I would like to make it so that certain units (tanks) inside a city or on one type of terrain (rubble) a) defend after infantry and b) have their defense stat reduced.
3. In relation to that, I would like to boost infantry's defense rating when in a city or on rubble terrain, and ensure it will defend before tanks.

Are these going to be combatResolution tasks or is there a different place I want to take a stab at them? I know I've heard you talk about these but can't remember where you made the changes. You'd think #1 is probably something @CurtSibling might want to add to Overlords if he hasn't already as well.
 
1. I would like to make it so that air units always defend a stack first when attacked by air units so I can avoid having super tanks defend against fighters.
2. I would like to make it so that certain units (tanks) inside a city or on one type of terrain (rubble) a) defend after infantry and b) have their defense stat reduced.

Somewhere in your code, you would have to write a function
Code:
local function onChooseDefender(defaultFunction,tile,attacker,isCombat)
    -- compute the desired defender
    return desiredDefender
end
and register it with
Code:
civ.scen.onChooseDefender(onChooseDefender)
This is the code I provided you for Cold War to make air units defend first
Code:
local function chooseDefender(defaultFunction,tile,attacker,isCombat)
    local function hasAirGroundStack(tile)
        local groundOrSea = false
        local air = false
      
        if tile.city or gen.hasAirbase(tile) then
            return false
        end
  
        for unit in tile.units do
            if gen.isCarryAir(unit.type) then
                return false
            end
            if unit.type.domain ==1 and unit.type.range >= 2 then
                air = true
            else
                groundOrSea = true
            end
        end
        return air and groundOrSea
    end
    local function adjustedAttack(unit)
        local attack = unit.type.attack
        if unit.veteran then
            attack = attack*1.5
        end
        return attack
    end
  
    -- note: this doesn't factor in much,
    -- since air units don't gain terrain
    -- bonus, and don't have a vs air bonus
    local function adjustedDefense(airUnit)
        local defense = airUnit.type.defense
        if airUnit.veteran then
            defense = defense*1.5
        end
        return defense
    end
    local function defenseRating(airUnit)
        return adjustedDefense(airUnit)*(airUnit.hitpoints)//(airUnit.type.hitpoints)
    end
    local function selectAirDefender(tile)
        local unitChosen = nil
        local defensiveValue = 0
        for airUnit in tile.units do
            if airUnit.type.domain ==1 and airUnit.type.range >= 2 then
                local ad = defenseRating(airUnit)
                if ad > defensiveValue then
                    defensiveValue = ad
                    unitChosen = airUnit
                end
            end
        end
        return unitChosen
    end
    if gen.isAttackAir(attacker.type) and hasAirGroundStack(tile) then
        return selectAirDefender(tile)
    else
        return defaultFunction(tile,attacker)
    end
end
civ.scen.onChooseDefender(chooseDefender)
Let me know if you need more help for this.

2. I would like to make it so that certain units (tanks) inside a city or on one type of terrain (rubble) a) defend after infantry and b) have their defense stat reduced.
3. In relation to that, I would like to boost infantry's defense rating when in a city or on rubble terrain, and ensure it will defend before tanks.

For this, you will need to use initiateCombat.lua, which you are already using and have several copies to change with batch files.

The current version of the template has choosing a defender and initiating combat in the same file, (MechanicsFiles\combatSettings.lua), and has a computeCombatStatistics function to be referred to by both of them. You may want to look at it.

Are these going to be combatResolution tasks or is there a different place I want to take a stab at them? I know I've heard you talk about these but can't remember where you made the changes.
FYI, I noticed that you have an event in combatResolution (capturing a fort automatically), but your events.lua file has onResolveCombat commented out (my template did this once onResolveCombat was deprecated -- there's even a comment at the top of the file) , so that event won't happen unless you've rewritten it elsewhere.

EDIT: fixed code block.
 
Last edited:
Thanks, I was able to get everything working well. I decided just to give infantry a bonus against any defender that's in a city, to give them more of a reason to be built/higher value. Very cool module.
 
There's an important change to the template that will impact anyone who downloaded a version in November 2020 or later. I'm pretty sure this applies to @civ2units , and it may apply to others.

In the version I shipped, I wanted to make it optional to have certain files. Since the 'require' function causes an error if the file is missing, I used pcall(require,"moduleName") instead, since pcall suppresses errors, and instead just returns a boolean.

I recently realised that this is a problem, however, because if the file is there, but loading it causes an error, instead of telling you about the error, Lua will just act as if the file wasn't found at all. This will make debugging much more frustrating and difficult.

If you're not sure if your scenario is affected, open events.lua and do a search for 'pcall'. You will find numerous lines similar to
Code:
    local fileFound,prefix = pcall(require,fileName)
    local fileFound, prefix = pcall(require,"recentFeature"..tostring(fileNumber))
    pcall(require,"customMusicIntegration")

If you're not sure, send me a copy of your events.lua, and I'll be able to tell.

If you haven't done too much work on your scenario, download the latest version of the template, and copy over what you have done to the new version. If you've already done a lot of work, or aren't comfortable moving the code, send me a copy of your scenario and I'll make the changes line by line.
 
If anyone downloaded the template in the last couple hours (since my last update), a bug will prevent the unitKilled (and possibly onNegotiation) events from happening. To fix it, replace the events.lua with the one currently in the repository.
 
Back
Top Bottom