Lua Scripting Possibilities

--Text for Event
local WarriorsKilledText = [[If you are seeing this, then the text portion at least works]]
local IntroText=[[does this work?]]

-- The `onTurn` function runs its argument every turn, with the turn number passed as `turn`.
civ.scen.onTurn(function (turn)
-- Show the intro text on the first turn. I'm omitting `justOnce` since it won't be turn 1 more than once anyway.
if turn == 1 then
civ.ui.text(func.splitlines(introText))
end
end)

IntroText and introText are not the same. Variables are case sensitive. Check if this fixes your error.
 
I just checked the original zip file I uploaded and the unit killed works as I wrote it now that I've added the blank events.txt. Not sure why it wasn't working for you?
 
I thought units start with "0" but I could be wrong... in any event, if you changed "2" to "3" we'd quickly find out.

I just tested your original code after adding an events.txt file, and the event worked as expected.
 
I've never felt as good about a unitkilled event =)

Now I'll have to see if I can try to code something that you can't do in macro.txt...
 
Can someone point me to a guide to the civ 2 macro language? I'm thinking it might be worthwhile to write functions that are direct implementations of the macro language (or, at least a minimally altered version of the macro language). This would allow scenario makers to keep using their existing knowledge of the macro language and then learn lua when it is needed to achieve something new.
 
The macro language for ToT is contained in the document, macro.txt (attached), usually found in the main installation folder for English versions of the game.

For clarification of events involving flags and transport relationships, see the Test of Time section at the bottom of the Scenario League's Tips page.

For clarification of the EnableTechnology event, see my own guide on the subject.
 

Attachments

I wonder if lua will have the same issues as the macro.txt in terms of what actions are forbidden in what events... For example, not allowing the "ReceivedTechnology" and "TakeTechnology" in the same event...

You can get around it with flags, but you have to tie up two flags and takes two events:

Spoiler Example from Over the Reich :

Here, if Allies bomb Krupp Works, Germans get technology 80 "Krupp Works Destroyed", which would reduce the number of units that will be produced when they research a "Production Run" (totally different tech than in these sequences). I had a third tech, tech 81 "Krupp Works Repaired. This event is showing what happens there (it needs to remove the "destroyed" tech so the Allies can attack it again, and it needs to then remove the "repair" tech so the Germans can repair it again if the Allies destroy it again.

@IF
CheckFlag
who=Germans
Technology=81
State=on
flag=11
@THEN
TakeTechnology
whom=Germans
technology=80
TEXT
Through considerable effort, the Germans manage to repair the Krupp Works, restoring production.
ENDTEXT
Flag
Continuous
who=German Industry
State=on
flag=11
@ENDIF

@IF
CheckFlag
who=German Industry
flag=11
State=on
@THEN
TakeTechnology
whom=Germans
technology=81
Flag
Continuous
who=German Industry
State=off
flag=11
@ENDIF
 
Can someone point me to a guide to the civ 2 macro language? I'm thinking it might be worthwhile to write functions that are direct implementations of the macro language (or, at least a minimally altered version of the macro language). This would allow scenario makers to keep using their existing knowledge of the macro language and then learn lua when it is needed to achieve something new.

There's also a complete chapter on the Macro language in the "Civilization II: Test of Time" manual starting on page 199, which is better formatted and perhaps more complete, and which you can access from CivFanatics download section here.
 
Last edited:
You got that to work in the scenario I posted? I can't replicate it. The absolute only thing I can get to work is the print in the lua console itself.

@tootall_2012 - you've played around with this a bit - am I supposed to run any kind of delevent file / is there an actual file called a civ.scen library? My download of ToTPP did not include this?

I thought I had created a pdf but I can't seem to find it. You can find the library of LUA functions in the "[TOTPP] Lua function reference" thread here.

Perhaps TNO can confirm but I don't believe the delevent file is relevant anymore. Remember the purpose of the delevent file was to wipe clean the sav file from the previous events of a scenario when you needed to insert new events, and this was only required in the past because there was a limit on how big an event file could be. With ToTPP and Lua this isn't an issue anymore, i.e. your event/lua file can be as big as required (my Vietnam event file ended up being 20,000 lines long, probably 4 times bigger than was previously possible).
 
Last edited:
The macro language for ToT is contained in the document, macro.txt (attached), usually found in the main installation folder for English versions of the game.

For clarification of events involving flags and transport relationships, see the Test of Time section at the bottom of the Scenario League's Tips page.

For clarification of the EnableTechnology event, see my own guide on the subject.

There's also a complete chapter on the Macro language in the "Civilization II: Test of Time" manual starting on page 199, which is better formatted and perhaps more complete, and which you can access from CivFanatics download section here.

Thanks, I'll have a look.

I wonder if lua will have the same issues as the macro.txt in terms of what actions are forbidden in what events... For example, not allowing the "ReceivedTechnology" and "TakeTechnology" in the same event...

We should be able to do whatever we want in any event, as long as the civ.scen library gives us the means of interacting with the "game board" in that way.

It seems, however, that we don't have a received technology trigger at this time. From "migrating events to lua.txt"
Spoiler migrating events to lua.txt :

ReceivedTechnology
------------------
Normally, you'd use the `civ.scen.onTurn` callback in combination with one of the following tests. For receiver=anybody, use the `researched` property of a tech. For a specific receiver, use `tribe:hasTech(tech)`. For the number of future techs, use tribe.futureTechs.
@IF
RECEIVEDTECHNOLOGY
receiver=Humans
technology=38
@And
RECEIVEDTECHNOLOGY
receiver=Anybody
technology=44
@THEN
...
civ.scen.onTurn(function (turn)
local humanTribe = civ.getTribe(2)
if humanTribe:hasTech(civ.getTech(38)) and civ.getTech(44).researched then
...
end
end



The work around is to check every turn if a civilization has a given technology. So, if Germany gets a technology in June 1944, the corresponding trigger won't activate until after the time between June 1944 and July 1944.
 
Well, this doesn't work:

function isInSquare(coordinate)
return function (unit)
local x, y = table.unpack(coordinate)
end
end

civ.scen.onTurn(function (1)
local isInFrance = isInSquare(unit, {{65,7,1}})
local romans = civ.getTribe(0)

-- Give the Germans 100 gold for each unit currently in France
for unit in civ.iterateUnits() do
if unit.owner == romans and isInFrance(unit) then
romans.money = romans.money + 10000
end
end
 
EDIT: DON'T USE THIS CODE. I've been having problems getting it to work.

This is how I would write the code. I haven't tested it, though.

Code:
local function isInSquare(unit,coordinate)
local x,y,z = unpack(coordinate)
if unit.location == civ.getTile(x,y,z) then
return true
else
return false
end
end

local frenchTile = {65,7,1}

local function isInFrance(unit)
return isInSquare(unit, frenchTile)
end

local romans=civ.getTribe(0)

civ.scen.onTurn( function(turn)
for unit in civ.iterateUnits() do
if unit.owner == romans and isInFrance(unit) then
romans.money = romans.money + 100
end
end
end)

EDIT: Noticed error in code.
 
Last edited:
My advice is not to use the unpack function. I had to get rid of it in the code.

After some effort (and finding out that I was editing the events.lua file in the wrong folder) I found correct code to run in our lua test scenario to check if a unit is on (65,7)

Code:
local function isInSquare(unit,coordinate)
local x = coordinate[1]
local y = coordinate[2]
local z = coordinate[3]
if unit.location == civ.getTile(x,y,z) then
return true
else
return false
end
end

local frenchTile = {65,7,0}

local function isInFrance(unit)
return isInSquare(unit, frenchTile)
end

local romans=civ.getTribe(1)

civ.scen.onTurn( function(turn)
    --civ.ui.text("The name of tribe 1 is" .. civ.getTribe(1).name)
    for unit in civ.iterateUnits() do
        if unit.owner == romans and isInFrance(unit) then
        --civ.ui.text("A roman unit is in France")
        romans.money = romans.money + 100
        end
    end
end)

Incidentally, the roman tribe number is 1, not 0 (0 is barbarians). And we're on map 0, so the tile is {65,7,0}.
 
Hi John,

For easy reference, I've created the following "Lua Reference Library" PDF file, whose elements are outlined in the "[TOTPP] Lua function reference" thread mentioned above.

I've also included a new lua.zip file which includes a compendium of TNO's Lua resources (including the library reference file) in the Scenario Creation Excel Sheet thread here.

I hope it will prove useful to all.
 

Attachments

It seems, however, that we don't have a received technology trigger at this time. From "migrating events to lua.txt"
Spoiler migrating events to lua.txt :

...


The work around is to check every turn if a civilization has a given technology. So, if Germany gets a technology in June 1944, the corresponding trigger won't activate until after the time between June 1944 and July 1944.

Not a workaround actually. This is exactly the same behavior as in the vanilla game, RECEIVEDTECHNOLOGY only runs once at the start of the turn.

My advice is not to use the unpack function. I had to get rid of it in the code.

It's table.unpack. This works fine:

Code:
local function isInSquare(unit, coordinate)
local x, y, z = table.unpack(coordinate)
return unit.location == civ.getTile(x, y, z)
end

You could even put all of it in one statement if you'd like.

Code:
local function isInSquare(unit, coordinate)
return unit.location == civ.getTile(table.unpack(coordinate))
end
 
Spoiler your quote :
Order is correct.

giveTech line should be
civ.giveTech(killed.owner,civ.getTech(LegionKilled[unitType].tech))

the homeCity=civ.getCity(Batavodurum) part is also wrong, but don't feel bad, since we need more machinery to get it right.

civ.getCity() converts an integer into the correct city object. We need a function that converts a string into the correct city object. In which case it would be homeCity=stringToCity("Batavodurum")

We can work around this by using the tile where the city should be to get the city.

local bataTile = {1,2,0}
local Batavodurum = civ.getTile(bataTile[1],bataTile[2],bataTile[3]).city

So, I think this would work
1. local bataTile = {1,2,0}
2. local Batavodurum = civ.getTile(bataTile[1],bataTile[2],bataTile[3]).city
3. civ.scen.onUnitKilled(function (killed, killedBy)
4. local unitType = killed.type.id
5. if unitType == 54 then
6. civ.ui.text(func.splitlines(LegioIText))
7. civ.giveTech (killed.owner, civ.getTech (LegionKilled[unitType].tech))
8. civlua.createUnit(civ.getUnitType(31),civ.getTribe(0), massacreLocations[31][1], {randomize=false, veteran=true, count=3, homeCity=civ.getCity(Batavodurum)})
9. end
10. end)

I suppose we could put lines 1 and 2 inside the civ.scen.onUnitKilled if we wanted to.

My only other concern is that you call civ.scen.onUnitKilled twice in your code. I don't know if this is a problem or not. We may have to bundle them all into one call to civ.scen.onUnitKilled by using a sequence of if statements.

Getting back into this after a few weeks of letting my brain calm down and working on a brand new scenario that is now ripe for events and playtesting (yes I know I really ought to conduct more tests but it shouldn't be hard to test these in the scenario).

I'm trying to organize the events to prepare for the new lua scripting...

The events really aren't that complicated...

-I have unit killed events that give technologies to one tribe or another, that change terrain, that create other units, that have a text message, or any combination of these
-I have moveunit events
-I have two events that close off the "tribes may research" (you have to choose if you are going to assimilate Gaul or subjugate it--choosing one closes the other).
-I have a few turn based events asking the player to run a batch file to swap terrains
-I want to have events that give money to the player if Caesar is in Italy during the winter, or if the Roman Legions (and only Legions) are dispersed in winter quarters.

We will see what I can do...

I do take it that based on what you wrote that I quoted above, I will need to have a local line for every single city location so I can use it in the code as it needs to be an integer?
 
I do take it that based on what you wrote that I quoted above, I will need to have a local line for every single city location so I can use it in the code as it needs to be an integer?

There is a city object type of variable in TOTPP lua. In order to use a city in the events, you need to get the corresponding city object. One way to do this is to get the index number of the city and then use civ.getCity(cityInteger) to convert it to the actual city object.

So, for each city that you use for an event, you must get either the integer index of the city, or the city object itself. I recommend establishing a (local) variable for each city that you use using (ie a "local line"), so that it is clear what each line of code does.

Code:
local myCityTile= {3,2,0}
local myCity = civ.getCity(civ.getTile(myCityTile[1],myCityTile[2],myCityTile[3]).city)
...
homeCity = myCity

is preferable to

Code:
...
homeCity=civ.getCity(civ.getTile(3,2,0).city)

The former has a few advantages. First, when you are using homeCity=, it is clear which city you are referring to in that particular line of code. If you had 20 city specific events, you would have to figure out which line corresponded to which specific event when you are debugging. The second is that if you use the same city in multiple events, and you make a mistake in the city location, or something, you only have to change one place to make it correct, rather than go through every line of code and figure out if you need to make a correction to that particular city.

-I have a few turn based events asking the player to run a batch file to swap terrains

This seems like something that should be doable in lua (and would be quite convenient to do there), but perhaps @TheNamelessOne can tell us for sure.

Not a workaround actually. This is exactly the same behavior as in the vanilla game, RECEIVEDTECHNOLOGY only runs once at the start of the turn.

OK. The documentation suggested that it also activated when a technology was actually discovered. That was also how I remembered the old MGE Jules Verne scenario working, but I could be remembering it wrong.
 
Back
Top Bottom