1. Firaxis celebrates the "Asian American and Pacific Islander Heritage Month", and offers a give-away of a Civ6 anthology copy (5 in total)! For all the details, please check the thread here. .
    Dismiss Notice
  2. We have selected the winners of the Old World random draw and competition. For the winning entries, please check this thread.
    Dismiss Notice

Lua Scripting Possibilities

Discussion in 'Civ2 - General Discussions' started by JPetroski, Jan 21, 2018.

  1. Knighttime

    Knighttime Prince

    Joined:
    Sep 20, 2002
    Messages:
    336
    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'. ;)

    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: Nov 17, 2020
  2. Dadais

    Dadais Prince

    Joined:
    Oct 20, 2010
    Messages:
    580
    Location:
    France
    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 ?
     
  3. JPetroski

    JPetroski Deity

    Joined:
    Jan 24, 2011
    Messages:
    4,506
    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.
     
  4. Dadais

    Dadais Prince

    Joined:
    Oct 20, 2010
    Messages:
    580
    Location:
    France
    Much thanks. That would just be a plus anyway. :) there's already plenty.
     
  5. Prof. Garfield

    Prof. Garfield Deity Supporter

    Joined:
    Mar 6, 2004
    Messages:
    3,818
    Location:
    Ontario
    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".
     
    Dadais and Knighttime like this.
  6. JPetroski

    JPetroski Deity

    Joined:
    Jan 24, 2011
    Messages:
    4,506
    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}},
     
  7. Prof. Garfield

    Prof. Garfield Deity Supporter

    Joined:
    Mar 6, 2004
    Messages:
    3,818
    Location:
    Ontario
    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}})
    
     
  8. Knighttime

    Knighttime Prince

    Joined:
    Sep 20, 2002
    Messages:
    336
    @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.
     
    Dadais likes this.
  9. civ2units

    civ2units Emperor

    Joined:
    Feb 1, 2009
    Messages:
    1,031
    Location:
    Somewhere in nowhere
    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(...)'.
     
  10. Prof. Garfield

    Prof. Garfield Deity Supporter

    Joined:
    Mar 6, 2004
    Messages:
    3,818
    Location:
    Ontario
    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.
     
  11. civ2units

    civ2units Emperor

    Joined:
    Feb 1, 2009
    Messages:
    1,031
    Location:
    Somewhere in nowhere
    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()
     
  12. Knighttime

    Knighttime Prince

    Joined:
    Sep 20, 2002
    Messages:
    336
    The file name itself needs to be in quotes. Try:
    local CubaColonize = civ.ui.loadImage("01imp.bmp")
     
  13. civ2units

    civ2units Emperor

    Joined:
    Feb 1, 2009
    Messages:
    1,031
    Location:
    Somewhere in nowhere
    Many thanks @Knighttime :thumbsup:
    It works but doesn't look so nice. Please ignore the content of the picture, I just used it for a test.
    upload_2021-4-5_19-6-36.png
     
  14. Knighttime

    Knighttime Prince

    Joined:
    Sep 20, 2002
    Messages:
    336
    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.
     
  15. civ2units

    civ2units Emperor

    Joined:
    Feb 1, 2009
    Messages:
    1,031
    Location:
    Somewhere in nowhere
    I've changed the width of the dialo box from 800 to 700 and now it works.:)
    upload_2021-4-5_20-14-19.png
     
    Dadais, Knighttime and CurtSibling like this.
  16. Dadais

    Dadais Prince

    Joined:
    Oct 20, 2010
    Messages:
    580
    Location:
    France
    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: Apr 18, 2021
    CurtSibling likes this.
  17. JPetroski

    JPetroski Deity

    Joined:
    Jan 24, 2011
    Messages:
    4,506
    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})
          
    
     
  18. Prof. Garfield

    Prof. Garfield Deity Supporter

    Joined:
    Mar 6, 2004
    Messages:
    3,818
    Location:
    Ontario
    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.
     
  19. CurtSibling

    CurtSibling ENEMY ACE™ SLeague Staff Supporter

    Joined:
    Aug 31, 2001
    Messages:
    29,280
    Gender:
    Male
    Location:
    Innsmouth
    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.
     
  20. Prof. Garfield

    Prof. Garfield Deity Supporter

    Joined:
    Mar 6, 2004
    Messages:
    3,818
    Location:
    Ontario
    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.

    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.
     

Share This Page