Events question...

Just to clarify that code (since I think it is neat and useful):

If a German unit is activated when Germany has the Align Romania technology, the text triggers, all Romanian cities are changed to German cities, any Romanian units in the cities are deleted, and then Germany gets a Romanian army in their place. Further, one specific unit receives a specific home city so that the strategic bombing mechanism will work. You'll note that two cities (Kishinev and Jassy) only turn German if the Soviets haven't snagged them first.

There may be other ways to do this, but I've found that I've needed to first convert cities, then delete prior units, then create new units in that order (I suppose steps 1 and 2 might be flippable). It's an extremely powerful event.
 
Just one question:
What is the difference between "~=" and "==" in this code?
Code:
if (unit.owner ~= object.tGermany and unit.owner ~= object.tUSSR) and unit.location.x == object.cKishinev.location.x...
 
yes ~= means does not equal, == means it equals

I probably could have simply had the unit owner == Neutrals there but hey, this works too and who knows if the AI Britain, or whoever, would figure out a way to own the city.
 
Lots of great comments here. @CurtSibling, some of this discussion has kind of hijacked your original thread, and I feel a little responsible for providing the spark! But I also feel like it's a really important conversation that needed to happen and multiple people can hopefully benefit.

Wish I could comment on everyone's recent posts, but that would make this post far too long. I used the Like button on multiple posts above, and will try to quote and respond only to those where I have something more to add than "Agree 100%!"
If you can get your head around Flags in the Macro system, then starting with Lua will be no problem for a seasoned designer like yourself.
:yup: IMHO, the macro system was a real breakthrough in its time, but unfortunately has quirky rules, unreasonable limitations, and convoluted implementations (like Flags). But all this is manageable because it's small -- there's a limited number of valid commands, and a designer who spends time working within it probably feels like they know all of them pretty well. But of course small in scope means that power is limited as well as complexity.

(EDIT: I'm sorry if that sounds too harsh. There certainly have been many fantastic scenarios created using macro, by designers who pushed it to its limits, and I sincerely admire the dedication it took to do so.)

In comparison, Lua can feel (and is) huge. But it isn't necessarily harder. In some ways, the rules are more consistent, the language is more rational and less arbitrary (i.e., there's better justification for why things work the way they do), and the error handling is better. It's the larger scope that makes it seem daunting.

This vastly expanded set of possibilities means that it would take considerably longer to master than macro did. But you certainly don't have to master every nuance of Lua in order to produce useful and interesting events that can add a ton of value to a scenario.
I know there are different ways to achieve the same thing with Lua, with various designers having their own method, all them excellent.
I for one would be happy to see us all agree on what we could call a "Civ2 SL style" of Lua, just so we are all on the same hymn book page.
I think it would be reasonable (and perhaps a better goal for the community right now) to aim for a "Civ2 LST style" of Lua -- LST meaning Lua Scenario Template, as written (and primarily supported) by @Prof. Garfield. I think that definition and focus will help to alleviate some of the first issue regarding different preferences by different designers. There may be multiple ways to achieve the same goal in Lua, and programmers are notorious for endless debates about whose code or approach is better! :lol: But given the way Prof. Garfield has written his template, and recognizing him as the expert in how it's intended to be used, I believe it would be much easier to coalesce around a single preferred approach to implementing a given event with that scope clarification.
Here's the designers readme which is unfinished (I had intended to add some examples and links) but at least talks about what is in every different folder. A read through should at least break down the mystery of what goes in what box.
John, this is an excellent document already and I'm sure you have ideas to make it even better. I would propose that as soon as this can be completed, it ought to be included in the base download of the template (not just with Boudicca, although it's fine there too of course), so that every designer gets this alongside the files and folders that it describes.
... you might need to put

"if turn >= 1 and civ.hasTech..." in the front instead. I'd ask for feedback from the pros on that.
There's no need to add a check for "turn >= 1" to any event. That will always evaluate to true, so it wouldn't change anything. On the other hand, there could be a use case for adding "turn > 1" for events that you want to fire on every turn after the first turn (but not as soon as someone begins a new game with your scenario).
onTurn - event fires the first turn that the game realizes that it Soviets have this tech. May or may not mean it fires the 2nd turn that they have it (I'm not clear on this). Will fire for "first" civ (think in the old days when we deliberately picked civ order based on event order).
afterProduction - event fires after a certain civ starts producing something(?) this event is utilized to make sure that you don't need to worry about civ order - you can define the specific civ's turn that it'll fire on
The word "turn" is often used two ways to mean two different things. In the strict Lua sense, a "turn" of the game is more like what you might call a round. It begins at the point when the date counter increments. The game performs some calculations of its own, then the barbarians play, then tribe 1 plays (the traditionally "white" tribe), then tribe 2 etc. on through tribe 7 (the traditionally "purple" tribe). That ends a single turn.

The onTurn trigger fires once at the beginning of that process -- right away when the date counter increments, before any tribe (including the barbarians) plays. It will not fire again at any point during the turn (between tribes). So any code you put in this trigger will be checked once per turn (or round), always after tribe 7 and before the barbarians or tribe 1.

(@Prof. Garfield, please correct me if I'm wrong with this next part...) The afterProduction event is actually a LST enhancement that isn't a "native" Lua trigger. It runs multiple times during a turn, once for every active tribe, always after that tribe finishes processing its cities and before it moves any units. So if you want an event's condition to be checked between the play of each tribe, the code should go here rather than in onTurn.

There isn't a right or wrong answer for which one to use -- it all depends on what you intend for that particular event.
I've also been playing around with unitActivation frequently. Honestly I think the reason I went with unitActivation is because I wanted an event to fire the same turn that I got the tech, right after I got the tech -- but I'm not 100% this was necessary, I just know it works.
So whereas afterProduction fires once for each player, before they move their first unit, unitActivation fires over and over again while they play, before they move each unit. In John's example, putting the code in afterProduction would work great if all techs were acquired by research. But since techs can also (presumably) be acquired by theft, trade, or conquest during each player's turn, putting his code in afterProduction means that a tech acquired in one of those ways wouldn't be recognized by the event until that player's next turn (i.e., in the next round). So putting the code in unitActivation will make sure that it runs almost immediately.

The downside to this is that code you put in this trigger gets run very frequently, and if the code takes a long time to run, there could be a noticeable lag for the player. For example, in Medieval Millennium I have some events that scan the entire map, one tile at a time, and perform dozens of calculations or checks for each tile. If that code takes 1 second to run, putting it in unitActivation would lead to a one-second "pause" every time a new unit activated, and that would start to get pretty annoying to the player. But since I put this in onTurn, a one-second delay after tribe 7 and before tribe 0 isn't even noticeable.

Is this helpful? Looking for input here. It feels like the question of "where do I put this code" is so prevalent that every designer is going to need to be able to figure out on their own why a given location is best, without asking over and over again -- in other words, teaching people to fish instead of giving them fish. :) What would those of you trying to learn Lua right now find most valuable?
Just one question:
What is the difference between "~=" and "==" in this code?
As JPetroski said, ~= means "not equal to". Lua is a bit odd for using that syntax, since most programming languages use either <> or !=
==
means "is equal to". This is a comparison operator used in a conditional statement (like an "if" or "while" statement).
= means "make equal to". This is the assignment operator used in the effect of an event when you want to change a value, not just check it.
 
Last edited:
(@Prof. Garfield, please correct me if I'm wrong with this next part...) The afterProduction event is actually a LST enhancement that isn't a "native" Lua trigger. It runs multiple times during a turn, once for every active tribe, always after that tribe finishes processing its cities and before it moves any units. So if you want an event's condition to be checked between the play of each tribe, the code should go here rather than in onTurn.

Correct. It uses the unit activation trigger to run, so if a player doesn't have any active units that turn, it won't run. In parameters.lua, you can set a unit type that will be created each turn to ensure every player has an active unit at the start of their turn (and for some other event that is triggered via unit activation). It also lets you choose an out of the way corner for the unit to be created.

There is now a 'beforeProduction' event trigger that works in the same way, except it leverages onCityYield instead.

I think it would be reasonable (and perhaps a better goal for the community right now) to aim for a "Civ2 LST style" of Lua -- LST meaning Lua Scenario Template, as written (and primarily supported) by @Prof. Garfield. I think that definition and focus will help to alleviate some of the first issue regarding different preferences by different designers. There may be multiple ways to achieve the same goal in Lua, and programmers are notorious for endless debates about whose code or approach is better! :lol: But given the way Prof. Garfield has written his template, and recognizing him as the expert in how it's intended to be used, I believe it would be much easier to coalesce around a single preferred approach to implementing a given event with that scope clarification.

It feels like the question of "where do I put this code" is so prevalent that every designer is going to need to be able to figure out on their own why a given location is best, without asking over and over again -- in other words, teaching people to fish instead of giving them fish.

Roughly speaking, this was my intention for the template:

1. Is what I want to do a "setting"? (e.g. what munition can a unit fire?, what can a city build?). If so, find the appropriate file with settings in its name, in the LuaRulesEvents directory. If no, then:

2. When do I want the game to run my code (or check if my code should be run)? Find the file with the name that most closely matches when I want the game to run my code. This will be in either LuaRulesEvents or LuaTriggerEvents\UniversalTriggerEvents .

3. If there are multiple functions already defined in the file, choose the best one for my purpose. (unit killed is like this, mostly to account for circumstances where events 'kill' units, in a single space)

Exceptions:
If I only have a small number of events, it may make sense to put the trigger events in the triggerEvents.lua file, within the appropriate function, instead of in their own file in UniversalTriggerEvents. If I have events that share information, it might make sense to use that file also for those events.

If I have a scenario where the events are significantly different depending on who's playing (e.g. Single player vs multiplayer in Cold War), I might want to use the ContextTriggerEvents. If that's the case, I'll ask for help. If not, I'll ignore the file.
 
@Knighttime
Not a problem - The thread is doing a good job. Lots of great Lua discussions here. :)

Your suggestion about "Civ2 LST style" is inspired. Let's do it. I happily give ProfG my full backing.
Making his style the main one is the first step to making Lua an accepted system for progression of Civ2.

@JPetroski
I've been looking over Boudicca's triggerevents file, it's very interesting. Great work.
Your added Lua comments are invaluable. Seeing the events laid out in this way is
so useful and opens my brain to how certain things are achieved...Nice.
 
Last edited:
But you certainly don't have to master every nuance of Lua in order to produce useful and interesting events that can add a ton of value to a scenario.

I want to highlight this point because it's just so true. I'm nowhere near a master and still pester the pros with alarming regularity, however... I can figure a lot of stuff out on my own now too, thanks to their help and patience. At the very least, I can get it 90% there and then need a quick proof read to see what I've goofed. In Cold War, there were several "new" events like rebel spawn that I was able to more or less get going independently by basically reverse engineering/tweaking stuff that had already been done.

Once you start grasping the "how" behind lua, your civ2 designer brain (which should be well-honed at figuring out ways around problems right now... We basically have been "breaking" the game for 20 years) starts taking off.

One thing I'm proud of is the true east/west movement for linked maps that I have in Hinge of Fate. These two maps are linked together left to right - not one on top of the other as per usual. It really wasn't that difficult to implement.

upload_2021-4-28_6-57-37.png
upload_2021-4-28_6-57-55.png


Here's the thought process:

-I knew that I could track the longitude of any unit
-I knew that it is possible to teleport units anywhere that I want.
-I knew that I could initiate this teleportation with a key press.

For a human player, that's really all I needed... Bring your ship to a certain longitude on the European map, press a key, and then "poof!" it goes to the North American map. That was very pleasing!

OK, but this is a single player scenario, and I need the Allies to send cargo to Europe... How do I do this when the AI won't press a key?

-Well, I knew that unitActivation checks each tile on the AI turn. In other words, lua considers a unit activation to happen every...single...space... that an AI unit moves. So...

-Again, I knew I could check the AI unit's longitude.
-Again, I knew I could teleport the AI unit wherever I wanted.
-I would initiate this teleportation after it crossed a certain line.

Granted, my scenario only needs west --> east movement for the AI. To achieve both directions would require some other consideration, because otherwise they'd just pinball back and forth. I haven't explored it further, but others might take this and run with it. The point is, however, that this is something I would have thought was impossible for me to figure out in 2019 when I was starting, yet I was able to figure it out, basically because I'm starting to get familiar with what can and can't be done.

The mastery element, which is beyond me at the moment, would be adding in something to this event that checks that the teleportation tile is unoccupied and if it is, it moves it slightly. However, on testing, I can confirm that the teleportation doesn't give a hoot if the other tile is occupied by another civ, so it doesn't really matter. The point is, there's always a way to make something better or more refined, but you can probably get to a point where you have something "that works." Think Caesar vs. Napoleon. The latter is far more polished. The former works though, and (I think) it is fun!

've been looking over Boudicca's triggerevents file, it's very interesting. Great work.
Your added Lua comments are invaluable. Seeing the events laid out in this way is
so useful and opens my brain to how certain things are achieved...Nice.

I'm glad you found it useful - that scenario has a "starter pack" for most events that you would want to use. It's small enough you should be able to skim through it but you could always play it and use the text boxes to kind of search for/hone in on what you're trying to do.
 
I think it would be reasonable (and perhaps a better goal for the community right now) to aim for a "Civ2 LST style" of Lua -- LST meaning Lua Scenario Template, as written (and primarily supported) by @Prof. Garfield. I think that definition and focus will help to alleviate some of the first issue regarding different preferences by different designers. There may be multiple ways to achieve the same goal in Lua, and programmers are notorious for endless debates about whose code or approach is better! :lol: But given the way Prof. Garfield has written his template, and recognizing him as the expert in how it's intended to be used, I believe it would be much easier to coalesce around a single preferred approach to implementing a given event with that scope clarification.

Your suggestion about "Civ2 LST style" is inspired. Let's do it. I happily give ProfG my full backing.
Making his style the main one is the first step to making Lua an accepted system for progression of Civ2.

I'm probably not going to be in a position to actually write a "style guide" for a few months. I'm probably going to be more available in terms of "five minutes to answer a question", but far less available in terms of writing a guide or writing and testing substantial code.

I'm not sure I have much of a 'style' anyway, although I do have a bit of an idea of how I planned for the template to be used, which I described above and will quote here:

Roughly speaking, this was my intention for the template:

Roughly speaking, this was my intention for the template:

1. Is what I want to do a "setting"? (e.g. what munition can a unit fire?, what can a city build?). If so, find the appropriate file with settings in its name, in the LuaRulesEvents directory. If no, then:

2. When do I want the game to run my code (or check if my code should be run)? Find the file with the name that most closely matches when I want the game to run my code. This will be in either LuaRulesEvents or LuaTriggerEvents\UniversalTriggerEvents .

3. If there are multiple functions already defined in the file, choose the best one for my purpose. (unit killed is like this, mostly to account for circumstances where events 'kill' units, in a single space)

Exceptions:
If I only have a small number of events, it may make sense to put the trigger events in the triggerEvents.lua file, within the appropriate function, instead of in their own file in UniversalTriggerEvents. If I have events that share information, it might make sense to use that file also for those events.

If I have a scenario where the events are significantly different depending on who's playing (e.g. Single player vs multiplayer in Cold War), I might want to use the ContextTriggerEvents. If that's the case, I'll ask for help. If not, I'll ignore the file.

A couple other things about 'style':

If you're going to write code for others to use, please use (lower) "camelCase" at least for the functions you provide to others. TNO's functions use this case, and I've followed suit for the stuff I've provided, and I think having different cases will just force looking up things for no reason. (I'm happy to hear counter arguments to this.)

My other 'style' is that I've disabled global variables in the template. This makes things so much easier when debugging, but it does make 'linking' files to the state table (or, generally, having files communicate) more difficult. I did provide gen.getState() and gen.getEphemeralTable() to alleviate this, not to mention flags and counters for the simpler instances. I've also provided a global 'console' table, to put things in if you want them accessible to the console. Unfortunately, stopping globals does make the console harder to use, at the very least requiring commenting out a line. Now that I think about it, by inserting a global key associated with a table into the default global table, we could get global functionality on explicit request, but still get explicit errors when a typo happens.

I think I've only commented on avoiding setting and checking flags when the 'status' that the flag is meant to convey is easily accessible directly, and the code writer didn't seem to realise it. I suppose this is 'style', but I just meant it as 'you don't need to have this function span multiple triggers.'
 
I'm probably not going to be in a position to actually write a "style guide" for a few months. I'm probably going to be more available in terms of "five minutes to answer a question", but far less available in terms of writing a guide or writing and testing substantial code.

I'm not sure I have much of a 'style' anyway, although I do have a bit of an idea of how I planned for the template to be used, which I described above...
@Prof. Garfield I'm sorry if anything that I wrote came across as volunteering you for more work. I'm trying (perhaps with too many words!) to promote the work you've already done on the Lua Scenario Template and drive its adoption, because (a) I'd like to see Lua events become more accessible and less intimidating to designers, and (b) it seems unhelpful for me to try and build something on my own to serve the same need and audience.

I hope this doesn't swamp you with too many questions. I'm happy to interpret error messages and review someone's code that isn't working, but I feel like I'm on shaky ground whenever someone asks, "How do I do ___ with the LST?" Often I'm not really sure myself, and I'm afraid I'll either steer them wrong or make something harder than necessary. This exchange may be a typical example: I could interpret the initial error message and explain how to correct that problem. But you were also able to point out two other things that needed to be done... and then there was a further error, which I actually didn't know how to solve within the context of the LST.

Thanks again for the time you've put into this, and let me know if there's anything specific I can do to make things easier for you and the community.
 
Last edited:
I should probably mention that by using the word "style" I didn't really intend to focus on "code styling" (although that's valuable) as much as "approach" or maybe "structure". In other words, using each of the LST files and modules in the way that you envisioned, and putting various definitions and code elements in the right place so that all the linkages function as expected. Your post about intentions for the template, and the Designer Readme file from Boudicca that JPetroski posted, are the type of thing I had in mind, and should be very helpful.
 
From here on, I am looking at the Boudicca triggerEvents as my archetype file to try and do some Overlord events in Lua.
A lot of it makes sense, and I will clone as much as I can, and then come to chase @JPetroski or @Prof. Garfield when things are too dense, or I am too dense. :)

It might sound odd, but to me, the code part is less daunting than the file organisation. :D
 
I should probably mention that by using the word "style" I didn't really intend to focus on "code styling" (although that's valuable) as much as "approach" or maybe "structure". In other words, using each of the LST files and modules in the way that you envisioned, and putting various definitions and code elements in the right place so that all the linkages function as expected. Your post about intentions for the template, and the Designer Readme file from Boudicca that JPetroski posted, are the type of thing I had in mind, and should be very helpful.

Ok, so basically the documentation that I've been 'planning' on doing for a while, but just haven't gotten around to (documentation is not usually the most 'fun' of the Lua stuff I can do). I'll have a think about if there is a way to offload some of the work to others, in order to get this done.
 
yes ~= means does not equal, == means it equals

I probably could have simply had the unit owner == Neutrals there but hey, this works too and who knows if the AI Britain, or whoever, would figure out a way to own the city.

As JPetroski said, ~= means "not equal to". Lua is a bit odd for using that syntax, since most programming languages use either <> or !=
==
means "is equal to". This is a comparison operator used in a conditional statement (like an "if" or "while" statement).
= means "make equal to". This is the assignment operator used in the effect of an event when you want to change a value, not just check it.

Many thanks for the explanations, guys.:thumbsup:

I too using the codes for changing ownership of the cities (I copied the code from Cold War scenario:D) as it perfectly illustrates the Reformation progress within Europe. It's good to know if I use "==" for ownership, that LUA checks if a certain tribe owns the city and only than change ownership. Beside the Reformation I also add some events for the Italian Wars during the early 16th century, where I can use the "==" for Venice.
 
If you wish I can maybe adding another code with explanations like showing text boxes including pictures at a certain turn or event.

This would be great. I haven't tried it yet and if you've done all the heavy lifting I'm happy to shamelessly steal :lol:
 
Attached are the code for text boxes with pictures/graphics in LUA.

This is one of the codes I'm using in 1517, describing the beginning of the Reformation. THe origin of the text code is from @JPetroski's Boudicca scenario, the picture codes are from @Knighttime and @Prof. Garfield. If I wrote or explained anything wrong, please correct me. I've copied the code into the "triggerEvents.lua" file behind function "triggerEvents.onCityProduction(city,prod)".

Code:
--THE REFORMATION
--Diet of Worms (Turn 5 = 1521)
    if  turn ==5 then
        gen.justOnce("Diet of Worms", function()
        local DietofWorms = civ.ui.loadImage("99_DietofWorms.bmp")
        local dialog = civ.ui.createDialog()
            dialog.title = "The Reformation"
            dialog.width = 700
            dialog:addImage(DietofWorms)
            local multiLineText = "Because Martin Luther doesn't recant his Ninety-five Theses..."
            text.addMultiLineTextToDialog(multiLineText,dialog)
            dialog:show()
        end)
    end

Attached are the explanation for every line:
Code:
--Diet of Worms (Turn 5 = 1521)
Only some help text for me to know what event will trigger here. If you use "--" before the text, LUA doesn't interpred this as a code. For me it's easier to sort the events with this method. In Notepad++ this line is coloured green, so you can directly see that this isn't a code.
Code:
   if  turn ==5 then
Start of the event, in this case at turn 5, same like in Macro.
Code:
 gen.justOnce("Diet of Worms", function()
Same like Macro's "justOnce" function. The event triggers only one time. "Diet of Worms" defines the event.
Code:
local DietofWorms =
Set the variable "DietofWorms" for showing a picture in the text box in game. "99_DietofWorms.bmp" is the name of the graphic (Bitmap format), which shall be displayed. I've saved the graphic in the main scenario folder.
Code:
 local dialog = civ.ui.createDialog()
Variable for creating a text box in game.
Code:
dialog.title = "The Reformation"
Title of the text box. If you don't need it, you can delete this line.
Code:
dialog.width = 700
Width of the text box. The maximum should be 750. If you choose 800, the text box will be shown incorrect.
Code:
dialog:addImage(DietofWorms)
LUA adds the defined picture above in the text box. Important, only use the name of the variable, not the name of the picture itself. LUA looks at the variable and see that there is the picture defined.
Code:
local multiLineText = "Because Martin Luther doesn't recant his Ninety-five Theses..."
Text which will appear.
Code:
text.addMultiLineTextToDialog(multiLineText,dialog)
I'm not sure but this code should make automatically line breaks in the text box. I think this line isn't really neccessary. Maybe our LUA experts can say more.
Code:
 dialog:show()
LUA displays the text box in game. Without this line, the text box won't be displayed.
Code:
  end)
    end
Ending of the event.

If you made everything right, the code for the event should look like this one:
upload_2021-4-29_19-53-16.png




And in game it looks like this one:
upload_2021-4-29_19-52-7.png
 
Back
Top Bottom