Small Questions Thread

Hi, a quick one for @Prof. Garfield : is there a way to capture which level of "Future Technology" has a civ reached using Lua? Given FT is a "special" tech, I'd like to know if I can do stuff based on how many levels a civ has researched,

Thanks!
 
Hi, a quick one for @Prof. Garfield : is there a way to capture which level of "Future Technology" has a civ reached using Lua? Given FT is a "special" tech, I'd like to know if I can do stuff based on how many levels a civ has researched,

Thanks!
futureTechs (get/set)
tribe.futureTechs -> integer

Returns the number of future techs the tribe has researched.
 
Hi there. I was wondering if anyone could assist with something. I'm trying to make it so player cities can only be founded on a certain terrain type. I found the function onCityFounded, but do not need a reaction to that, but rather a reaction to terrain type. Would this be a conditional? I.e., if civ.getTerrain(map, terrainType, resource) then onCityFounded == false or something along those lines? I've tried a dozen different variants and have looked at several other successful scenario events.lua files, but no luck on engineering this trick.
 
Hi there. I was wondering if anyone could assist with something. I'm trying to make it so player cities can only be founded on a certain terrain type. I found the function onCityFounded, but do not need a reaction to that, but rather a reaction to terrain type. Would this be a conditional? I.e., if civ.getTerrain(map, terrainType, resource) then onCityFounded == false or something along those lines? I've tried a dozen different variants and have looked at several other successful scenario events.lua files, but no luck on engineering this trick.
You want the onCanFoundCity event/execution point:

onCanFoundCity (since 0.18)
civ.scen.onCanFoundCity(function (unit, advancedTribe) -> boolean) -> void

Registers a function that is called to determine if `unit` can found a city at the unit's location. `advancedTribe` is `true` when picking up a hut with `unit` triggers an advanced tribe. Return `true` to allow, `false` to disallow.

The current version of the template has onCanFoundCity.lua in the EventsFiles directory. (I believe this tool is also in the consolidated and discrete events.) You'll want something like this (untested):

Code:
function register.onCanFoundCity(unit,advancedTribe)
    if unit.location.baseTerrain == object.bMountains or unit.location.baseTerrain == object.bDesert then
        return false
    end
    return true
end
 
Thanks for this, @Prof. Garfield. What do I put in place of "unit" and "advancedTribe" -- would it be something like "civ.getUnitType(0),civ.getTribe(1)"?
 
Thanks for this, @Prof. Garfield. What do I put in place of "unit" and "advancedTribe" -- would it be something like "civ.getUnitType(0),civ.getTribe(1)"?
You don't do anything. register.onCanFoundCity is a function that is run by the game when someone tries to found a city (the template handles this part). The game supplies the unit parameter (a unit object, the unit founding the city) and the advancedTribe parameter (a boolean, true or false, depending on whether this possible city is the result of an advanced tribe from a village or not). If the function returns true, the city can be founded as normal, if not, the city is not founded.

Your job is to take the unit and advancedTribe parameters, and do computations on them to determine whether a city can be founded at that particular time. In the above example, I check if the unit is on a mountain or desert tile (assuming object.lua has been built using those names), and, if so, return false telling the game the city can't be built. Otherwise, the function returns true, telling the game the city can be built (as long as it isn't adjacent to another city).
 
I see, that is very clear, thank you. So I wrote into object.lua the following:

Code:
object.bDesert = civ.getTerrain(0,0,0)

Does this make sense? And then the added code to events.lua will pick that up and process it as desert on map 0, with no resources?

I also may be dealing with the lua template incorrectly. Is that .zip file meant to be extracted into the scenario folder? I wonder this because in other scenarios, i.e. Napoleon and Caesar, those lua folders are not placed into the scenario folders. Are they meant to be extracted in the ToT folder more generally?
 
Napoleon and Caesar use Lua events, but not Prof. Garfield's Lua Scenario Template -- actually I think they both predate it. If a scenario does use the LST, those files go in the scenario folder, not the main TOT folder. Over The Reich Hinge of Fate is a scenario that uses the template, if you want a general example of file placements. (Edited to correct misinformation per posts below.)

The Lua Scenario Template is a custom framework for creating Lua events, which makes many things easier by handling a lot of details "behind the scenes". A framework like this can be very helpful, but it's not strictly required.
 
Last edited:
Over The Reich is a scenario that uses the template, if you want a general example of file placements.
Over the Reich doesn't use the template. The template was a response to how disorganised OTR's events became after "one more feature" syndrome took hold. JPetroski's Hinge of Fate does use an older version of the template.

I also may be dealing with the lua template incorrectly. Is that .zip file meant to be extracted into the scenario folder? I wonder this because in other scenarios, i.e. Napoleon and Caesar, those lua folders are not placed into the scenario folders. Are they meant to be extracted in the ToT folder more generally?
You should be extracting the Lua Scenario Template into the folder of your scenario (the same place as the custom rules.txt).

As Knighttime mentioned, not all scenarios use the Lua Scenario Template, so they will be organised differently. If you want, you can place everything in a single events.lua file. The problem is that it quickly becomes an organisational nightmare (and you run into the 200 local variable per function limit). In older scenarios, there may be instructions to change files in the TestOfTime/lua folder. This is because when we started using Lua, the game would look for extra "required" lua files in that folder first. Now, we know how to override that functionality, so the game can be made to look only in the scenario's directory (and designated subdirectories). Tools and best practices have been evolving over the past few years.

I see, that is very clear, thank you. So I wrote into object.lua the following:

Code:
object.bDesert = civ.getTerrain(0,0,0)
Does this make sense? And then the added code to events.lua will pick that up and process it as desert on map 0, with no resources?
Yes, this is correct. However, you don't have to build the whole object table yourself. The beginning of this video shows how to install the Lua Scenario Template to an existing scenario and generate an object.lua file with a script. Since the template has changed a bit, you have to move legacyEvents.txt to the EventsFiles directory instead of LuaTriggerEvents.
 
OK, I see! Well, I was able to load the object.lua script. Here is the error I'm receiving with the code typed in as we have:

Code:
Global variables are disabled

WARNING: setGuaranteeUnitActivationType was set to nil.  The functionality to guarantee that a tribe will have an active unit is disabled.  Some events may not work properly until a unit type is specified.

...Various\Scenarios\Pulp Test 2\LuaCore\generalLibrary.lua:2967: 

The variable name 'register' doesn't match any available local variables.

Consider the following possibilities:

Is 'register' misspelled?

Was 'register' misspelled on the line where it was defined?

(That is, was 'local register' misspelled?)

Was 'local register' defined inside a lower level code block?

For example:

if x > 3 then

    local register = 3

else

    local register = x

end

print(register)

If so, define 'register' before the code block:

local register = nil -- add this line

if x > 3 then

    register = 3 -- remove local from this line

else

    register = x -- remove local from this line

end

print(register)

If you really did mean to access a global variable, write:

_global.register

If you are trying to work in the console, use the command:

console.restoreGlobal()

to restore access to global variables (locals don't work well in the console)

stack traceback:

    [C]: in function 'error'

    ...Various\Scenarios\Pulp Test 2\LuaCore\generalLibrary.lua:2967: in metamethod '__index'

    ...nd Pulp Testing Various\Scenarios\Pulp Test 2\events.lua:1011: in main chunk

I did not spell register wrong in my additions. Wondering where this might have come from.

But more than that, and I need to check if this is related to any of this at all, but check this out. When I begin scenario, and reveal map, my map looks insane (this is with Catfish's graphics modpack).

But, if I start an original game with the map (not begin scenario), it all looks fine. See attached images.

This is bizarre!
 

Attachments

  • Screen Shot 2022-08-25 at 2.23.12 PM.png
    Screen Shot 2022-08-25 at 2.23.12 PM.png
    898.4 KB · Views: 26
  • Screen Shot 2022-08-25 at 2.24.45 PM.png
    Screen Shot 2022-08-25 at 2.24.45 PM.png
    1.2 MB · Views: 26
Over the Reich doesn't use the template. The template was a response to how disorganised OTR's events became after "one more feature" syndrome took hold. JPetroski's Hinge of Fate does use an older version of the template.

I think the most impressive thing about you is that OTR didn't drive you to heavy drinking or quitting lol and that you were able to use it as motivation to clean things up!
 
OK, I see! Well, I was able to load the object.lua script. Here is the error I'm receiving with the code typed in as we have:
I'm not sure what you've done.

In the EventsFiles directory, there is a file called onCanFoundCity.lua. Open this file, and you will find these contents:

Code:
-- this file can be deleted if it is unnecessary

local register = {}


-- Checking if a unit can found a city
-- Return true if the unit can found a city
-- return false if it can't
-- If any one of the consolidated event, the discrete events, 
-- or the separate file event return false, then the city
-- can't be built
-- Notes: Returning true does NOT override any normal city
-- building condition (like no adjacent cities, or cities at sea)
-- Registers a function that is called to determine if `unit` can found 
-- a city at the unit's location. `advancedTribe` is `true` when picking 
-- up a hut with `unit` triggers an advanced tribe. 
-- Return `true` to allow, `false` to disallow.

function register.onCanFoundCity(unit,advancedTribe)
    if _global.eventTesting then
        civ.ui.text("separate file onCanFoundCity for "..unit.type.name)
    end
    return true
end

return register
In here, there is the function
Code:
function register.onCanFoundCity(unit,advancedTribe)
If you change this to what I suggested earlier, it should prevent you from building cities on mountains and deserts. (Unless I made some mistake.) (The return true line is important. The other lines are some testing code that doesn't run under normal circumstances.)

Alternatively, there are functions in consolidatedEvents.lua and discreteEvents.lua that do the same thing.
 
Over the Reich doesn't use the template. The template was a response to how disorganised OTR's events became after "one more feature" syndrome took hold. JPetroski's Hinge of Fate does use an older version of the template.
Sorry, my bad! I should have checked this before posting about it -- was replying from my phone instead of from the computer where all my Civ files are located. I updated my original post to avoid misleading anyone in the future. Thank you for setting the record straight!
 
Last edited:
@ThichN I'll let Prof. Garfield address the Lua Scenario Template questions. 😅 Maybe I can help with your other issue?

But more than that, and I need to check if this is related to any of this at all, but check this out. When I begin scenario, and reveal map, my map looks insane (this is with Catfish's graphics modpack).

But, if I start an original game with the map (not begin scenario), it all looks fine. See attached images.

This is bizarre!
Catfish's graphics modpack also requires (and includes) modifications to Rules.txt. He is taking advantage of some advanced graphics features that are only supported with TOTPP, and which require simultaneous changes to both the terrain image files and also Rules.txt to teach the game how to interpret those files.

So my guess is that you've updated or replaced the Rules.txt file in the Original folder, so that a new base game works fine. But when you start a scenario, the game will first look for a Rules.txt file in the scenario folder, and use that instead. So to use Catfish's graphics modpack with a scenario, you would need to update the scenario's custom Rules.txt file with the same changes as Catfish made to the base Rules.txt. Does that make sense?

If you'd like me to research this in more depth and provide a specific list of the changes to make, let me know and I could probably put that together.
 
Last edited:
If you change this to what I suggested earlier, it should prevent you from building cities on mountains and deserts. (Unless I made some mistake.) (The return true line is important. The other lines are some testing code that doesn't run under normal circumstances.)
I successfully ran the make object script and have a valid objects.lua file. That was a great video! My success ends there, though. I added the code to onCanFoundCity.lua, but no luck. I tried writing the code in all of the files you mentioned, each of them separately -- a lot of combos, but I still get that error or a variant of it. I wholly believe that I am doing something wrong, and that it is probably something silly.
So my guess is that you've updated or replaced the Rules.txt file in the Original folder, so that a new base game works fine. But when you start a scenario, the game will first look for a Rules.txt file in the scenario folder, and use that instead. So to use Catfish's graphics modpack with a scenario, you would need to update the scenario's custom Rules.txt file with the same changes as Catfish made to the base Rules.txt. Does that make sense?
This worked like a charm! Silly me. I copied and pasted a rules.txt file from another folder from before implementing the graphics modpack. Thank you for this fix! Feeling very old today...
 
I added the code to onCanFoundCity.lua, but no luck. I tried writing the code in all of the files you mentioned, each of them separately -- a lot of combos, but I still get that error or a variant of it. I wholly believe that I am doing something wrong, and that it is probably something silly.
onCanFoundCity.lua doesn't have a line to access object.lua, so that must also be included.

This should be the entire contents of onCanFoundCity.lua:
Code:
-- this file can be deleted if it is unnecessary
local object = require("object")
local register = {}


-- Checking if a unit can found a city
-- Return true if the unit can found a city
-- return false if it can't
-- If any one of the consolidated event, the discrete events, 
-- or the separate file event return false, then the city
-- can't be built
-- Notes: Returning true does NOT override any normal city
-- building condition (like no adjacent cities, or cities at sea)
-- Registers a function that is called to determine if `unit` can found 
-- a city at the unit's location. `advancedTribe` is `true` when picking 
-- up a hut with `unit` triggers an advanced tribe. 
-- Return `true` to allow, `false` to disallow.

function register.onCanFoundCity(unit,advancedTribe)
    if unit.location.baseTerrain == object.bMountains or unit.location.baseTerrain == object.bDesert then
        return false
    end
    return true
end

return register
Check that object.bMountains and object.bDesert are correct (and fix them if they are not, or write civ.getBaseTerrain(0,5) and civ.getBaseTerrain(0,0) in their place).

If you still have problems, please upload your code, and I'll take a look.
 
@Prof. Garfield It worked! This is great, thank you. I think I understand what you mean, as well. We need to tell the file to access our object script? Is this correct?
 
Hi @Prof. Garfield another quick one:

I want to be able to use the Diplomacy/Foreign Minister screen (especially the "Check Intelligence" screen), but at the same time, I want to forbid negotiations between tribes. When I'm using the onNegotiation event, what I noticed is that when it returns false, the talker/listener tribes with forbidden negotiations don't even appear in the diplomacy screen, so I can't "check intelligence" on them.

If I uncomment the diplomacy.setEventTreatiesOnly() call on the diplomacySettings.lua, the Diplomacy/Foreign Minister screen is completely disabled.

Is there a way to block the "send emissary" option only, as well as AI diplomacy interactions, but leave the tribes visible in the screen and to be able to "check intelligence" if there's embassy established?

Thanks,

Pablo
 
Last edited:
Top Bottom