[TOTPP] Prof. Garfield's Lua Code Thread

Oh, I also found (and updated general library) the city attribute flags for an investigated city, a used airport, and a used transporter. It seems that there aren't any 'famine' flags, though perhaps I misremembered how famine works, and expected a flag for it.
 
Repository updated again. A few things added to the General Library

The map can now be declared round or flat, and checked for same. By default it is assumed to be flat.
gen.isMapFlat()-->boolean
gen.isMapRound()-->boolean
gen.declareMapFlat()-->void
gen.declareMapRound()-->void

Distance (gen.distance) was also changed to take into account situations when the map isn't flat. There may be things I overlooked in this regard, so let me know if something doesn't work as expected.

I also produced a couple functions to get nearby tiles

-- gen.cityRadiusTiles(cityOrTileOrCoordTable) --> table
-- gen.getTilesInRadius(centre,radius,minRadius=0,maps=nil) --> table

gen.cityRadiusTiles gets the tiles in the city radius, indexed according to the position of the bit in city.workers that determines if that tile is worked. That is
Code:
--      #       #       #       #       #
--          #       #       #       #       #
--      #       #       #       #       #
--          #       20      13      #       #
--      #       12      8       9       #
--          19      7       1       14      #
--      #       6       21      2       #
--          18      5       3       15      #
--      #       11      4       10      #
--          #       17      16      #       #
--      #       #       #       #       #
--          #       #       #       #       #
Absent tiles have a nil value.

gen.getTilesInRadius is more generic, and simply lists nearby tiles. If a tile doesn't exist, there is no gap in the indices, rather the index is simply used for the next tile.
 
In the course of my other work, I've tracked down a fairly substantial bug in my Legacy Event Engine. This bug essentially means that the 'continuous' modifier was added to all event triggers, due to a pair of typos. I know @JPetroski and @civ2units have used my engine. Maybe @techumseh was planning to use it as well for changing his civil war scenario? I'm not sure if others have used this code.

There have been a couple versions of the Legacy Event Engine around, which are slightly incompatible, so I'll post the code that must be changed. If anyone needs any help making the change, just post your copy of legacyEventEngine.lua and I'll post a fixed version shortly. The change is to the function called
Code:
local function clearSatisfiedEventConditions(eventIndex)
The entire function must be changed to
Code:
local function clearSatisfiedEventConditions(eventIndex)
    g_LegacyState.eventStatusTable=g_LegacyState.eventStatusTable or {}
    if g_LegacyState.eventStatusTable[eventIndex] then
        local eStatus = g_LegacyState.eventStatusTable[eventIndex]
        eStatus.ifConditionSatisfied = (eStatus.ifConditionSatisfied and eStatus.ifConditionContinuous) or nil
        eStatus.andConditionSatisfied =(eStatus.andConditionSatisfied and eStatus.andConditionContinuous) or nil
    end
end
The code should take up the same amount of space.

On the plus side, I've added a means of triggering a legacy event from within Lua. This way, you can express complicated trigger conditions in Lua, but leverage your existing knowledge of the macro system for the action. I first noticed the bug trying to implement this for @civ2units a couple months ago. I'll provide it with the template I'm working on. If anyone has a project requiring legacy events that they'd like to start with sooner, let me know, and I'll help you get it working.

Code:
Lua Trigger
Allows Lua to trigger events in the Legacy Event Engine directly
usage:
@IF
lua
triggername=myluatrigger
@AND
...

legacy.luaTrigger("myluatrigger","triggerAttackerNameOrNil","triggerDefenderNameOrNil","triggerReceiverNameOrNil")
 
Bumping this thread to ask if there is a way to put a hard limit on a type of unit?

I have updated the Imperialism v3 scenario, using Lua, and wish to limit each city to only three Mfg Goods unit.
Once all three are built, it could move to the first unit available on the roster or the next improvement. Or a pop up?

Wondering how feasible this would be?
 
Bumping this thread to ask if there is a way to put a hard limit on a type of unit?

I have updated the Imperialism v3 scenario, using Lua, and wish to limit each city to only three Mfg Goods unit.
Once all three are built, it could move to the first unit available on the roster or the next improvement. Or a pop up?

Wondering how feasible this would be?

One of the keys for canBuildSettings is
Code:
--      .conditionFunction = function(defaultBuildFunction,city,item) --> bool
--          if function returns true, item can be built if other conditions are met, if false, item can't be built
--          absent means no extra condition

This lets us set arbitrary conditions.

In this lesson I count legions and tribe population, and only allow legions to be built if they can be supported by the tribe. I also deal with the fact that we can't see or change the item that a city is producing.

If you want to limit each city to 3 mfg Goods units at a given time, the conditionFunction for Mfg Goods should be something like this (untested code)
Code:
local function limitMFGGoods(defaultBuildFunction,city,item)
    local supportedMfgUnits = 0
   for unit in civ.iterateUnits() do
        if unit.type == object.uMfgGoods and unit.homeCity == city then
            supportedMfgUnits = supportedMfGUnits+1
        end
    end
    return supportedMfgUnits < 3
end
If the city supports less than 3 MfgUnits, true will be returned, and another one can be built (as long as the other conditions are met). If 3 or more are supported, false will be returned, so the city can't build an Mfg unit.

If you only want 3 mfg units to be built per city during the entire game, you would use the state table. A cityProduction event would increment an entry in the state table when appropriate, and the conditionFunction would check this value. If this is what you meant, I can write it for you. It wouldn't be that complicated, but just a little too involved to write 'off the cuff'.

Note that the code I provided above cycles through every unit on the map. That was the main reason I didn't include this type of functionality by default. One or two unit types making this kind of check is probably fine, but too many might cause noticeable lag when changing production in a large scenario. Getting around this is likely to require a scenario specific mechanism. For example, it might sometimes make sense to simply use the conditions that existed after production (and so, the calculation need only be run once per turn, then saved in the state table), but for other scenarios that might not make sense.
 
Thanks for the educational response.
I am trying to grapple with the local functions and codes right now, so this is useful.

I always felt that CIV2 should have had something that limited caravans to 3 per city as default.
There would potentially be a ton of units, and a giant map too...So it might prove too much hassle.
I'll play through my current Lua-enabled Imperialism game, and see how things pan out...:)
 
At the moment, the names of unit types, improvements, and advances are only 'get' fields, so they can't be changed with Lua, in addition to the art. I did suggest this to @TheNamelessOne , around the same time I suggested making the spaceship fields setable. Since the latter was done, I presume that there is some sort of technical difficulty with changing names.
Developping there as not to pollute the scenario thread.

Could we imagine functions to save the game (with no user manipulation), then Launch a Batch file (replacing there ruleset and graphic files), and finally load previously saved game to propose such changes ?
I dislike that on security considerations though.

Howether, simply changing graphics without changing unit type name, all within limits of lua, would still be *incredible :
one could imagine an infantry unit evolving through ages, or one "heros" unit changing its weapons, etc.

.

*changed great for incredible, as what we have at the moment is already beyond great thanks to TheNamelessOne and you.
 
Could we imagine functions to save the game (with no user manipulation), then Launch a Batch file (replacing there ruleset and graphic files), and finally load previously saved game to propose such changes ?
I dislike that on security considerations though.

I'm pretty sure you could use os.execute to run the batch file, and Lua has the capability to change files directly instead of relying on the batch file anyway. I don't think you can automatically save or load a game (but you can run os.exit() to immediately quit Civ II). I also dislike this on security grounds, so I haven't looked into it.

I don't know this for sure, but it might be the case that the onLoad event happens after the saved game data is loaded, but before the rules files are chosen, and onScenarioLoaded happens after. In which case, automatic batch file execution (or equivalent) might be possible. But again, this automatic file changing doesn't sit well with me, even if it would be convenient.
 
I don't believe I'm using the correctly. I'm trying to confirm that a tile I want to teleport a unit to is not occupied by a different tribe. Is "gen.isEmpty" the wrong function? Which one should I use instead? I don't need anything more complex than a check to see if the tile can be used by the human or not - if not, I'll simply have a text box telling them to move it a space.

Code:
if gen.isEmpty({unit.location.x,unit.location.y,2}) then 
                    civ.teleportUnit(unit,civ.getTile(unit.location.x,unit.location.y,2))
end
 
I don't believe I'm using the correctly. I'm trying to confirm that a tile I want to teleport a unit to is not occupied by a different tribe. Is "gen.isEmpty" the wrong function? Which one should I use instead? I don't need anything more complex than a check to see if the tile can be used by the human or not - if not, I'll simply have a text box telling them to move it a space.

You want to use the TOTPP native tile.defender, which returns the tribe occupying the tile, and nil if the tile is empty.

gen.isEmpty is used for checking if a table has no key-value pairs.
 
Thanks! Sorry, I've just been looking through the work you did on the general library quite a bit lately and trying to incorporate it. I guess I got confused over that one. I appreciate the help.
 
Sorry to jump in with a request, but I am wondering if there is a Lua event
I could create that allows "+1" bonus to movement/defence/etc with a tech?

I want to get all civs a "special" - For instance the Germans start with "Blitzkrieg" tech,
giving a "+1" bonus to movement for a time, until the Soviets take a city from them.

Is this doable?
 
I've done it using a flag but it could probably be done with techs as well. For some reason I did notice that I had to have a multiple of the movement I really wanted but I didn't explore why. Probably something to do with the road/railroad settings. I think I was going for 25 which is why it says 100.

Code:
--Changing Troop Ship MP for Germany
if unit.type == object.uTroopShip and flag.value("America Can Be Invaded") == true then
object.uTroopShip.move = 100

end

Edit - I did this onActivate but it might work onTurn or other conditions too.
 
I've done it using a flag but it could probably be done with techs as well. For some reason I did notice that I had to have a multiple of the movement I really wanted but I didn't explore why. Probably something to do with the road/railroad settings. I think I was going for 25 which is why it says 100.

Code:
--Changing Troop Ship MP for Germany
if unit.type == object.uTroopShip and flag.value("America Can Be Invaded") == true then
object.uTroopShip.move = 100

end
Edit - I did this onActivate but it might work onTurn or other conditions too.
I'd try a different approach.
I would do it using unittype.move attribute to change when giving/taking back technology, or checking if tech is found, then, checking conditions after each unittype stat reset to set it like whished.

It's nice to see how different ways may give same destination :) .
 
Sorry to jump in with a request, but I am wondering if there is a Lua event
I could create that allows "+1" bonus to movement/defence/etc with a tech?

I want to get all civs a "special" - For instance the Germans start with "Blitzkrieg" tech,
giving a "+1" bonus to movement for a time, until the Soviets take a city from them.

Is this doable?

Don't worry about cluttering this thread. It's original purpose has been taken over by the Lua Scenario Template thread. It doesn't need to be sticky anymore either.

Here's a way to do +1 movement. Untested code follows, and I'm not sure exactly how everything looks in the version of the template you're using, so ask if you need anything else cleared up.

Somewhere, probably object.lua, you need
Code:
flag.define("Soviets Captured German City",false)

In your onCityTaken code, you need
Code:
function triggerEvents.onCityTaken(city,defender)
    -- other city taken code
    if city.owner == object.pSoviets and defender == object.pGermans then
        flag.setTrue("Soviets Captured German City")
    end
    -- other city taken code
end

In afterProduction add the following code. Note some is outside the afterProduction function.
Code:
local blitzkriegBonus = 1
-- these units receive the movemement bonus, and have the following default movement
local defaultUnitMovement = {
[object.uPanzer.id] = 2,
[object.uTroopTruck.id]=3,
}
function triggerEvents.afterProduction(tribe,turn)
    -- other after production events
    if tribe == object.pGermany and not flag.value("Soviets Captured German City") then
        for unitID, defaultMove in pairs(defaultUnitMovement) do
           civ.getUnitType(unitID).move = totpp.movementMultipliers.aggregate*(defaultMove + blitzkriegBonus)
        end
    else
        for unitID, defaultMove in pairs(defaultUnitMovement) do
           civ.getUnitType(unitID).move = totpp.movementMultipliers.aggregate*defaultMove
        end
    end
    -- other after production events
end

For defence, there are a couple options. If the tribe receiving the bonus gets it for tribe specific units, then you can use the same technique as for movement, except don't do the tribe check (since otherwise, they would only get the defence bonus on their turn).

If your template is recent enough to use onInitiateCombat (I think under RulesFiles, initiateCombat.lua, but I changed the file names recently, so I don't know for sure), you can use that to modify defence at the time of combat calculation. I can give more help on that subject if and when you need it.
 
@Prof. Garfield
Thanks for creating this neat code, sir.

I am wondering as a variant, is there a method to do the same, but tie the bonus to the civ holding a certain tech?
So if they own it, the bonus is active, but if tech is revoked, the bonus ends? I would handle the tech give/take aspect.

So if Germany has "Warrior Code", renamed to "Blitzkrieg" tech, I could tie the Lua code to that?

PS
Hope I am making sense after an 8-hour work shift!
 
I am wondering as a variant, is there a method to do the same, but tie the bonus to the civ holding a certain tech?
So if they own it, the bonus is active, but if tech is revoked, the bonus ends? I would handle the tech give/take aspect.

So if Germany has "Warrior Code", renamed to "Blitzkrieg" tech, I could tie the Lua code to that?

PS
Hope I am making sense after an 8-hour work shift!

Sure, the line

Code:
if tribe == object.pGermany and not flag.value("Soviets Captured German City") then
becomes
Code:
if tribe == object.pGermany and tribe:hasTech(object.aBlitzkrieg) and not flag.value("Soviets Captured German City") then

P.S., when I said
Somewhere, probably object.lua, you need
Code:
flag.define("Soviets Captured German City",false)
I meant that it could go in any file (or, at least any file that is at some point required by another file), but that object.lua would be a good place.
 
Hello @Prof. Garfield .
I'm wondering if there's a possibility to break the "7civs" limit with the current system, jumping to the 21 described in rules.txt civs, (or even more) :

-Have a table for diplomatic relations.
-Have a table for each civilisation knowledges, units and cities owned
-Play 3 different turns like ONE same turn (and trick time displayed accordingly).
-Have secured useless "government" cities for 7 players
-At the beginning of new turn, gives the civ its accordingly units & territory and adapt its knowledges, make it at the end of previous tribe's turn human or not.
Divide all other units and territories between altered other 6 civs : "Allied civs", "At Peace civs", "At War civs", "Unknown civs", "Specific civ on diplomatic purpose (to elaborate for AI- maybe not needed for historical scenarios)"
-Some graphical consequences are to be thought indeed, yet, maybe does it worth it ?

Doable ?

.

On another less enthousiastic point, sorry for not dwelving in your most recent template, but did you manage to allow caravan comodities allocation ?
 
Last edited:
Top Bottom