Lua Scripting Possibilities

if city.cityAliases == cityAliases.Berlin and defender.tribeAliases == tribeAliases.Germans then

should simply be

if city == cityAliases.Berlin and defender == tribeAliases.Germans then

The variable "city" contains a city object, since that's what is passed in to this trigger function, and you've stored the city object for the city of Berlin as "cityAliases.Berlin", so those are the two objects you want to compare.
Similarly, the variable "defender" contains a tribe object, and you've stored the tribe object for the Germans as "tribeAliases.Germans", so those are the two objects you want to compare.

Does that resolve your issue?
 
To do something like "any city" in the context of the above example, you can just omit the comparison for "city" entirely:

if defender == tribeAliases.Germans then

allows you to take action whenever the city that was taken was defended by the Germans, regardless of which city it is.

(Note that this is different than if you want to check or change something for every city in the game all at once -- that requires a loop using civ.iterateCities.)

In order to have a 10-turn timer that continues to function across save / exit / reload, you'll need to store it as a variable within the state table. You would probably initialize this by setting it to 1 within the onCityTaken() trigger. To have it apply only to the first city, and avoid resetting it if another city is taken, just check the value of it first, and don't set it to 1 if it has already been defined. Then within the onTurn() trigger, increment the state variable and test to see if it's equal to 10.
 
Last edited:
I don't know if this is humorous or just frustrating to you (I hope humorous) but thank you for the help! That definitely solved the problem. I will have to try adding the timer now.

I'm also trying to get certain units to die each time they land in terrain 0 or 15 (but a few units can land in 15 but not 0). I tried to modify the munitions coding but this is throwing up an error (it says "then" is expected in the last paragraph, but it is there?)

Code:
local currentUnit = civ.getActiveUnit()
local cannotLandCityItalyRussia = {
["Me109G6"] = { cannotLand=civ.getUnitType(12), killedTerrain={0, 15, -128, -114} },
}
for unit in civ.iterateUnits()do
        for _, cannotLand in pairs (cannotLandCityItalyRussia) do
            if unit.type.id==cannotLand then
            killedTerrain=0
            for _, killedTerrain in pairs (cannotLandCityItalyRussia.killedTerrain) do
                if currentUnit.location.terrainType==killedTerrain then
                killedTerrain=1
                end
            end
          
            if killedTerrain=1 then
                civ.deleteUnit(unit)
                end
            end
      
        end

I need to ask - how long did it take you guys to figure out how to do this stuff :lol:
 
I'm not frustrated... I hope you're not either! Personally I think it's kinda cool watching/helping someone else figure out programming.

"if" checks in Lua require a double equals sign; a single equals sign is used to set or change a value. In programmer-speak, = is an assignment operator and == is a relational or comparison operator. Try:

if killedTerrain == 1 then

EDIT: That might fix the syntax, although I'm not sure it will clear up all your issues. It looks to me like you're re-using killedTerrain as both an integer (0 or 1) and as the value returned by pairs() -- and as a key within cannotLandCityItalyRussia. That probably isn't quite what you need to be doing.

I honestly hadn't used Lua until TNO added it to TOTPP, but I've learned quite a few other languages over the years; that's a huge help since the concepts are all pretty much the same, and it's just learning the implementation and syntax that takes a bit of time. I couldn't tell you how many hours I spent on Lua for Civ though... thankfully I don't need to keep track of that! :lol:
 
"if" checks in Lua require a double equals sign; a single equals sign is used to set or change a value. In programmer-speak, = is an assignment operator and == is a relational or comparison operator.

Knighttime, thank you very much for explaining this. :) I´m a complete 'not-programmer' and I wondered about the cryptic mechanism behind ==.

Other things I´m wondering about when having a look in the lua event file of the Cesar scenario:

What means:--g ?

Why is the cryptic writing in different lines, avoiding the listing in columns:



When inserting this formating into this post, the text stands in columns:


civ.getUnitType(64).move = 5*multiplier --g Titus Labienus in winter

civ.getUnitType(65).move = 6*multiplier --g Cretan Archers in winter


The following text brings me next to capitulation :sad::

if recruitmentUnit.displayText ~= nil then

civ.ui.text(func.splitlines(tostring(recruitmentUnit.displayText)))



Inserting this formating into this post, shows the 'ends' in columns:

end

end

end

end


end



end


Why are there different free lines between the end-orders? Couldn´t these 'ends' in the lua events file be written one under the other in a column without loosing their function?
 

Attachments

  • Cryptic text formating.jpg
    Cryptic text formating.jpg
    41.8 KB · Views: 282
  • The End.jpg
    The End.jpg
    6.8 KB · Views: 280
Last edited:
What means:--g ?

-- tells the interpreter that everything on the rest of the line is a comment and to ignore it. Comments help people understand what the code is doing and where.

--g seems to mean the comment was made by Grishnach

if recruitmentUnit.displayText ~= nil then

civ.ui.text(func.splitlines(tostring(recruitmentUnit.displayText)))

Earlier in the code there is a for loop over the table recruitmentUnitTypes. recruitmentUnit was specified to be the name of the "current entry" of recruitmentUnitTypes for the purposes of specifying further instructions.

recruitmentUnit.displayText takes the data "stored in" recruitmentUnit and returns the part of that data "named" displayText.

~= is the "not equal to" operator. It returns true if two things are not equal, and false otherwise. nil is the lua representation of "no data" or "missing data."

if recruitmentUnit.displayText ~= nil then

is the instruction to do all the code between "then" and its corresponding "end" if recruitmentUnit.displayText actually refers to some kind of data.

civ.ui.text(string) prints the string (list of characters) in an in-game text box. You can create a string with double quotes, e.g. "This is a string."

func.splitlines(string) adds newline characters to a string, so that it fits in the in-game text box properly.

tostring(input) turns whatever "input" is to an appropriate string.

Why is the cryptic writing in different lines, avoiding the listing in columns:



When inserting this formating into this post, the text stands in columns:


civ.getUnitType(64).move = 5*multiplier --g Titus Labienus in winter

civ.getUnitType(65).move = 6*multiplier --g Cretan Archers in winter

In my text editor, those particular lines are in a column.



Inserting this formating into this post, shows the 'ends' in columns:

end

end

end

end


end



end


Why are there different free lines between the end-orders? Couldn´t these 'ends' in the lua events file be written one under the other in a column without loosing their function?

Lua ignores "extra" "whitespace," so extra spaces, tabs and newlines don't change how the interpreter uses code.

https://en.wikibooks.org/wiki/Lua_Programming/whitespace

Indentation tends to make code more readable. It is much easier to see what code is in an "if statement" or "for loop" if the code is indented. Some text editors will even anticipate the indentation that you'll want on the next line.

As for the spare lines between the "end" lines, they are probably there because it is easier to write the "end" at the same time as the statement needing the "end," rather than remembering to put it in later, but having it it on the very next line makes the code feel "cluttered" when writing it.

Are you looking at the code in a proper text editor (or lua interpreter)? I think people have recommended notepad++ as one that colours lua code properly. (I use the text editor that comes with Linux Mint, so I can't recommend it to a Windows user.)
 
Prof. Garfield, thank you very much for your explanations to my questions. :thanx:

Now I´m less irritated by those signs in the lua events file and have a chance to understand it a little bit better. May be your explanations and the explanations of Knighttime help some other modders too, who are -like me -no programmers, in better understanding the lua events file.

I opened the lua events file with word as it has a function to number all lines and with Wordpad. I tried to add the changes in the lua code you have suggested in the Cesar scenario thread, but I wasn´t succesful. I will have a look at notepad ++ and at your link to lua programming / whitespace.

About the several cluttered 'ends', would it be also correct to write end, end end, end, end in one line?
 
Last edited:
To give another editor option, that colours Lua code properly: http://luaedit.sourceforge.net/download.html

"This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License […] LuaEdit is powerful script editor and debugger for the 5.1 and/or 5.2 version of Lua. It features many tools such as advanced breakpoint management, syntax highlighting, completion proposal list, local and global variable windows."
 
Last edited:
Prof. Garfield, thank you very much for your explanations to my questions. :thanx:

Now I´m less irritated by those signs in the lua events file and have a chance to understand it a little bit better. May be your explanations and the explanations of Knighttime help some other modders too, who are -like me -no programmers, in better understanding the lua events file.

I opened the lua events file with word as it has a function to number all lines and with Wordpad. I tried to add the changes in the lua code you have suggested in the Cesar scenario thread, but I wasn´t succesful. I will have a look at notepad ++ and at your link to lua programming / whitespace.

About the several cluttered 'ends', would it be also correct to write end, end end, end, end in one line?

Hi Civinator. Attached please find the updated events for Caesar so that you can utilize the change. I tested this and it works for me - I'm not sure where/how you placed it and couldn't get it to work. Did it throw up an error for you? You can hit ctrl + shift + F3 to see what the error is.
 

Attachments

  • Events.zip
    25.6 KB · Views: 124
Well everyone, it is a very small step but all of your considerable help is paying off a bit because

1. I was able to write this very simply code;
2. I was able to interpret the "migrating events to lua" to add some stuff I didn't have a sample for elsewhere;
3. When it initially messed up, I was able to determine where I needed to add an "end)" to fix it and it almost made sense.

So I appreciate all of your help very much!!!

Code:
civ.scen.onCityTaken(function (city, defender)
     if defender == tribeAliases.Germans then
     justOnce("DDayInvasion", function ()
    civ.ui.text(func.splitlines(textAliases.DDayText))
    tribe = civ.getCurrentTribe()
    tribe:giveTech(civ.getTech(75))
    end)
  end
end)


local state = {DDayInvasion = false}

It's a small step but feels good. Now to try and add the part about the countdown and the D-Day event, at least, will be complete.
 
So here is what I attempted to get the D-Day delay to work. It has failed. The error is that I'm attempting to compare a number with a nil stack trace back.

What I attempted to do here was add a state for when the Allies capture any city (because I'm not tying this to a particular city I think this is how I need to handle this?) I then wanted to also set a state for when the Germans capture any Allied city (which is only possible on the actual continent), and if that state is triggered within 5 turns then there is a text for the loss. I'm not sure if I am approaching this the wrong way.

D:\Test of Time\Scenario\OTR3\events.lua:1143: attempt to compare number with nil
stack traceback:
D:\Test of Time\Scenario\OTR3\events.lua:1143: in function <D:\Test of Time\Scenario\OTR3\events.lua:1139>
D:\Test of Time\Scenario\OTR3\events.lua:1143: attempt to compare number with nil
stack traceback:
D:\Test of Time\Scenario\OTR3\events.lua:1143: in function <D:\Test of Time\Scenario\OTR3\events.lua:1139>


Code:
local state = {}

state.DDayInvasion=state.DDayInvasion or 0
state.AlliesRepulsed=state.AlliesRepulsed or 0



civ.scen.onCityTaken(function (city, defender)
     if defender == tribeAliases.Germans then
     state.DDayInvasion=1
     justOnce("DDayInvasion", function ()
     civ.ui.text(func.splitlines(textAliases.DDayText))
     tribe = civ.getCurrentTribe()
     tribe:giveTech(civ.getTech(75))
    end)
  end
 
      if defender ==tribeAliases.Allies then
     state.AlliesRepulsed=1
     end 
 
end)




  if state.delay > 0 then  -- this is line 1139
    state.delay = state.delay - 1
  end

  if state.delay == 1 or 2 or 3 or 4 or 5 and state.DDayInvasion==1 and state.AlliesRepulsed=1 then  -- this is line 1143
    civ.ui.text(func.splitlines(textAliases.AlliedLoss))
  end
end)
 
It looks like state.delay wasn't defined, and so evaluated to nil. Then, you tried to evaluate nil > 0 and nil ==1 I believe I've guarded against this

I've changed state.DDayInvasion and state.AlliesRepulsed to boolean (true/false) variables.

Try this

Code:
local state = {}

state.DDayInvasion=state.DDayInvasion or false
state.AlliesRepulsed=state.AlliesRepulsed or false



civ.scen.onCityTaken(function (city, defender)
     if defender == tribeAliases.Germans then
     state.DDayInvasion=true
     justOnce("DDayInvasion", function ()
     civ.ui.text(func.splitlines(textAliases.DDayText))
     tribe = civ.getCurrentTribe()
     tribe:giveTech(civ.getTech(75))
    end)
  end
      if defender ==tribeAliases.Allies then
     state.AlliesRepulsed=true
     end
end)




  if state.delay and state.delay > 0 then  -- this is line 1139
    state.delay = state.delay - 1
  end

  if  state.delay and state.delay >= 1 and state.delay <= 5 and state.DDayInvasion and state.AlliesRepulsed then  -- this is line 1143
    civ.ui.text(func.splitlines(textAliases.AlliedLoss))
  end
end)
 
state.delay == 1 or 2 or 3 or 4 or 5 and state.DDayInvasion==1 and state.AlliesRepulsed==1

This is the expression for an if statement. It won't do what you expect it to do. or compares two values, and returns true if one of them is true and false if both are false. and compares two values and returns true if both of them are true, and false otherwise. In lua, nil and false are false and everything else is true. (including 0).

https://www.lua.org/pil/2.2.html

Since 2 is true as far as or is concerned, 2 or (...) will always be true, and so the if statement will always hold.
 
The event does not fire at all unless I switch the position of the justonce function and the state. Would putting the justOnce above the state mean that the state is no longer persistent? I ask because I can't get the first event (the DDayText) to fire without doing this, yet the second event (textAliases.AlliedLoss) does not fire on the recapture. I tried this by having the Germans recapture on the same turn and the next turn and neither seems to work. Any ideas? Am I not correctly linking the delay to the AlliesRepulsed state being true?

if defender == tribeAliases.Germans then
state.DDayInvasion=true
justOnce("DDayInvasion", function ()

civ.ui.text(func.splitlines(textAliases.DDayText))
tribe = civ.getCurrentTribe()
tribe:giveTech(civ.getTech(75))
end)
 
justOnce("DDayInvasion", function ()

Try changing the "key" to the justOnce function. At the moment you already have "DDayInvasion" as a key in state.
 
I tried changing the red to "OperationNeptune" and the event still does not fire, though I'm not sure I totally follow you (other than not wanting two things named DDayInvasion.
 
You did what I suggested. I'm not sure what is going on. I'll think about it some more, but perhaps @TheNamelessOne can explain how to use the state variable.
 
To give another editor option, that colours Lua code properly: http://luaedit.sourceforge.net/download.html

"This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License […] LuaEdit is powerful script editor and debugger for the 5.1 and/or 5.2 version of Lua. It features many tools such as advanced breakpoint management, syntax highlighting, completion proposal list, local and global variable windows."

Hi Civinator. Attached please find the updated events for Caesar so that you can utilize the change. I tested this and it works for me - I'm not sure where/how you placed it and couldn't get it to work. Did it throw up an error for you? You can hit ctrl + shift + F3 to see what the error is.

Thank you both very much. :thanx:

JPetroski, yes it did throw out an error, but I haven´t listed that error and deleted my try. Besides playing your great scenario, I will have a look into your file to see how you inserted the code into that file.
 
I'm swinging and missing all over the place! Here's another one I can't get to work (I don't get any errors but the terrain never changes) - I am using the civ.scen.onTurn(function (turn)

Code:
if tribeAliases.Allies:hasTech(civ.getTech(76)) then
    tile = civ.getTile(405, 75, 0)
    tile.terrainType = 2
  end
 
I think I've tidied up the DDay events

Code:
local state = {}

state.DDayInvasion=state.DDayInvasion or false -- I don't think these are needed
state.AlliesRepulsed=state.AlliesRepulsed or false -- Comment out if state still doesn't work

civ.scen.onCityTaken(function (city, defender)
     if defender == tribeAliases.Germans then
     state.DDayInvasion=true  -- this could probably be moved inside justOnce, but it shouldn't matter
     justOnce("OperationNeptune", function ()
     civ.ui.text(func.splitlines(textAliases.DDayText))
     tribe = civ.getCurrentTribe()
     tribe:giveTech(civ.getTech(75))
     state.delay = 5 -- added this line to initialize the delay
    end) -- end justOnce
  end --End if defender is german
      if defender ==tribeAliases.Allies then
     state.AlliesRepulsed=true
     end
 -- removed end) at this line.  Everything that was below this would run when you loaded the file and not when a city was taken
  if  state.delay and state.delay >= 1 and state.delay <= 5 and state.DDayInvasion and state.AlliesRepulsed then  -- this is line 1143
    civ.ui.text(func.splitlines(textAliases.AlliedLoss))
  end -- End loss check
end) --End function and onCityTaken

-- Put this in the onTurn trigger
  if state.delay and state.delay > 0 then  -- this is line 1139
    state.delay = state.delay - 1
  end
 
Top Bottom