• Our friends from AlphaCentauri2.info are in need of technical assistance. If you have experience with the LAMP stack and some hours to spare, please help them out and post here.

Lua Scripting Possibilities

So I plugged this in (I just put it all in onKeyPress events) and while I had to correct a couple minor typos in the above I was able to get to a point where there's no error however it also isn't firing. You mentioned that I might have an older version of the template - I hesitate to add it to this scenario given all the big changes you made. Am I going to run into compatability problems if I simply change the luacore file (which is the one I don't touch?) I can't really update the other ones as that would wipe all the work I've done within them.
 
Turns out I still have a copy of the scenario you're working on, so I was able to test. There seems to be an issue with the game not updating the player's "chart" (visible map), and with failing to redraw. Replace the General Library with the version attached here, and add the two lines indicated to the script.

Code:
        if choice == 2 then
            activeUnit.moveSpent = activeUnit.moveSpent + totpp.movementMultipliers.aggregate*railUpgradeMoveCost
            activeUnit.owner.money = activeUnit.owner.money - railUpgradeMoneyCost
            gen.placeRailroad(activeUnit.location)
            gen.chartRailroad(activeUnit.location,activeUnit.owner) -- new line
            civ.ui.redrawTile(activeUnit.location) -- new line
        end
 

Attachments

Worked like a charm! Thank you. If anyone else is following along, this would be a good method to get one specific settler function out of a unit without the concern of a road network being built from scratch all over the map, if desired.
 
Can anyone recommend a cleaner way to write this? I don't like how there is terrain type, owner, improvements, etc. If there's no way around it, I'll live with it. BTW @Knighttime your supply line module is working very well :) I just want to give the player some idea where the enemy unit that can't move is located.

Code:
    civ.ui.text("We have encircled this ".. tostring(unit.owner.adjective) .. " ".. tostring(unit.type.name) .. " at ".. tostring(unit.location) .. " ! " )


upload_2021-12-4_15-57-51.png



Edit - as often happens 2 seconds after I post this I'm guessing if I write "unit.location.y" "...x" "...z" in each their own strings, it'll work. But just curious if there's a simpler way to achieve this.
 
@JPetroski Your guess is right, and there isn't really a simpler way. I think you can "shortcut" unit.location.x as simply unit.x (etc.), and you can probably skip the tostring() function for fields that you know are strings or integers and will always be populated (never nil).

civ.ui.text("We have encircled this " .. unit.owner.adjective .. " " .. unit.type.name .. " at " .. unit.x .. "," .. unit.y .. "," .. unit.z .. "!")

Glad supply lines is working well for you! Let me know if you have any questions about it or if there's any more advanced features you'd like to try with it.
 
Edit - as often happens 2 seconds after I post this I'm guessing if I write "unit.location.y" "...x" "...z" in each their own strings, it'll work. But just curious if there's a simpler way to achieve this.

The text.lua module has a function
Code:
text.coordinates(tile) --> string
which returns the 3 coordinates of a tile (without the parentheses on either side). Might be slightly easier.
 
I was playing around with the new city.currentProduction and got this error:

Code:
...cenario\Hinge of Fate\LuaTriggerEvents\triggerEvents.lua:953: bad argument #2 to '__eq' (civ.improvement expected, got civ.unittype)
stack traceback:
    [C]: in metamethod '__eq'
    ...cenario\Hinge of Fate\LuaTriggerEvents\triggerEvents.lua:953: in function 'triggerEvents.onTurn'
    D:\Test of Time\Scenario\Hinge of Fate\events.lua:155: in function <D:\Test of Time\Scenario\Hinge of Fate\events.lua:147>

It says it is expecting a civ.improvement, but it shouldn't need that per the directions in the functions guide. Here's the code I used:

Code:
if turn >= 1 then 
        for city in civ.iterateCities() do 
            if city.currentProduction == object.uNeutralTerritory then
            city.currentProduction = object.uConscripts

            end
        end 
   
   
    end

Basically, I've noticed in playtests that cities default to building neutral territory for some reason, so I'm trying to catch it and change it to conscripts, which are a generic unit everyone can use.

Any idea what I've goofed? It doesn't seem to make sense to me (but then so little does).

Thanks!
 
In some (or all, I'm not sure) cases involving the TOTPP Objects, you can only use == to compare between similar object types. It looks like city.currentProduction was an improvement, so it was expecting to compare with an improvement on the other side of the ==, but caused an error since it was a unit type.

For your particular case, you'll want something like
Code:
if civ.isUnitType(city.currentProduction) and city.currentProduction == object.uNeutralTerritory then
    city.currentProduction = object.uConscripts
end

You can override the effects of the comparison operators (and a lot of other stuff) for tables using metatables and metamethods, in order to create custom data types. It looks like something similar is done for the TOTPP data types, so you have to check that the data types are the same first. Perhaps @TheNamelessOne could provide something similar to the 'type' function in a future release, so there is an easy way to check the types of the TOTPP objects, rather than going through a list of civ.isAnObjectType functions.
 
That's an easy enough fix. Thanks!

This scenario has more than 127 units, as I recycle them a bit differently than has been done in the past, so I'm going to be using this quite a bit or else there'd be all sorts of crazy effects. I appreciate the help.
 
@Prof. Garfield I'm putting this here in case others can benefit, but I noticed in the general library you've made accommodations to change the different flags of units. I just want to confirm that I am using this right with this code, as I'm having naval vessels use the sub flag until such time that they no longer need to.

Note that I have this in onActivate because the D-Day happened flag can happen after a turn, and also after production:

Code:
if (unit.type == object.uLightCruiser or unit.type == object.uHeavyCruiser or unit.type == object.uBattleship)  and flag.value("D-Day Happened") == true then 
        gen.removeSubmarine(unit)   
end

Is this the correct way to use this tool or am I making an error? I just want to ensure that writing gen.removeSubmarine(unit) will have my desired effect. Thanks.
 
Is this the correct way to use this tool or am I making an error? I just want to ensure that writing gen.removeSubmarine(unit) will have my desired effect. Thanks.
You should use
Code:
gen.removeSubmarine(unit.type)
 
I'm stumped again. I'm trying to add a little more danger to sending out your capitol ships. I was trying to have a random chance that group of warships spawns near the battleship. I'm using a simple -5 location on the .x because I was worried it would appear off map. However, 'unit.location.x - 5' does not appear to work, and no units are created. I also tried unit.type.location but that too did not work. Any ideas on what I need to type to get this working? Thank you.

Code:
if unit.type == object.uTirpitz and math.random(1, 1) == 1 and unit.location.x >= 20 and unit.location.x <= 53 and unit.location.z == 0 and flag.value("First British City Captured") == false then 

    text.simple("An Allied battle squadron is sent to chase down and sink the Tirpitz!","Sink the Tirpitz!",object.mTirpitz)
    civlua.createUnit(object.uBattleship, object.tBritain, {{unit.location.x - 5,unit.location.y,unit.location.z}},{count=2, randomize=false, veteran=false})

end
 
All tile coordinates have the property that X + Y is an even number (they're either both evens or both odds). So you can't subtract an odd number from X, keep Y the same, and have that be a valid tile. My guess is that if you subtracted 4 or 6, this would work.
 
Yes that worked like a charm - I would have NEVER thought of that, so thanks!
 
@Knighttime , @TheNamelessOne , or anyone else who might have an idea:

I want to make it so that there can be optional files in the Lua Scenario Template. At the moment, I'm using code along the lines of
Code:
local fileFound, prefix = pcall(require,"optionalModule")

This has been working fine, except that now I've realised that if the file is found, but causes an error when it is read, pcall suppresses the error and acts as if the file wasn't found. What I want is for syntax errors and error messages I've deliberately inserted (e.g. when loading legacy events fails) to appear as they would regularly, but for Lua to let me implement some alternate condition if the file is not actually found. Does anyone have any idea of how to do this?

The best I've thought of is to check 'prefix' (which will be an error message if the file isn't found) for "module '___' not found", and not throw an error if that happens, but to throw an error (or use an unprotected require) in other situations.

Since this is something that I re-write in every file it is needed, I'd like to see if anyone has any ideas for a more elegant solution.
 
@Prof. Garfield I don't personally have an idea better than yours, but I found the question you posed here:
https://stackoverflow.com/questions/15429236/how-to-check-if-a-module-exists-in-lua
Are any of the answers there helpful to you?

Thanks! I think my searching may have focused too much on "require" specifically. If the first answer works as advertised, it will do what I need. It's also put me on to the package library, which looks like it will let me tailor the code more specifically to my particular use case.
 
I ultimately went with this code. It was easy to substitute into the existing lines
Code:
local fileFound, prefix = gen.requireIfAvailable("optionalModule")
and the code only required changing the function name line if I wanted to copy it directly rather than require the General Library.

Code:
-- gen.requireIfAvailable(fileName) --> boolean, modulePrefix
--      Attempts to require the module called fileName
--      returns true, modulePrefix if the module is found
--      returns false, nil if no module is found
--      makes an error if there is a problem loading the module
--      Note: if you change the function name here, the function
--      can be copied and pasted if you don't want to require
--      the general library
function gen.requireIfAvailable(fileName)
    if package.loaded[fileName] then
        return true, require(fileName)
    else
        for _,searcher in ipairs(package.searchers) do
            local loader = searcher(fileName)
            if type(loader) == 'function' then
                return true, require(fileName)
            end
        end
        return false, nil
    end
end
I chose to explicitly call the require function rather than try to do the work of require so that I could minimise the amount of testing I had to do to be confident that this works.
 
Hi, quick question, does civ.addImprovement work to force creation of wonders in a specific city? I assume so given they are part of the @IMPROVE rules section and din't see anything in the Wonder object section.

Thanks!

I've answered this here, since this is a more general Q&A and discussion thread than the Lua Function Reference.

To add a wonder to a city, you set the 'city' property of the wonder

city (get/set)
wonder.city -> city

Returns the city that has built the wonder, `nil` if not built yet or destroyed.

That is, for example
Code:
local myCity = civ.getCity(0)
civ.getWonder(0).city = myCity
This sets the Pyramids (I believe) to the first city built (Id numbers start at 0, hence the first city and first wonder have ID 0).

Although wonders and improvements are sometimes interchangeable in the rules and macro style events, they are distinct in Lua.
 
Back
Top Bottom