Lua Scripting Possibilities

Looks good. Maybe I read your code wrong, but it looks like your code assumes the civ has only one capital. While this is usually the case, you can use cheat mode to give a civ multiple capitals, so it might make sense to try to find the nearest one.
Good point. I exited the loop after finding the first capital as a way to improve performance, but in this case that's probably assuming too much. I'll make that update, shouldn't be too difficult.

EDIT: By the way, TNO's civlua.findCapital() makes this same faulty assumption. Just sayin'. ;)

I'll have to put the 'in game distance' into the General Library, so we can reference distances without re-creating the function all the time, and let the General Library handle the world shape (currently, setting the world as round is just running a function once).
Sounds great. I think it would be nice if there was both "getMoveDistance" (with the taxicab distance you originally explained, relevant for units) and "getTrueDistance" (with a version of this formula, used for economic calculations like corruption and caravans). Of course you can use different names if you prefer.
 
Last edited:
Hello all.
Was wondering if the Lua library attached to ToTPP included the "image" object and its functions, which could enhance quite a bite scenarii's atmospheres, particulary in conjunction with "dialog" objects ?
 
That was something TNO was working on when he left. It was to be part of the new release. Unfortunately we haven't seen him for several years.
 
Here are some observations on the new functionality.

onCalculateCityYield will let us have a 'beforeProduction' event just as we currently have an afterProduction event. Before production would be more reliable than after production in most scenarios (although I do have code in the template to make sure after production will always trigger).

If you change production values of terrain during the onCalculateCityYield event, the city's production doesn't change, although the displayed production on the terrain does. This can be overcome by calculating the production the city should have with the new terrain production values, and providing returning the difference as the appropriate value. Custom terrain production values for individual tribes or even cities seems not to difficult, nor confusing to the player.

Food importing and exporting can now be simulated fairly easily, and there can be blockade criteria to prevent the import.

The onInitiateCombat event allows for both units to survive combat. The onUnitKilled event doesn't appear to run in that case, which makes sense, since nothing was killed. I haven't experimented with altering combat stats yet.

With access to current city production orders, setting maximum numbers of certain units for a tribe is now much more feasible, since we can count units being produced when counting units. It could also be used to limit the number of a type of unit in production, for example trade units, so you can only be building a few of them at a time.

The domain specific counter means that we can create caravans now, which might be preferable to allowing them to be produced by regular production. Of course, it also means that aircraft can now expend their last movement point for munitions. We can alter the speed of settler work, and probably eliminate "pre-charging".
 
Hi - so I'm helping out on a project and there are specific coordinates that will repeatedly be utilized throughout it. Literally, these could repeat hundreds of times. Given this, if there is an error, or a desire later to modify these in any way, it would be exceptionally preferable to define them in the object file, however I believe you're only allowed to use one tile for that and not a full list?

object.lGraz = civ.getTile(140,98,0)

How instead could I write this so that it said something like this:

object.lBritReinforcements = civ.getTile{{12,14,0}, {25,33,0}, {43,53,0}, {69,85,0}, {88,104,0}, {65,147,0}, {25,161,0}}

I don't think that works, right?

Here's the two lists I'm trying to add to a simple "object" reference so I can modify it in one spot as opposed to hundreds in case I make a mistake or we just want a change. Any help on how to achieve this would be appreciated.

Y - {{12,14,0}, {25,33,0}, {43,53,0}, {69,85,0}, {88,104,0}, {65,147,0}, {25,161,0}}

X - {{55,21,0}, {62,38,0}, {57,49,0}, {69,85,0}, {88,104,0}, {127,117,0}, {93,171,0}, {71,185,0}},
 
So, you want a table that has tile objects for values instead of coordinate triples, correct?

Code:
object.lBritReinforcements = {civ.getTile(12,14,0),civ.getTile(25,33,0),civ.getTile(43,53,0),}

You can convert an existing table of coordinate triples using gen.toTile (untested code)
Code:
local function convertCoordinates(tableOfTriples)
    for index,triple in pairs(tableOfTriples) do
        triple[3] = triple[3] or 0 -- if coordinates only have 2 values, this assumes the map is 0
        tableOfTriples[index] = gen.toTile(triple)
    end
end
with this, you could write
Code:
object.lBritReinforcements = convertCoordinates({{12,14,0}, {25,33,0}, {43,53,0}, {69,85,0}, {88,104,0}, {65,147,0}, {25,161,0}})
 
Was wondering if the Lua library attached to ToTPP included the "image" object and its functions, which could enhance quite a bite scenarii's atmospheres, particulary in conjunction with "dialog" objects ?
That was something TNO was working on when he left. It was to be part of the new release. Unfortunately we haven't seen him for several years.
Much thanks. That would just be a plus anyway. :) there's already plenty.
@Dadais If you haven't checked out the new TOTPP 0.16 yet, you should definitely do so! It contains exactly what you requested: an image object which can be read in from a file via civ.ui.loadImage(), and the addition of dialog:addImage() to add that object to any dialog object. The images appear on the left side of the dialog popup box with the text on the right, just like it does when the game natively provides dialogs with images. Pretty sure you could have a dialog with only an image and no text if you wanted. Also transparent colors work great, with the standard rules that magenta is transparent and the top left pixel of the image defines that color as an additional transparent color.
 
Inclusing images in dialog text boxes sounds very interesting. I would like to use it but unfortunately I don't know how to write the code for it.
This is one of the dialog object I'm currently using.
Code:
local dialog = civ.ui.createDialog()
            dialog.title = "Colonization of Cuba"
            dialog.width = 800
            dialog:addImage(01imp.bmp)
            local multiLineText = "The hope of new ressources..."           
            text.addMultiLineTextToDialog(multiLineText,dialog)
            dialog:show()

I've added the code 'dialog:addImage(...)' but I don't know where to set 'civ.ui.loadImage(...)'.
 
I've added the code 'dialog:addImage(...)' but I don't know where to set 'civ.ui.loadImage(...)'.

Haven't tried it, but my guess is
Code:
local myImage = civ.ui.loadImage(01imp.bmp)
local dialog = civ.ui.createDialog()
           dialog.title = "Colonization of Cuba"
            dialog.width = 800
            dialog:addImage(myImage)
            local multiLineText = "The hope of new ressources..."           
            text.addMultiLineTextToDialog(multiLineText,dialog)
            dialog:show()

I'm guessing that, if you wanted to, you could put store all the imageObjects in the object table, though I suppose that would only be useful if you wanted to have the same image in multiple places.
 
I've changed the code and LUA shows me the following error:
upload_2021-4-5_16-22-31.png


I don't understand why LUA expects a ')' as the value '(01imp.bmp)' is closed already.
Code:
 local CubaColonize = civ.ui.loadImage (01imp.bmp)
         local dialog = civ.ui.createDialog()
            dialog.title = "Colonization of Cuba"
            dialog.width = 800
            dialog:addImage(CubaColonize)
            local multiLineText = "The hope of new... ."           
            text.addMultiLineTextToDialog(multiLineText,dialog)
            dialog:show()
 
The file name itself needs to be in quotes. Try:
local CubaColonize = civ.ui.loadImage("01imp.bmp")
 
The strange appearance of the box is because it's too wide. If you make all of your text lines shorter, that should go back to normal. Glad the image feature is working for you now.
 
That image stuff is one great feature to enrich scenarii universes !
Much thanks you all.

I'll resist from touching it right now, shall put heart in finishing the diplomatic menu of the current projet first.

Anyway : that's wonderfull !
 
Last edited:
I have a question about how to structure these events. What I'm trying to achieve here is basically have the reinforcements show up as close to the front line as possible, depending where that is (as judged by what cities the Soviets own or don't). My question is, for the first elseif (and subsequent), do I need to explain/define that the Soviets don't own Vipurri (so, elseif object.cVipurri.owner ~= object.tUSSR and object.cLeningrad.owner == object.tUSSR then) or should it work the way I've written it?

Code:
if object.cVipurri.owner == object.tUSSR then
        civ.ui.text("The Soviets have launched a massive offensive aimed at knocking Finland out of the war! Our allies to the north are stretched thin!!")
        --{{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}
        civlua.createUnit(object.uKatyusha, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietInfantry, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=15, randomize=false, veteran=true})
        civlua.createUnit(object.uT34, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=8, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietTankDestroyer, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietHeavyTankI , object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietGuards, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterII, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uIl2, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietBomber, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterI, object.tUSSR, {{177,9,0},{177,11,0},{175,9,0},{174,10,0},{178,10,0},{179,11,0},{177,11,0},{177,7,0}}, {count=4, randomize=false, veteran=true})
      
        elseif object.cLeningrad.owner == object.tUSSR then
        civ.ui.text("The Soviets have launched a massive offensive aimed at knocking Finland out of the war! Our allies to the north are stretched thin!!")
        --{{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}
        civlua.createUnit(object.uKatyusha, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietInfantry, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=15, randomize=false, veteran=true})
        civlua.createUnit(object.uT34, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=8, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietTankDestroyer, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietHeavyTankI , object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietGuards, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterII, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uIl2, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietBomber, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterI, object.tUSSR, {{183,15,0},{184,12,0},{184,14,0},{184,16,0},{183,17,0},{181,17,0},{181,13,0},{182,14,0}}, {count=4, randomize=false, veteran=true})
      
        elseif object.cNovgorod.owner == object.tUSSR then
        civ.ui.text("The Soviets have launched a massive offensive aimed at knocking Finland out of the war! Our allies to the north are stretched thin!!")
        --{{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}
        civlua.createUnit(object.uKatyusha, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietInfantry, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=15, randomize=false, veteran=true})
        civlua.createUnit(object.uT34, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=8, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietTankDestroyer, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietHeavyTankI , object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietGuards, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterII, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uIl2, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietBomber, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterI, object.tUSSR, {{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}}, {count=4, randomize=false, veteran=true})
 
I have a question about how to structure these events. What I'm trying to achieve here is basically have the reinforcements show up as close to the front line as possible, depending where that is (as judged by what cities the Soviets own or don't). My question is, for the first elseif (and subsequent), do I need to explain/define that the Soviets don't own Vipurri (so, elseif object.cVipurri.owner ~= object.tUSSR and object.cLeningrad.owner == object.tUSSR then) or should it work the way I've written it?

Your code will work as written. Since object.cVipurri.owner == object.tUSSR was the only condition in if statement, it must be false to reach the next elseif. That said, it wouldn't hurt anything to put that kind of check in if you're not sure (perhaps if you're checking 2 or 3 conditions at each time, and aren't entirely sure if the logic excludes a possibility).

I would suggest that, since you're always creating the same units in the same numbers, and only changing the locations, that you write a helper function:
Code:
local function sovietReinforcements(tileTable)
       civlua.createUnit(object.uKatyusha, object.tUSSR, tileTable, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietInfantry, object.tUSSR,tileTable, {count=15, randomize=false, veteran=true})
        civlua.createUnit(object.uT34, object.tUSSR, tileTable, {count=8, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietTankDestroyer, object.tUSSR, tileTable, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietHeavyTankI , object.tUSSR, tileTable, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietGuards, object.tUSSR, tileTable, {count=5, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterII, object.tUSSR, tileTable, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uIl2, object.tUSSR, tileTable, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietBomber, object.tUSSR, tileTable, {count=4, randomize=false, veteran=true})
        civlua.createUnit(object.uSovietFighterI, object.tUSSR, tileTable, {count=4, randomize=false, veteran=true})
end
then call, for example
Code:
elseif object.cNovgorod.owner == object.tUSSR then
       civ.ui.text("The Soviets have launched a massive offensive aimed at knocking Finland out of the war! Our allies to the north are stretched thin!!")
       sovietReinforcements({{186,22,0},{185,23,0},{185,25,0},{186,20,0},{185,19,0},{187,19,0},{186,18,0},{184,18,0}})
Having the code all re-written each time is going to make anyone looking at it wonder if there are subtle differences in the units created each time, not to mention make it impractical to change the reinforcements if you need to later.
 
Excellent work, guys. I assume these lines would go into "eventsTriggers"?

Could one of you chaps amend the trigger to be a tech being discovered?

If so, I can immediately make all my invasion unit spawns use the above trigger system, (it is where I am with the events)
as it seems more efficient than macro, in that all the units can be jammed into one big event. The table function just puts the
cherry on the cake too. I realise this is where Lua is way ahead of the old events system.
 
Excellent work, guys. I assume these lines would go into "eventsTriggers"?

The question is where in triggerEvents.lua does it have to go.

If you want the trigger to run (or, rather, be checked for) at the start of the round (before the barbs play), you would put it in
Code:
function triggerEvents.onTurn(turn)
context[getContext()]["onTurn"](turn)
universal["onTurn"](turn)
delay.doOnTurn(turn)
legacy.onTurnEventsAndMaintenance(turn)
-- Put the code here, unless for some reason you want it to run before one of those other event systems
end

If you want the game to check for each player, either before or after their city production, you would put it in one of these
Code:
function triggerEvents.afterProduction(turn,tribe)
context[getContext()]["afterProduction"](turn,tribe)
universal["afterProduction"](turn,tribe)
delay.doAfterProduction(turn,tribe)
end

function triggerEvents.beforeProduction(turn,tribe)
context[getContext()]["beforeProduction"](turn,tribe)
universal["beforeProduction"](turn,tribe)
delay.doBeforeProduction(turn,tribe) -- at the moment this
-- is an empty function, but we might want to use it,
-- so it is here for future compatibility
end
You can also put the code in the UniversalTriggerEvents directory within the file (and function) of the same name.

If you write a helper function, you can define it outside of the event function.

Could one of you chaps amend the trigger to be a tech being discovered?
I'll assume you want to check during afterProduction. (If you want onTurn, omit the tribe == check).
Code:
if tribe == object.pTribeName and civ.hasTech(object.pTribeName,object.aTechName) then
    gen.justOnce("UniqueJustOnceString", function ()
        -- put your code here
    end) -- the end here is for the function we defined inside of gen.justOnce, the ) is to close gen.justOnce
end -- end the if statement for this check
If you want the stuff to happen every time, forget the justOnce part.
 
Top Bottom