Lua Scripting Possibilities

I tried it but that doesn't work.

Also the Aliases I believe is done to prevent the need of having numerous "locals" as Grishnach thinks you only can have up to 200 of them? Hence the Aliases are in a table:

local cityAliases={}

cityAliases.London = civ.getCity(0)
cityAliases.Berlin = civ.getCity(1)

Unless this sort of table doesn't work?
 
civ.removeImprovement(Berlin, 15)

civ.removeImprovement takes an imrovement object as an argument, so try this

civ.removeImprovement(cityAliases.Berlin, civ.getImprovement(15))

I also need to figure out a way to get the production of improvement 15 in a particular city (Berlin) to spawn a new Industry1 unit at (364,68,1) and to change the terrain at (364,68,0) to terrain 8 and I'm not totally sure the best way to do this. civ.hasImprovement seems like the closest trigger but wouldn't that cause the industry to keep being built each turn? That won't work... And I also need it to keep triggering over and over again so justOnce wouldn't be an option here.
civ.hasImprovement(city, improvement)

onCityProduction
civ.scen.onCityProduction(function (city, prod) -> void)

should be an appropriate trigger.

The logic is something like this (this code may not be exactly right)

if civ.isImprovement(prod)
if prod.id == 15
local cityTile = city.location
local terrainTile = civ.getTile(cityTile.x,cityTile.y,0)
terrainTile.terrainType=8
local industryTile = civ.getTile(cityTile.x,cityTile.y,1)
newIndustry = civ.createUnit(unitAliases.Industry1, tribeAliases.German, industryTile)
newIndustry.veteran = true
newIndustry.homeCity = nil

Whenever a city produces improvement 15, the terrain of that city location on map 0 is set to 8, and an industry1 is created on map 1. The industry is set to veteran status and the home city is set to None.
 
I'm following (I think) what you're writing, but I really need to create a table much like that for ranged attack units and the build restrictions. I'm assuming however that instead of cityTile I could just use the location in the appropriate table spot? I'll give a shot at writing it up a bit later and will report back.

I need the table because each city can build up to 10 improvements (3x of industry, science, economy, and 1 military port if by sea). Just having the tile under the city wont work. I have an excel sheet wherein I have all of these coordinates for all cities in the game and am aware this is going to be a ton of work for me to implement =)

Thank you for your help!
 
There shouldn't be any problem pulling the appropriate square from a table.

If you set the home city of the industry to the city it is tied to, then I don't think you need a table tying each industry location to a particular city. You just remove the appropriate improvement from killed.homeCity. Maybe set the industry unit as a trade unit so it doesn't draw support. You still need a table telling where each city puts each new improvement, but you might be able to avoid having to make the table that goes the other way (or do a search).
 
This is kind of what I'm thinking about but I can't get it to work... It throws the error events.lua:399: '}' expected near 'unitTile' and I've tried putting an '}' in a few spots.

Code:
civ.scen.onCityProduction(function (city, prod)
end)

------------------------------------------------------------------------------------------------------------------------------------------------

local unitTile = civ.getTile(tile.x,tile.y,tile.z)
local cityBuilt = civ.getCity
local tribeType = civ.getTribe()


local industryBuildTypes = {
    ["BerlinIndustry1"] = { industryType=civ.isImprovement(15), unitType=civ.getUnitType(45), tribeType=(1) unitTile{364,68,1}, cityBuilt(1), displayText="Test if this works."  --- this is line 399
     },

    if civ.isImprovement(prod) then
    
        --g loop over all industryBuildTypes
        for ___, industryBuild in pairs(industryBuildTypes) do
            
            if industryBuild.isImprovement.id == current.prod.id do
            
            civ.createUnit(unitType, tribeType, {unitTile}), {unitType.veteran = false, unitType.homeCity = cityBuilt})
            
    
    end


end
 
civ.isImprovement(15) will always be false, maybe you want civ.getImrovement(15). Looks like you need a } to close the industryBuildTypes table.

I've attached some code that I think will work (haven't run it, so maybe there are syntax errors)

The Table construction would be quite laborious, but if the code works as desired, we could modify it to make the table construction easier, or write some code to print the table construction from input that is quicker to type.
 

Attachments

Hi,

I plugged it in and added coordinates for Berlin and London but got the error in bold below:

--Run this code for German Production
if civ.getPlayerTribe() == tribeAliases.Germany
if civ.isImprovement(prod) --D:\Test of Time\Scenario\OTR3\events.lua:422: 'then' expected near 'if' (This is line 22)
if createIndustryData[prod.id]


As far as laborious - that is something I can handle and handle well. It's this darned innovation and coding that gets me. If we can get something that works though, I can deal with the labor. I take it that I could add an infinite [getCityAt(x,y,z).id] (or about the 60-70 I'll need) and just keep repeating this code until the table is complete? That would work just fine by me.

Code:
 [15] = {unitType=getUnitType(45), -- Unit type to be produced when improvement number 15 is built
            terrainType=8, --Type of terrain to be created when improvement number 15 is built
            [getCityAt(363,71,0).id] = {unitTile=civ.getTile(364,68,1),terrainTile=civ.getTile(364,68,0)},
             -- city at (100,100,0) produces industry at (102,100,1) and changes terrain at (102,100,0)
            [getCityAt(172,68,0).id]={unitTile=civ.getTile(170,70,1),terrainTile=civ.getTile(170,70,0)}
        }, --Close createIndustryData[15] table
 
Oops. I'm used to programming in MATLAB, where you don't need to write "then" after the if condition.

Try this (after replacing the Berlin Coordinates).

If London is owned by the allies, the code won't execute, since I separated the Axis and Allied events with a check for whose turn it is. This isn't really necessary, except to separate the events. If you have many events designed for both players, you might want to eliminate lines 28,50,53,55 and change line 38 to give the unit to the current player instead of Germany specifically.
 

Attachments

Noticed a couple other things, so implemented the suggestions I made a few minutes ago.
 

Attachments

hey here is the whole events file... It's throwing up an error now at 406 saying:

Over the Reich
D:\Test of Time\Scenario\OTR3\events.lua:406: attempt to call a nil value (global 'getUnitType')
stack traceback:
D:\Test of Time\Scenario\OTR3\events.lua:406: in main chunk
 

Attachments

I wrote 'getUnitType' instead of 'civ.getUnitType'.

That's why I uploaded the revised file. I also commented out the distinction between German Production and Allied production, just in case you want the same code for allied cities.
 

Attachments

Ok... Progress. The code will load however on testing:

Over the Reich
D:\Test of Time\Scenario\OTR3\events.lua:433: bad argument #1 to 'createUnit' (civ.unittype expected, got nil)
stack traceback:
[C]: in function 'civ.createUnit'
D:\Test of Time\Scenario\OTR3\events.lua:433: in function 'runOnProduction'

I then changed the unitType to civ.unitType and that ran...

433 local newUnit = civ.createUnit(createIndustryData.civ.unitType,civ.getPlayerTribe(),makeUnitHere)

However then this came up:

Over the Reich
D:\Test of Time\Scenario\OTR3\events.lua:433: attempt to index a nil value (field 'civ')
stack traceback:
D:\Test of Time\Scenario\OTR3\events.lua:433: in function 'runOnProduction'
 
Perhaps I should explain the error, so that you can debug similar errors in the future

"bad argument" means that the wrong kind of data was used as an input to the function
"#1 to 'createUnit'" means the first argument to the function "createUnit"
"(civ.unittype expected, got nil)" is saying that it got a nil value, when it expected a value of civ.unittype

That happened because there is no key "unitType" in the table createIndustryData, so createIndustryData.unitType returns nil
 
Onto the next problem...

So, I realized that the local buildRestrictionsUnits={ from line 463 isn't going to work very well in this scenario because the way it is currently written, as soon as that improvement is built, the particular unit can be built, regardless of tech level.

What I'm trying to do is make it so that you need a certain improvement in a city to build a certain unit ONCE you have the appropriate tech level.

So I'm guessing that somewhere in this line, I need to have another condition (checking for a certain hasTech civ.hasTech(tribe, tech) -> boolean) to:

Code:
local buildRestrictionsUnits={
["Fw190D9"] = {unit=civ.getUnitType(17), conditionMet=function (city, state) return civ.hasImprovement(city, civ.getImprovement(13)) end}

And I'm guessing that it needs to be built into after the conditionMet?

And then this piece down here is where I would build in the new condition?

Code:
civ.scen.onCanBuild(function (defaultBuildFunction, city, item)

   local separateCondition=nil
  
   if civ.isUnitType(item) then
       for _,restrictedUnit in pairs(buildRestrictionsUnits) do
                      if item.id==restrictedUnit.unit.id then
               separateCondition=restrictedUnit.conditionMet(city,state)
           end
       end
   end

But where or how to throw that in is a bit advanced for me.
 
This sounds like something I touched on briefly in one of my earlier posts:
Note the "else return nil" in what I provided. That value is being provided back to your "separateCondition" variable -- so if the city does not have City Walls, near the end of your code, you'll run defaultBuildFunction and let the game's normal logic determine whether or not an airport can be built.
It sounds like that's what you want here as well. In other words, you don't need to manually check whether the tribe has the appropriate tech to build something -- you just want the game to handle that like it always does, and for your code to limit itself to blocking the ability to build certain things that tech levels would normally grant.

So you're right, you can handle this in the conditionMet part of the buildRestrictionsUnits table -- and even better, you can even get away with only making a change there, and not touching anything in civ.scen.onCanBuild(). Try this:
Code:
local buildRestrictionsUnits={
["Fw190D9"] = {unit=civ.getUnitType(17), conditionMet=function (city, state) if not(civ.hasImprovement(city, civ.getImprovement(13))) then return false end}
Your previous code would return either true or false and store it as separateCondition. As a result, you weren't running defaultBuildFunction on line 599. By only returning false for things you want to block, but returning nothing (in Lua terms, "nil") otherwise, the game will run its standard check.

Side note: "function (city, state) if not(civ.hasImprovement(city, civ.getImprovement(13))) then return false else return nil end" and "function (city, state) if not(civ.hasImprovement(city, civ.getImprovement(13))) then return false end" should produce the same result. One explicitly returns nil (extra code, but makes it clear in the code exactly what you intend), and the other simply fails to return anything (less code, but a little less obvious whether that was on purpose or an oversight).
 
Hm.

Adding all that onto line 469 produces this error:

D:\Test of Time\Scenario\OTR3\events.lua:469: unexpected symbol near '}'

I did try temporarily removing the rest of the table to try and make it just the 190D9 to see if that helped but it did not. (469 is the Fw190D9 code).
 
Forgot an "end", sorry! Ah, the perils of providing code without testing it! :hammer2:
Code:
["Fw190D9"] = {unit=civ.getUnitType(17), conditionMet=function (city, state) if not(civ.hasImprovement(city, civ.getImprovement(13))) then return false end end}
or, if you prefer,
Code:
["Fw190D9"] = {unit=civ.getUnitType(17), conditionMet=function (city, state) if not(civ.hasImprovement(city, civ.getImprovement(13))) then return false else return nil end end}


EDIT: Although it takes up a lot more lines, if you format the code like this, it makes it quite a bit more obvious where blocks begin and end:
Code:
["Fw190D9"] = {
   unit = civ.getUnitType(17),
   conditionMet = function (city, state)
       if not(civ.hasImprovement(city, civ.getImprovement(13))) then
           return false
       end
   end}

Just curious, what editor are you using? I use Notepad++ for editing Lua scripts, and it will helpfully add block indicators in the left margin, to show you the lines on which blocks begin and end. That can be really useful to find things like missing/mismatched "ends" or parentheses or curly braces.
 
Last edited:
It works beautifully now!

I am using luaedit, so it does have block indicators though I won't pretend to know how to read it :)

The formatting is mainly for ease of repeating over and over again. I tend to build my scenarios out in excel to start and then can have the code up on one half of the monitor and the excel on the other and just kind of go down the column speedily. The other way you suggested probably makes a lot more sense when trying to build something for the first time though and trouble shoot.
 
Back
Top Bottom