[TOTPP] Lua Scenario Template

Just another question.
The Thirty Years War will take place near the end of my scenario. I have some cities which could be conquered earlier in game which is ok but some events by conquering a city should only trigger between a certain time period. For example, I have Prague which is controlled by the Protestants. If the Imperials conquers the city before 1618, nothing should happen. If the Imperials conquer Prague after 1618, a text box and units should appear.

I tried this code, but LUA gave me always an error message when I conquered the city with the Imperials.
Code:
if city == object.cPrague and defender == object.tProtestant and turn >=102 and turn <= 132 then
            gen.justOnce("HRE liberates Prague",function ()
            civ.ui.text("After the Habsburgian victory at the Battle of White Mountain the Emperor has executed 27 leaders of the insurrection in Prague's Old Town Square. The Bohemian revolt is collapsed.")
            civlua.createUnit(object.uImperialPikemenII, object.tHabsburgian, {{165,39,0}}, {count=2, randomize=false, veteran=false})
            civlua.createUnit(object.uImperialMusketeers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
            civlua.createUnit(object.uCuirassiers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
        end)
    end

LUA says that there isn't a value associated with 'turn'
upload_2021-4-11_13-20-42.png


So I added this code
Code:
legacy.doCityTakenEvents(turn,tribe)
into
Code:
function triggerEvents.onCityTaken(city,defender)
    context[getContext()]["onCityTaken"](city,defender)
    universal["onCityTaken"](city,defender)
    legacy.doCityTakenEvents(city,defender)
in hope that LUA says everything is ok, but it doesn't work. Is it even possible to create a city taken event, which only appears during a certain time period?
 
in hope that LUA says everything is ok, but it doesn't work. Is it even possible to create a city taken event, which only appears during a certain time period?

I found a solution by using flags. Now it works. :)

Congratulations, but there is an easier way in this case. You simply need to set the 'turn' variable equal to the in game turn, using civ.getTurn().

Code:
local turn = civ.getTurn()
if city == object.cPrague and defender == object.tProtestant and turn >=102 and turn <= 132 then
           gen.justOnce("HRE liberates Prague",function ()
            civ.ui.text("After the Habsburgian victory at the Battle of White Mountain the Emperor has executed 27 leaders of the insurrection in Prague's Old Town Square. The Bohemian revolt is collapsed.")
            civlua.createUnit(object.uImperialPikemenII, object.tHabsburgian, {{165,39,0}}, {count=2, randomize=false, veteran=false})
            civlua.createUnit(object.uImperialMusketeers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
            civlua.createUnit(object.uCuirassiers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
        end)
    end

When an event is triggered, the game* provides certain information to the function that holds the instructions for our events. In the case of onCityTaken, the city and its previous owner are provided. Any other information we have to gather for ourselves, like the turn in this example. The information provided is given by the names of the variables in the function argument.

* In at least one case (the unit killed events) I had extra code behind the scenes to provide more information than the game itself provided.
 
@Prof. Garfield or @Knighttime
Just a quick question that will affect my current tech-tree creation - In Lua, is there a quick/simple way to restrict techs to a certain civ?

Usually, I use the Twice-Removed, Once-Removed tech method to fence off techs, but that trick
still can be exploited by civs demanding techs in diplomacy. And @Leader2 flags don't work.

Can Lua make techs exclusive and hide them from all but the target civ?
I ask this with the assumption that an Object.lua file is in place with techs listed, etc.

Cheers in advance! :)
 
And @Leader2 flags don't work.
There is a TOTPP patch for that. If it doesn't work, you should report it in the TOTPP thread, especially since TNO might still be around. Unless I misunderstand the problem.

Code:
Fixes the rule 2 restrictions in @LEADERS2 so that forbidden technologies cannot be stolen.

Can Lua make techs exclusive and hide them from all but the target civ?
I ask this with the assumption that an Object.lua file is in place with techs listed, etc.

You can certainly use Lua check if the tribe has a tech it shouldn't and take it away. The calculate city yield should give us a 'before production' event, which should allow us to change the technology prerequisites depending on the active player, so some players can research techs, while others can't. We can also access the technology being researched, and either set it to nothing being researched if the player is human (so they can select again), or change it so something else is being researched (if AI).

I haven't spent much time thinking about the tech tree, though I think Knighttime might have for Medieval Millennium, so he might have more insight.
 
Congratulations, but there is an easier way in this case. You simply need to set the 'turn' variable equal to the in game turn, using civ.getTurn().

Code:
local turn = civ.getTurn()
if city == object.cPrague and defender == object.tProtestant and turn >=102 and turn <= 132 then
           gen.justOnce("HRE liberates Prague",function ()
            civ.ui.text("After the Habsburgian victory at the Battle of White Mountain the Emperor has executed 27 leaders of the insurrection in Prague's Old Town Square. The Bohemian revolt is collapsed.")
            civlua.createUnit(object.uImperialPikemenII, object.tHabsburgian, {{165,39,0}}, {count=2, randomize=false, veteran=false})
            civlua.createUnit(object.uImperialMusketeers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
            civlua.createUnit(object.uCuirassiers, object.tHabsburgian, {{165,39,0}}, {count=1, randomize=false, veteran=false})
        end)
    end

When an event is triggered, the game* provides certain information to the function that holds the instructions for our events. In the case of onCityTaken, the city and its previous owner are provided. Any other information we have to gather for ourselves, like the turn in this example. The information provided is given by the names of the variables in the function argument.

* In at least one case (the unit killed events) I had extra code behind the scenes to provide more information than the game itself provided.

Again many thanks @Prof. Garfield for the codes. They working very well.:)
The events around the Reformation and the resulting Thirty Years War are done, so I will start a first own playtest to see if everything working like it should.
 
@Leader2 flags don't work.
There is a TOTPP patch for that. If it doesn't work, you should report it in the TOTPP thread, especially since TNO might still be around. Unless I misunderstand the problem.
...
I haven't spent much time thinking about the tech tree, though I think Knighttime might have for Medieval Millennium, so he might have more insight.
I made pretty extensive use of tech groups and the @LEADER2 flags in Medieval Millennium, and it all seemed to work properly for me. This was in TOTPP 0.15.1 so the TOTPP patch that fixes a bug isn't new to TOTPP 0.16. I agree with Prof. Garfield that it should be working correctly, so if you can demonstrate any bugs related to this in the current TOTPP version, please post details.

There are a few cases where my Medieval Millennium events either change tech prerequisites, or change the tech group to which a tech is assigned, or remove one or more techs from a tribe and change what they're currently researching. But for the most part, I relied on the initial assignment of techs to tech groups as entered into Rules.txt, and then used civ.enableTechGroup() to grant a given tribe access to a group at the appropriate time.
 
Ah! I didn't realise the more recent versions of ToTPP had addressed the infamous bug.
If a complex scenario like Medieval Millenium had the @Leader2 facility, and it worked...Then that is evidence enough for me.

I will make use of @Leader2 and see how it pans out...Thanks, chaps!
 
I've updated the template.

I spent the afternoon working on a 'calendar' module, which was surprisingly difficult since Civ II is weird with its dates for monthly turn increments. I also modified the object builder yesterday or the day before. Those files are attached to this post. I also added some (currently empty) files for some of the new functionality with totpp 16.

calendar.turnFromDate() allows you to input a date, and will return the turn for that date. By default, it returns the number of the turn 'nearest' to that date, but you can set it so that it returns the turn before or after the date, if the date doesn't fall exactly on a turn. Due to Civ II weirdness, if you have month increments, dates in year 0 can't be used, since they occur twice in the game.

I figure that this will make events for historical scenarios a bit easier to write, since you can just put the historical date of the event into the code instead of figuring out manually what the turn should be. This also means you can change the start year or year increment without necessarily changing all the events (of course, a different number of turns means different capabilities at any given time, so you might still have to change things).

I also have calendar.dateFromTurn which allows you to go in the opposite direction.

-- calendar.turnFromDate(year,month,day,beforeAfterNearest = "nearest)
-- calendar.turnFromDate(year,month,beforeAfterNearest="nearest")
-- calendar.turnFromDate(year,beforeAfterNearest="nearest")
-- finds the turn corresponding to the date given
-- beforeAfterNearest is a string with 3 possible values,
-- (not case sensitive)
-- "before" means that the turn before the date will be chosen
-- e.g. year 1528 would occur on year 1520, not year 1530
-- "after" means that the turn after the date will be chosen
-- e.g. year 1521 would occur on year 1530, not 1520
-- "nearest" means that the turn nearest the date will be chosen
-- e.g. year 1528 would occur on year 1530, not 1520
-- for odd year increments, (years with turns are in <>)
-- <20>,21,22,23,24,<25>, years are split half way
-- 21,22-><20>, 23,24-><25>
-- For even year increments
-- <20>,21,22,23,<24>, 21-><20>, 23-><24>
-- If 22 and month specified, months 1-6 -><20>, months 7-12-><24>
-- If no month specified, go to the later turn, 22-><24>
--
-- Note: For the purposes of determining the 'nearest' when there are
-- monthly increments, days 0-15 go to the earlier month, days 16-31
-- go to the later month
-- year is an integer
-- the year in question. Negative corresponds to BC years
-- NOTE: If increments are monthly, can't have year = 0,
-- since 0 year happens twice in the game, with a couple oddities
-- month is an integer 1 to 12
-- or string with month name or abbreviation (case doesn't matter,
-- but must be lower case in the table)
-- the month in question
-- day is an integer 1 to 31
local monthNames ={
["jan"]=1,
["january"]=1,
["feb"]=2,
["february"]=2,
["mar"]=3,
["march"]=3,
["apr"]=4,
["april"]=4,
["may"]=5,
["june"]=6,
["july"]=7,
["aug"]=8,
["august"]=8,
["sept"]=9,
["september"]=9,
["oct"]=10,
["october"]=10,
["nov"]=11,
["november"]=11,
["dec"]=12,
["december"]=12,
}
-- calendar.dateFromTurn(turn)--> integer, integer or nil
-- Returns the year and month (or nil, if not month increments)
-- for the turn
-- Default game years not currently supported
 

Attachments

  • CalendarMakeObject.zip
    4.9 KB · Views: 27
I would like to ask how I can add option into the dialog function. I've managed that the options can be choosen but I can't getting work the selected options itself. For example, if option 1 is selected, units should be spawn on the shores of Mexico. Whatever I tried, nothing worked. Unfortunately I too didn't find explenations or exmaples here on this forum.

upload_2021-4-15_21-54-6.png
 
I would like to ask how I can add option into the dialog function. I've managed that the options can be choosen but I can't getting work the selected options itself. For example, if option 1 is selected, units should be spawn on the shores of Mexico. Whatever I tried, nothing worked. Unfortunately I too didn't find explenations or exmaples here on this forum.
Code:
local dialog = civ.ui.createDialog()
dialog.title = "My first dialog"
dialog.width = 250
dialog:addOption("Foo", 1)
dialog:addOption("Bar", 2)
local choice = dialog:show()
if choice == 1 then
-- do code for "Foo" option
elseif choice == 2 then
-- do code for "Bar" option
end
Let me know if you need a more detailed explanation
 
I'm trying to add a unit transporter to a scenario I'm building and am having some issues. Specifically, I'm trying to plug in these three sections of code to the keyPressEvents in the module:

Spoiler :

Code:
-- UNIT TRANSPORTER
-- [[ By Sorfox]]

state.loadedTrucks = {}                                                        -- we have a nested table that holds following data: loadedTrucks[truck_ID] = {loadedUnit_ID1, loadedUnit_ID2, ...}
activeTruck = nil                                                             -- a global variable is defined

function firstTimeFakeLoadingOnTruck()
print("Within the function: firstTimeFakeLoadingOnTruck.")
local activeUnit = activeTruck                                                -- update the local variable (ID of the truck) with the data of the gloal variable, which was "filled" in the triggering functions (below) and which reference this function
local unitsOnTruck = state.loadedTrucks[activeUnit.id]                         -- initialize local variable 'unitsOnTruck' [always first action in order to be able to use it] and connect it with exactly this truck; KEY for the state.table = activeUnit/currentUnit.id
    if unitsOnTruck == nil then
       print("This truck (ID: " .. activeUnit.id .. ") has never been loaded before, so we do it by means of Lua artificially.")
       unitsOnTruck = {[1] = "firstUnitFakeLoading", [2] = "secondUnitFakeLoading"}
       state.loadedTrucks[activeUnit.id] = unitsOnTruck
       print("Case ZERO - state.table successfully updated!")                -- just for checking if formula worked
    end
end                                                                            -- 'end' of function firstTimeFakeLoadingOnTruck()

-----------------------------------------------------------------------------------------------------------------------
function loadUnitsOnTruck()
    print("Within the function: loadUnitsOnTruck.")
local unitTypeAllowedToBeLoaded = civ.getUnitType(21)                        -- defines which unit(s) can be loaded on the truck -> modifiable (!) -> references the position of '@UNITS' in 'rules.txt' file
local supplyTruckType1 = civ.getUnitType(26)                                  -- defines which unit(s) count as 'truck' (= land transporter / carrying vehicle) -> modifiable (!) -> references the position of '@UNITS' in 'rules.txt' file
local supplyTruckType2 = civ.getUnitType(118) 

local transportVehicleType = {}
transportVehicleType[21]=true
transportVehicleType[118]=true

local cargoUnitType = {}
cargoUnitType[21]=true
cargoUnitType[27]=true
cargoUnitType[37]=true
cargoUnitType[24]=true


local successfullFakeLoading = 0                                            -- helper local variable (0 = false / 1 = true)
local activeUnit = civ.getActiveUnit()
local activeTile = nil



if activeUnit then                                                             -- check that there is an active unit
   activeTile = civ.getActiveUnit().location                                 -- gets the active unit and selects the tile
else                                                                         -- if there is no active unit, then
   print("No active unit.")                                                    -- 1) show this info in the console
   return                                                                    -- 2) and end the function, since there is no point in doing any further calculation
end
    if not(cargoUnitType[activeUnit.type.id]) then                             -- if there is no unitTypeAllowedToBeLoaded /cagoUnitType on the tile then there is no point to continue the code -> Therefore: return
       print("Active unit is NOT a unitTypeAllowedToBeLoaded.")
       return
    end
    print("Active unit is a unitTypeAllowedToBeLoaded.")                    -- if this line is reached (not broken up before) there must be an active unit which is a unitTypeAllowedToBeLoaded
    for currentUnit in activeTile.units do                                     -- do a 'for loop' over every unit on the active tile, where (we already know) units of unitTypes allowed to be loaded exist
        --if currentUnit.type == supplyTruckType then
        if (currentUnit.type == supplyTruckType1 or currentUnit.type == supplyTruckType2) then
           print("loadFunction - checking the truck ID " .. currentUnit.id) -- if this line is reached (not broken up before) there must be an active unit equal to supplyTruckType
           local unitsOnTruck = state.loadedTrucks[currentUnit.id]            -- "fill" the local variable 'unitsOnTruck' with data about the loaded units (IDs) on exactly this truck; KEY for the state.table = currentUnit.id
           activeTruck = currentUnit                                        -- update the global variable, i.e. ID of the truck used right at this moment; since this funtion - in one case - jump to the funtion 'firstTimeFakeLoadingOnTruck()', where the ID is needed
            if unitsOnTruck == nil then                                        -- if this line is reached (not broken up before) there must be an active unit equal to supplyTruckType (=2nd condition) BUT it still can be a "virgin" truck, which will always result in code errors
               print("unitsOnTruck == nil | This truck (ID: " .. currentUnit.id .. ") has never been loaded before, so we do it by means of Lua artificially.")
               firstTimeFakeLoadingOnTruck()                                -- jump to and then execute this function
               successfullFakeLoading = 1                                    -- toggle local variable "on" = proof that each place of the truck is at least "fake loaded", since the line before 'function firstTimeFakeLoadingOnTruck()' did run
            end
            if unitsOnTruck ~= nil or successfullFakeLoading == 1 then        -- only now we can introduce the variables ('firstUnit'+'secondUnit') in the code, earlier there would be an error "attempt to index a nil value (global 'unitsOnTruck')" -> covered by 'firstTimeFakeLoadingOnTruck()'
               unitsOnTruck = state.loadedTrucks[currentUnit.id]
               activeTruck = nil                                            -- delete content of the global variable
               local firstUnit = unitsOnTruck[1]                            -- data of the first unit will be stored by means of their ID -> 'local' = initialize the variable within this function
               local secondUnit = unitsOnTruck[2]
                if firstUnit == nil or firstUnit == "firstUnitFakeLoading" then    -- if there is NO first - or only a "firstUnitFakeLoading" (which is also NO) - unit on the truck => LOAD IT!
                   civ.ui.text("Loading first unit on the truck.")
                   unitsOnTruck = {[1] = activeUnit.id, [2] = secondUnit}    -- 1st step of "table magic": update the locale variable 'unitsOnTruck' with the newest info about the activeUnit.id, which is now loaded in the table 
                   civ.teleportUnit(activeUnit, civ.getTile(2, 184, 2)) -- code to teleport the currently loaded unit to a certain square on night map
                   activeUnit.order = 3                                        -- after teleportation to 2. map -> unit is set to 'sleep'
                   state.loadedTrucks[currentUnit.id] = unitsOnTruck        -- 2nd step of "table magic": update the state.table with the newest info -> which was stored in the locale variable table 'unitsOnTruck' - done during the 1st step
                   currentUnit:activate()                                    -- activates the truck, after loading the 1st unit, clearing its orders, and, if it has a human owner and movement points left, selects it on the map
                     break
                  elseif secondUnit == nil or secondUnit == "secondUnitFakeLoading" then -- checking if there is still space on the selected truck (secondUnit == nil, or "secondUnitFakeLoading"), if yes => LOAD IT!
                   civ.ui.text("Loading second unit on the truck.")   
                   unitsOnTruck = {[1] = firstUnit, [2] = activeUnit.id}    -- same procedure + code as with firstUnit, but of course here the 2nd unit must be stored in the table differently => [2] = activeUnit.id
                   civ.teleportUnit(activeUnit, civ.getTile(2, 184, 2))
                   activeUnit.order = 3
                   state.loadedTrucks[currentUnit.id] = unitsOnTruck
                   currentUnit:activate()                                    -- activates the truck, after loading the 2nd unit, clearing its orders, and, if it has a human owner and movement points left, selects it on the map
                     break
                elseif (firstUnit ~= nil and firstUnit ~= "firstUnitFakeLoading") and (secondUnit ~= nil and secondUnit ~= "secondUnitFakeLoading") then
                     civ.ui.text("The truck is full, due to the fact that it is only possible to load two units on it.")   
                end
            end
        end
    end
end                                                                            -- 'end' of function loadUnitsOnTruck()

-----------------------------------------------------------------------------------------------------------------------
function unloadUnitsOffTruck()
    print("Within the function: unloadUnitsOffTruck.")
local supplyTruckType1 = civ.getUnitType(26)                         
local supplyTruckType2 = civ.getUnitType(118) 
local successfullFakeLoading = 0
local activeUnit = civ.getActiveUnit()
local activeTile = nil

if activeUnit then                                                             -- check that there is an active unit
   activeTile = civ.getActiveUnit().location                                 -- gets the acive unit and selects the tile
else                                                                         -- if there is no active unit, then
   print("No active unit.")                                                    -- 1) show this info in the console
   return                                                                    -- 2) and end the function, since there is no point in doing any further calculation
end
   
   
   
    if (activeUnit.type ~= supplyTruckType1 and activeUnit.type ~= supplyTruckType2) then -- if there is no truck on the tile then there is no point to continue the code -> Therefore: return
       print("Active unit is NOT the supplyTruckType.")
       return
    else
       print("UN-loadFunction - checking the truck ID " .. activeUnit.id)     -- if this line is reached (not broken up before) there must be an active unit equal to supplyTruckType
       local unitsOnTruck = state.loadedTrucks[activeUnit.id]                -- "fill" the local variable 'unitsOnTruck' with data about the loaded units (IDs) on exactly this truck; KEY for the state.table = currentUnit.id
       activeTruck = activeUnit                                                -- update the global variable, i.e. ID of the truck used right at this moment; since this funtion - in one case - jump to the funtion 'firstTimeFakeLoadingOnTruck()', where the ID is needed
        if unitsOnTruck == nil then                                            -- if this line is reached (not broken up before) there must be an active unit equal to supplyTruckType (=2nd condition) BUT it still can be a "virgin" truck, which will always result in code errors
           print("unitsOnTruck == nil | This truck (ID: " .. activeUnit.id .. ") has never been loaded before, so we do it by means of Lua artificially.")
           firstTimeFakeLoadingOnTruck()                                    -- from that code line on -> each place of the truck is at least "fake loaded"
           successfullFakeLoading = 1
        end
        if unitsOnTruck ~= nil or successfullFakeLoading == 1 then            -- only now we can introduce the variables ('firstUnit'+'secondUnit') in the code, earlier there would be an error "attempt to index a nil value (global 'unitsOnTruck')" -> covered by 'firstTimeFakeLoadingOnTruck()'
           unitsOnTruck = state.loadedTrucks[activeUnit.id]
           activeTruck = nil                                                -- delete content of the global variable
           local firstUnit = unitsOnTruck[1]                                -- data of the first unit will be stored by means of their ID -> 'local' = initialize the variable within this function
           local secondUnit = unitsOnTruck[2]
            if (firstUnit == nil or firstUnit == "firstUnitFakeLoading") and (secondUnit == nil or secondUnit == "secondUnitFakeLoading") then    -- Case ONE: the respective truck is empty
               civ.ui.text("There are NO units to unload from this (ID: " .. activeUnit.id .. ") empty truck.")
               return
            elseif firstUnit ~= nil and firstUnit ~= "firstUnitFakeLoading" then
               local firstUnitComplete = civ.getUnit(firstUnit)
               civ.teleportUnit(firstUnitComplete, activeTile)                 -- code to teleport the currently loaded unit to exactly the same tile as where the truck stands (first map)
               firstUnitComplete:activate()                                    -- activates the unloaded unit, clearing its orders, and, if it has a human owner and movement points left, selects it on the map
               unitsOnTruck[1] = "firstUnitFakeLoading"                        -- removes the value (ID of the firstUnit) from the table; Be aware: We do the procedure NOT on variable 'firstUnit' since it's just used for easier reading the code - i.e. a representation of 'unitsOnTruck[1]' => the direct table entry, which we have to change here
               state.loadedTrucks[activeUnit.id] = unitsOnTruck                -- update the state.table
            elseif secondUnit ~= nil and secondUnit ~= "secondUnitFakeLoading" then
               local secondUnitComplete = civ.getUnit(secondUnit)
               civ.teleportUnit(secondUnitComplete, activeTile)             -- code to teleport the currently loaded unit to exactly the same tile as where the truck stands (first map)
               secondUnitComplete:activate()                                -- activates the unloaded unit, clearing its orders, and, if it has a human owner and movement points left, selects it on the map
               unitsOnTruck[2] = "secondUnitFakeLoading"                    -- removes the value (ID of the secondUnit) from the table; Be aware: We do the procedure NOT on variable 'secondUnit' since it's just used for easier reading the code - i.e. a representation of 'unitsOnTruck[2]' => the direct table entry, which we have to change here
               state.loadedTrucks[activeUnit.id] = unitsOnTruck                -- update the state.table
            end
        end
    end
end                                                                            -- 'end' of function unloadUnitsOffTruck()

-----------------------------------------------------------------------------------------------------------------------
function onActivateEveryUnit(activeUnit, source)
    print("Within the function: onActivateEveryUnit.")
local supplyTruckType1 = civ.getUnitType(26)                         
local supplyTruckType2 = civ.getUnitType(118) 
local successfullFakeLoading = 0

if (activeUnit.type ~= supplyTruckType1 and activeUnit.type ~= supplyTruckType2) then                                    -- if the currently activeUnit is no truck then there is no point to continue the code -> Therefore:
   print("Active unit is NOT the supplyTruckType.")                            -- 1) show this info in the console
   return                                                                    -- 2) and end the function
else
   print("Active unit (ID: " .. activeUnit.id .. ") is supplyTruckType.")     -- if this line is reached (not broken up before), the currently activeUnit must be a truck
   local unitsOnTruck = state.loadedTrucks[activeUnit.id]                    -- "fill" the local variable 'unitsOnTruck' with data about the loaded units (IDs) on exactly this truck; KEY for the state.table = activeUnit/currentUnit.id
   activeTruck = activeUnit                                                    -- update the global variable, i.e. ID of the truck used right at this moment; since this funtion - in one case - jump to the funtion 'firstTimeFakeLoadingOnTruck()', where the ID is needed
    if unitsOnTruck == nil then                                                -- if this line is reached (not broken up before) there must be an active unit equal to supplyTruckType (=2nd condition) BUT it still can be a "virgin" truck, which will always result in code errors
       print("unitsOnTruck == nil | Therefore: Execute funtion: firstTimeFakeLoadingOnTruck.")
       firstTimeFakeLoadingOnTruck()                                         -- from that code line on -> each place of the truck is at least "fake loaded"
       successfullFakeLoading = 1
    end
    if unitsOnTruck ~= nil or successfullFakeLoading == 1 then                -- only now we can introduce the variables ('firstUnit'+'secondUnit') in the code, earlier there would be an error "attempt to index a nil value (global 'unitsOnTruck')" -> covered by 'firstTimeFakeLoadingOnTruck()'
       unitsOnTruck = state.loadedTrucks[activeUnit.id]
       activeTruck = nil                                                    -- delete content of the global variable
       local firstUnit = unitsOnTruck[1]                                    -- data of the first unit will be stored by means of their ID -> 'local' = initialize the variable within this function
       local secondUnit = unitsOnTruck[2]
        if (firstUnit == nil or firstUnit == "firstUnitFakeLoading") and (secondUnit == nil or secondUnit == "secondUnitFakeLoading") then            -- Case ONE: the respective truck is empty
           civ.ui.text("Empty truck (ID: " .. activeUnit.id .. ").")
           return
        elseif (firstUnit ~= nil and firstUnit ~= "firstUnitFakeLoading") and (secondUnit == nil or secondUnit == "secondUnitFakeLoading") then        -- Case TWO: if there is ONLY the firstUnit on the truck
           civ.ui.text("Currently only unit " .. firstUnit .. " is on the truck " .. activeUnit.id .. ".")
           return
        elseif (firstUnit == nil or firstUnit == "firstUnitFakeLoading") and (secondUnit ~= nil and secondUnit ~= "secondUnitFakeLoading") then        -- Case THREE: if there is ONLY the secondUnit on the truck
           civ.ui.text("Currently only unit " .. secondUnit .. " is on the truck " .. activeUnit.id .. ".")
           return
        elseif (firstUnit ~= nil and firstUnit ~= "firstUnitFakeLoading") and (secondUnit ~= nil and secondUnit ~= "secondUnitFakeLoading") then    -- Case FOUR: truck is full / loaded with "real" units
           civ.ui.text("Currently the units: " .. firstUnit .. ", " .. secondUnit .. " are on the truck " .. activeUnit.id .. ".")
        end
    end
end
end


It is throwing this error:

Code:
..f Time\Scenario\Hinge of Fate\LuaCore\generalLibrary.lua:2738: The Global table can't accept values for indices that don't already exist.  Key value is: activeTruck
stack traceback:
    [C]: in function 'error'
    ...f Time\Scenario\Hinge of Fate\LuaCore\generalLibrary.lua:2738: in metamethod '__newindex'
    ...Scenario\Hinge of Fate\LuaRulesEvents\keyPressEvents.lua:18: in main chunk
    [C]: in function 'require'
    D:\Test of Time\Scenario\Hinge of Fate\events.lua:37: in main chunk

I'm not quite sure what to make of the indices error. Also, I'm uncertain if the three sections of code I have above (specifically the activation piece) can work in the keyPress section, either, but I'm starting there as this all worked pre-template and now I'm trying to adjust it to get it working within the template.

What is this indices issue and how would I fix it please?
 
Not the expert here, but I think it's saying that you can't create "activeTruck" as a new global variable (at the top of what you posted). Either you need to declare it as "local" here, or predefine it as a global in a different file, or turn off the setting that Prof. Garfield added to block new globals.
 
Knighttime is correct about the global variable. I think you can just write local activeTruck = nil, and everything will work (unless activeTruck is supposed to be referenced elsewhere). I think you're also going to need local state = gen.getState() in order to have access to the state table, and
Code:
state.loadedTrucks=state.loadedTrucks or {}
in place of
Code:
state.loadedTrucks = {}
 
Doing all of that removed that error but provided this one:

Code:
...Scenario\Hinge of Fate\LuaRulesEvents\keyPressEvents.lua:17: attempt to index a string value (local 'state')
stack traceback:
    ...Scenario\Hinge of Fate\LuaRulesEvents\keyPressEvents.lua:17: in main chunk
    [C]: in function 'require'
    D:\Test of Time\Scenario\Hinge of Fate\events.lua:37: in main chunk
 
OK, the problem is that gen.getState() is being run before the state table has been linked to that function. I have to think of a good way to solve that.
 
OK, I think this will work.

The transport module now provides these functions
Code:
transport.firstTimeFakeLoadingOnTruck()
transport.loadUnitsOnTruck()
transport.unloadUnitsOffTruck()
transport.onActivateEveryUnit(activeUnit, source)
which you can put wherever is necessary using require, as usual.

In the onScenarioLoaded event, run the line
Code:
transport.putInScenarioLoaded()
(make sure to require transport module in the file)

If that doesn't work, open events.lua, require transport module, and, in the linkStateTableToModules function, add the lines
Code:
state.transport = state.transport or {}
transport.linkState(state.transport)

If that doesn't work, send me your code so I can test it myself.
 

Attachments

  • transport.lua.zip
    3.4 KB · Views: 28
Just a quick check, and advice from the pros!

I assume there can be three city improvements for a unit requirement in "canbuildsettings"?
I want to make the B-29, and other super weapons are dependent on massive infrastructure before building.

Code:
--American home cities with airbases, assembly lines and armament plants can train the USAAF super bomber units
unitTypeBuild[object.uB29SuperFortress.id] = {location=USAHomeCities,allImprovements={object.iAirbase,object.iAssemblyLine,object.iArmamentsPlant}}

All the relevent object.lua refs are in place - I'm just making sure that I can have three improvements.
 
Top Bottom