Lua Scripting Possibilities

@Prof. Garfield
One more thing to ask - In "eventsTriggers",
I'm using the "onCityTaken" function, I want to emulate this macro:

Code:
@IF
CityTaken
city=AnyCity
attacker=Soviet Union
defender=German Reich
@THEN
JUSTONCE
TEXT
^
^^ Stalin has daringly unleashed a concerted strike upon German
^^ positions. He hopes to dislocate any action from the fascists.
^^ An inspired move, or potential disaster? Time will tell...
^
ENDTEXT
PlayWaveFile
RUS.wav
@ENDIF

The code I have so far is Below...What I want to change is instead of Paris, I would like that any city can be taken, and it will trigger the message...

Code:
function triggerEvents.onCityTaken(city,defender)
    context[getContext()]["onCityTaken"](city,defender)
    universal["onCityTaken"](city,defender)
    legacy.doCityTakenEvents(city,defender)
   
if city == object.cParis and city.owner == object.tGermany then
civ.ui.text("^^ Stalin has daringly unleashed a concerted strike upon German positions. He hopes to dislocate any future aggression from the fascists. An inspired move, or potential disaster? Time will tell...")
civ.playSound("RUS.wav")
end

end

If I can crack this, it enables me to clone lots of macro events into Lua.
 
The code I have so far is Below...What I want to change is instead of Paris, I would like that any city can be taken, and it will trigger the message...

Just omit the check for the city. That is:

Code:
if defender == object.tGermany then

Then, this code will run any time a city is captured from Germany. Note the use of defender instead of city.owner. I'm 99% sure that when the trigger is run, city.owner is now the tribe that just captured the city, and defender is the tribe that lost it (but I can't double check just now).
 
Thanks, sir - I should have said it is a specific justonce event for when the Russians take a city...(it's a Soviet surprise attack)

The defender line is perfect, but is there a way to make this event only fire once when the Russsians take a city?

The flow of how I am doing this in Lua:

1-Russians research a tech - Working.
2-Units are spawned - Working.
3-State of war begins - Working.
4-Russians take a city - Where I am at.
5-Invasion goes on - AI will take things from here. :)

No rush, I am calling it a night for some sleep - 100% appreciate all the help, man.
 
The defender line is perfect, but is there a way to make this event only fire once when the Russsians take a city?

"Wrap" your code inside of a gen.justOnce.

Code:
   gen.justOnce("UniqueJustOnceString", function ()
        -- put your code here
    end) -- the end here is for the function we defined inside of gen.justOnce, the ) is to close gen.justOnce

Then, even though the if statement will be true multiple times, the code inside the justOnce will only execute once. Remember that the string must be unique. If 2 justOnce events share the same justOnce 'key' (first argument), then only one of them will happen. (That could be a useful trick, but you don't want to do it by accident.)
 
I'm curious if one of our more advanced coders thinks something like this is possible for two interesting issues that might be solved by using a similar strategy:


1.
Is there a way for the AI to be directed towards the location of certain human units? Specifically, I'm curious if I had a unit, such as the Bismarck, that was attempting to break out into the Atlantic, if it would be possible to:

1. Acquire the location of this unit (it's the only one out there so this should be possible)
2. Then redirect certain units in an area to that location (for example, maybe British ships out of Scapa Flow try to intercept it).

So basically, I need a location that can change at any given turn to be fed into a goto

How would I go about capturing Bismarck's location? I think I know how to feed it to other units with a forloop that only looks at certain units in a coordinate box (so I don't have battleships in Alexandria abandoning their post to chase the Bismarck).

2.
What does everyone think about this as a way to solve the AI's inability to use aircraft carriers?

-On the AI turn, when a carrier activates, it "senses" if there are human naval units within a range of the carrier.
-If so, AI air units are created on the carrier's tile, their value/unique id is captured, and given a goto command to the human naval units' tile
-Then, at the start of the human player's turn, the air units with that value/unique id are deleted (so the human has to go kill the carrier to get the air attacks to stop).

#1 would make the scenario I'm building much more fun and #2 is my best stab at getting AI carriers to work as they currently don't.

I think #1 is possible, I'm not sure about #2 given the value but thought I'd open it up for discussion.

Thanks all,
 
Disclaimer: all this code is untested.
1. Acquire the location of this unit (it's the only one out there so this should be possible)
Code:
local bismark = nil -- This is deliberately outside the function
local function getBismark()
    if bismark and bismark.type == object.uBismark then
        return bismark
    end
    if bismark == false then
        return nil  -- return nil if no Bismark unit found
    end
    for unit in civ.iterateUnits() do
        if unit.type == object.uBismark then
            bismark = unit
            return unit
        end
    end
    bismark = false -- set to false, so we don't always look for a nonexistent Bismark
    return nil -- return nil if no Bismark unit found
end
Saving the Bismark unit in a variable isn't strictly necessary, but it saves going through all the units in the game every time you need the Bismark (in principle, you will only have to check when the game loads). However, this won't find the Bismark if it doesn't exist at the start of the scenario, at least until you reload the game.

2. Then redirect certain units in an area to that location (for example, maybe British ships out of Scapa Flow try to intercept it).

Code:
local function chaseBismark(hunterUnit)
    local bismarkUnit = getBismark()
    if bismarkUnit and bismarkUnit.location then
        hunterUnit.gotoTile = bismark.location
    end
end

You would have to run this code every turn for each hunterUnit, to update the goto destination.

If you have trouble with units not navigating around Great Britain properly, let me know and I can help you get better navigation (I did this for trains in OTR).

-On the AI turn, when a carrier activates, it "senses" if there are human naval units within a range of the carrier.
-If so, AI air units are created on the carrier's tile, their value/unique id is captured, and given a goto command to the human naval units' tile
-Then, at the start of the human player's turn, the air units with that value/unique id are deleted (so the human has to go kill the carrier to get the air attacks to stop).

This seems like it should work, although I don't think you can actually force a unit to attack. You would probably find gen.nearbyUnits useful when trying to find human units. If you're going to delete the aircraft on the human turn, you might as well delete them by event once they attack (don't make them missile units, or the AI won't use them properly).
 
Has anyone written a working alpha centauri arrival event? I tried to write one this evening in order to test a change to the Lua Scenario Template, and couldn't get it to work, even if I tried to use civ.scen.onCentauriArrival in the console to make an event. Since I'm not running Civ II on Windows, there is a chance the problem is with my setup, so I'd like a second opinion.

It isn't a serious problem for me either way (and I didn't care enough to test this particular event before). All I'm doing is writing a file where a designer can work with most kinds of events in a single file, and leaving this event out of the list isn't a big deal. However, if there is a bug with the event, it would be good to know.
 
I've never tried using this trigger before, but you made me curious so I had to try it out. I agree that this doesn't seem to fire for me either, at least in an Original game (where arrival on Alpha Centauri automatically ends the game). Did you try testing this in an Extended Original, SciFi, or Fantasy game? I wonder if that would make a difference.
 
Last edited:
I've never tried using this trigger before, but you made me curious so I had to try it out. I agree that this doesn't seem to fire for me either, at least in an Original game (where arrival on Alpha Centauri automatically ends the game). Did you try testing this in an Extended Original, SciFi, or Fantasy game? I wonder if that would make a difference.

Just tested in an extended original game, and the event does trigger. Interestingly, if I don't use the console to write an event, the game ends. However, if I do write an event (even just a text box event), the game continues and a few units appear on the next map.
 
Well, that's progress at least :thumbsup: and thanks for testing this. Glad to know the event isn't entirely broken, but maybe there are still bugs undocumented features to be discovered. Too bad that most of the event triggers don't have official documentation.
 
OK, if I start the game as an extended original game, but move it out of that folder, the Centauri event can still happen. The Centauri event availability will persist even after saving as a scenario.
 
I think civ.game.gameType is an undocumented field that contains the value of byte 982 in Catfish's saved game file structure. But I've always wondered at the values:
  • 0x00 Original
  • 0x01 Sci-Fi
  • 0x02 Fantasy
There isn't a separate value for Extended Original? Is that just coded as Original and then detected by the presence of more than 1 map?
 
There isn't a separate value for Extended Original? Is that just coded as Original and then detected by the presence of more than 1 map?

I just tried starting an 'original' game, and adding a second map, and the centauri arrival event didn't trigger.
 
:dunno: Hmm. Well, if you ever figure out how to tell whether a saved game was created as Original vs. Extended Original, please post the details!

For that matter, how did you add a second map to an Original game? By editing Rules.txt in the folder where the saved game was stored, to add a @SECONDARY_MAPS section, and then reloading? I never realized you could change the number of maps once a game was underway.
 
Last edited:
For that matter, how did you add a second map to an Original game? By editing Rules.txt in the folder where the saved game was stored, to add a @SECONDARY_MAPS section, and then reloading? I never realized you could change the number of maps once a game was underway.

I just started on a premade world, and used the cheat menu to import the same map again. Maybe there is a more subtle two map requirement. My main concern was simply to avoid providing a broken event in the template, by at least testing a text box event. This is an interesting mystery, but unless someone has a specific use for this event, I'm not intending to delve further into the mystery at the moment. We went a couple years without noticing the issue with this event.
 
Is anyone willing to write a small script for me? I think other designers would find it useful.

I want certain units (in my case, generals: object.uGuderian, object.uModel, object.uRommel, object.uManstein) to be able to press a button (might as well use "k") while standing on terrain that has the road improvement, and change it to the railroad improvement. In exchange, there is a 1,000 gold deduction, and the general's MP is reduced by 3 (there doesn't need to be a check to see how many MP the general starts with meaning I'm fine with them doing this if they only have 1 MP, I'm simply trying to reduce the number of times a general can do this to 2x per turn and they have 6 MP).

Reason I need it: I have an established road network for a scenario that I would like the player to be able to upgrade, but I want it to be costly so that it is used sparingly. Further, I don't want "new" roads to be constructed - there should simply be an ability to upgrade them. I would think this would be a useful script that could be used in many scenarios.

While I could probably handle a portion of this event myself, trying to figure out if there is a road on a tile is a bit beyond my grasp. Many thanks to anyone who is willing to help.
 
Disclaimer: Untested code follows.

This is the data that goes before the event. Maybe some of this should be in the parameters file.
Code:
local railBuilders = {}
railBuilders[object.uGuderian.id] = true
railBuilders[object.uModel.id] = true
railBuilders[object.uRommel.id] = true
railBuildres[object.uManstein.id] = true
local railUpgradeMoneyCost = 1000
local railUpgradeMoveCost = 3

This part goes in the onKeyPress event, after determining that the appropriate key has been pressed.

Code:
local activeUnit = civ.getActiveUnit()
if activeUnit and railBuilder[activeUnit.type.id] and gen.hasRoad(activeUnit.location) and
    not gen.hasRailroad(activeUnit.location) and activeUnit.owner.money >= railUpgradeMoneyCost then
    local menuOptions = {[1]="No, do not place railroad.", [2]="Yes, spend "..text.money(railUpgradeMoneyCost).." to upgrade this road to a railroad."}
    local menuText = text.substitute("Our %STRING1 unit can place a railroad at the cost of %STRING2 and %STRING3 movement points.  Shall we proceed?",
    {activeUnit.type.name, text.money(railUpgradeMoneyCost),railUpgradeMoveCost})
    local menuTitle = "Place Railroad"
    local choice = text.menu(menuOptions,menuText,menuTitle)
    if choice == 2 then
        activeUnit.moveSpent = activeUnit.moveSpent + totpp.movementMultipliers.aggregate*railUpgradeMoveCost
        activeUnit.owner.money = activeUnit.owner.money - railUpgradeMoneyCost
        gen.placeRailroad(activeUnit.location)
    end
end

In parameters.lua, there is a line with text.setMoney, where you can change how text.money displays money. (If text.money gives you an error, let me know, since that means you have an older version of the template than I thought.)

While I could probably handle a portion of this event myself, trying to figure out if there is a road on a tile is a bit beyond my grasp. Many thanks to anyone who is willing to help.

That's why I wrote the flag functions for the General Library. (There are some new ones for the recent TOTPP version that I haven't added to the documentation yet.)
 
Top Bottom