Lua Scripting Possibilities

Pablostuka

King
Joined
Mar 27, 2002
Messages
642
Location
Galway, IRL
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.

Thanks for the reply, so yes, it's appaerently easy to force creation of specific wonders by event. This is just what i wanted :)

I've also deleted my post in the reference thread to keep it clean.
 

Pablostuka

King
Joined
Mar 27, 2002
Messages
642
Location
Galway, IRL
Just my 2 cents in case anybody else needs to do the same (maybe it's been answered before, there are many posts on Lua that I haven't checked yet):

How to move a city from one place to another:

1st obtain the id of the city you want. You can open the city view, hit the Lua console and type this:

Code:
civ.getOpenCity().id

This will return an integer which is ther internal id of the city.

2nd close the city screen, go to the tile you want, ensure there's a road on it (shift + F8 to edit terrain) and then hit this in the Lua console:

Code:
civ.getCity(XX):relocate(civ.getCurrentTile())

Where XX is the city id obtained in the previous step.

How to paint a river on a tile:

As you know, the cheat mode doesn't allow you to add rivers to tiles. This is the quickest option I was able to find, you only need to navigate to the tile you want the river and hit this in the Lua console:

Code:
civ.getCurrentTile().river = true

That's it, If you want to remove a river, just change "true" to "false".

Hope it helps.

Pablo
 

Prof. Garfield

Deity
Supporter
Joined
Mar 6, 2004
Messages
3,846
Location
Ontario
As you know, the cheat mode doesn't allow you to add rivers to tiles. This is the quickest option I was able to find, you only need to navigate to the tile you want the river and hit this in the Lua console:

In TOTPP, CTRL+9 adds and removes rivers. Still, that's a useful example of using the tile.river property. I made links for both questions in the Great Lua Library thread.

Per the extra terrain hotkeys patch description.
Code:
Adds keyboard shortcuts for changing terrain / tile improvements. In cheat mode, change terrain with 0 (Desert) to 9 (Jungle) and Ctrl-3 (Ocean) to Ctrl-8 (Extra terrain 5). Use Ctrl-9 to add/remove a river.
For tile improvements, the following keys can be used in cheat mode when no unit is selected:
r: Road
o: Railroad
i: Irrigation
m: Mine
l: Farmland
f: Fortress
e: Airbase
p: Pollution
 
Joined
Feb 11, 2012
Messages
812
Thanks for that, as you can see I still have loads of stuff to catch up, big learning curve coming from MGE!!

Hi Pablo,

In case you don't have it, I've attached the TOTPP v0.18 PDF reference guide from the Scenario Creation Excel Sheet thread located here. The pdf contains all the features to be found within TNO's TOTPP project.
 

Attachments

  • TOTPP v018.pdf
    1,006.6 KB · Views: 20
Last edited:

Pablostuka

King
Joined
Mar 27, 2002
Messages
642
Location
Galway, IRL
Hi Pablo,

In case you don't have it, I've attached the TOTPP v0.18 PDF reference guide from the Scenario Creation Excel Sheet thread located here. The pdf contains all the features to be found within TNO's TOTPP project.

That link is pure gold, thanks!
 

JPetroski

Deity
Joined
Jan 24, 2011
Messages
4,517
Can someone please help me out with a really stupid question? I have the below code (in after production) which aims to remove trade routes from cities that shouldn't have them, but really that's not what this code is doing obviously.

What I want is to have any cities that are not in Japan to be precluded from trading with one another, with a penalty if it is attempted. What this say is simply that half of the trade route is always going to be removed (unless it happens to be between two Japanese mainland cities).

Now, I think what i want to do is add another check between lines 4 and 5 below where I use the:

from (get)
traderoute.from -> city

and

to (get/set)
traderoute.to -> city

but I'm just drawing a blank of how I'd actually write this in the way that makes most sense. I'd really like to avoid having to go through and do one event for every single city that I don't want to be able to trade. Also I'm not totally certain how to write the actual line "traderoute.to (the -> city part is throwing me).

Hopefully it's another one of my stupid "it's been a long day" questions that isn't too hard for one of our experts to explain :) Thank you all!

Code:
1if tribe == object.pJapanese then
  2  for city in civ.iterateCities() do 
    3        if city.owner == object.pJapanese and (city ~= object.cNagasaki and city ~= object.cKagoshima and city ~= object.cKumamoto and city ~= object.cUita and city ~= object.cKitakyushu and city ~= object.cHiroshima) then
      4          if city.tradeRoutes[0] then
        5        city:removeTradeRoute(0)
                civ.ui.text("HOUSE RULES: You may only trade with Japan itself.  Any cities with a trade route on the mainland will have that route deleted each turn.  As you violated this house rule, a -25 gold penalty has been taken.")
                object.pJapanese.money = object.pJapanese.money - 25
                end
                if city.tradeRoutes[1] then
                city:removeTradeRoute(1)
                civ.ui.text("HOUSE RULES: You may only trade with Japan itself.  Any cities with a trade route on the mainland will have that route deleted each turn.  As you violated this house rule, a -25 gold penalty has been taken.")
                object.pJapanese.money = object.pJapanese.money - 25
                end
                if city.tradeRoutes[2] then
                city:removeTradeRoute(2)
                civ.ui.text("HOUSE RULES: You may only trade with Japan itself.  Any cities with a trade route on the mainland will have that route deleted each turn.  As you violated this house rule, a -25 gold penalty has been taken.")
                object.pJapanese.money = object.pJapanese.money - 25
                end
            end 
    end
end
 

Prof. Garfield

Deity
Supporter
Joined
Mar 6, 2004
Messages
3,846
Location
Ontario
I haven't worked with the traderoute stuff yet, but I'm pretty sure this will work.

Code:
local function isNotInJapan(city)
    -- return true if a city is not in japan,
    -- and false otherwise
    return city ~= object.cNagasaki and city ~= object.cKagoshima and city ~= object.cKumamoto and city ~= object.cUita and city ~= object.cKitakyushu and city ~= object.cHiroshima
end
if tribe == object.pJapanese then
    for city in civ.iterateCities() do
        for tradeRouteID=2,0,-1 do
            if city.tradeRoutes[tradeRouteID] then
                local route = city.tradeRoutes[tradeRouteID]
                if isNotInJapan(route.from) or isNotInJapan(route.to) then
                    civ.ui.text("HOUSE RULES: You may only trade with Japan itself.  Any cities with a trade route on the mainland will have that route deleted each turn.  As you violated this house rule, a -25 gold penalty has been taken.")
                    object.pJapanese.money = math.max(object.pJapanese.money - 25,0)
                    city.removeTradeRoute(tradeRouteID)
                end
            end
        end
    end
end
We check the 3 possible trade routes in reverse order, since removing a trade route shifts the IDs of the remaining routes. That is, if you remove route 0, route 1 now takes on the ID of 0. With a reverse order check, we don't need to worry about that.

I also removed the trade route last, in case you want to use city names in the text. I'm not sure I would call this a "House" Rule when a penalty is levied in game.

Let me know if you want more explanation, or if this doesn't work.
 

JPetroski

Deity
Joined
Jan 24, 2011
Messages
4,517
This threw up an issue with the last line before all the ends (city.removeTradeRoute(tradeRouteID) - looks like it wanted a city instead?

Code:
Enter console.commands() to see a list of keys in the console table.  Some give access to functions in modules, others will run event code.
...Scenario\1937-Japan Invades China\consolidatedEvents.lua:709: bad argument #1 to 'removeTradeRoute' (civ.city expected, got number)
stack traceback:
    [C]: in field 'removeTradeRoute'
    ...Scenario\1937-Japan Invades China\consolidatedEvents.lua:709: in function 'consolidatedEvents.onCityProcessingComplete'
    ...est of Time\Scenario\1937-Japan Invades China\events.lua:444: in function <...est of Time\Scenario\1937-Japan Invades China\events.lua:436>

I haven't worked with the traderoute stuff yet

I personally think this is one of the more interesting recent things... Sanctions, trade treaties and such are all now possible.
 

Prof. Garfield

Deity
Supporter
Joined
Mar 6, 2004
Messages
3,846
Location
Ontario
This threw up an issue with the last line before all the ends (city.removeTradeRoute(tradeRouteID) - looks like it wanted a city instead?

No, I should have put a colon instead of a period.
Code:
city:removeTradeRoute(tradeRouteID)

I think you get the "argument #1, civ.city" expected because the ':' operator puts the item to the left of the colon as the first argument of the function.

I personally think this is one of the more interesting recent things... Sanctions, trade treaties and such are all now possible.

I agree.
 

JPetroski

Deity
Joined
Jan 24, 2011
Messages
4,517
That did work to remove the traderoute. It's showing the text multiple times (one for each trade route) but when I have some time tomorrow I can play around with where to put that and the money cost to make sure it only fires once per turn. Thanks for your help!
 

Prof. Garfield

Deity
Supporter
Joined
Mar 6, 2004
Messages
3,846
Location
Ontario
Hello TheNamelessOne.

I just came across an issue in a hotseat game yesterday where this function was used :

To make it simple, bonuses that were meant for the ai got provided to a human player.
This code was located in the "onTurn" section, before tribes play.

Does this function in multiplayer games only works at the playing player's tribe turn ?
Does it not work at all in multiplayer game ?

Much thanks.

I've replied here, so we don't clutter the Function Reference Thread.

Can you please post the relevant code? I quickly started a hotseat game, and tried this

Code:
function discreteEvents.onTurn(turn) 
    for i=0,7 do
        if not civ.getTribe(i).isHuman then
            civ.ui.text(civ.getTribe(i).name.." is not human.")
        end
    end
end

and it worked as expected.
 

Dadais

King
Joined
Oct 20, 2010
Messages
626
Location
France
I've replied here, so we don't clutter the Function Reference Thread.

Can you please post the relevant code? I quickly started a hotseat game, and tried this

Code:
function discreteEvents.onTurn(turn)
    for i=0,7 do
        if not civ.getTribe(i).isHuman then
            civ.ui.text(civ.getTribe(i).name.." is not human.")
        end
    end
end

and it worked as expected.
Thx prof.

Guess I understood the issue with the used code (from the "old" EpicCasualWWII" scenario) :

Code:
       if civ.getPlayerTribe() ~= Nazi then
           LocationList = {{129,121,0},{135,115,0},{140,124,0}}
           civlua.createUnit(UnitTable.NazInf, Nazi, LocationList,{count = 21, randomize = true, homeCity = nil, veteran = false})
           civlua.createUnit(UnitTable.TanknM, Nazi, LocationList,{count = 12, randomize = true, homeCity = nil, veteran = false})
           civlua.createUnit(UnitTable.ArtillM, Nazi, LocationList,{count = 9, randomize = true, homeCity = nil, veteran = false})
       end
As one of the player wasn't the nazi, it thus triggered the function.

My first assumption was false (I believed I used the isHuman() function to code such a thing), revealing I changed the way I coded :)

I stupidly didn't take time to check the code before asking. My deep mistake there.

Sorry for eating some of your time ! I edited the question post so it won't bother anyone else.
 

Prof. Garfield

Deity
Supporter
Joined
Mar 6, 2004
Messages
3,846
Location
Ontario
Hi all, quick silly question but I haven't been able to find it in the Lua reference: is there a way to add/remove pollution into/from a tile using Lua code?

Thanks

The general library has code to do this:

Code:
gen.hasPollution(tile)-->boolean
Returns true if a tile has pollution.
Returns false othrewise.

gen.placePollution(tile)-->void
Places pollution, unless the tile has a city, airbase or transporter.

gen.placePollutionForce(tile)-->void
Places pollution, unless the tile has a city.
Transporters and airbases are removed, if present.

gen.removePollution(tile)-->void
Checks if tile has pollution, and if so, removes it.

Pollution is a tile "improvement", so you can do bitwise operations yourself if you really want to.

improvements (get/set)
tile.improvements -> integer

Returns the tile's improvements (bitmask).

From @Catfish 's saved game format:

1
2ndByteTile Improvements
0x00Nothing
0x01Unit Present
0x02City Present
0x04Irrigation
0x08Mining
0x0CFarmland
0x10Road
0x30Railroad (+ Road)
0x40Fortress
0x42Airbase
0x80Pollution
0x82Transporter
 
Top Bottom