Under the Comanche Moon (dev thread)

Thanks @techumseh :)

I have a bit of a foundational question here. If I want to write my scenario parameters into lua code, where do they go?
E.g.,
Code:
civ.scen.params.flags = 11010011

Where would something like this go? I want to specifically:
No animations on land and units (not having issues w/this, but want to code it in)
Override .spr
No pollution
No government change

I tried putting the above code into consolidatedEvents.lua. Nothing bad happened, no error, but the US switched gov next turn.
 
I have a bit of a foundational question here. If I want to write my scenario parameters into lua code, where do they go?
E.g.,
Code:
civ.scen.params.flags = 11010011
Where would something like this go? I want to specifically:
No animations on land and units (not having issues w/this, but want to code it in)
Override .spr
No pollution
No government change

I tried putting the above code into consolidatedEvents.lua. Nothing bad happened, no error, but the US switched gov next turn.
Try putting it in an onScenarioLoaded event. However, the representation
is the binary representation of the number (a "bitmask"), and Lua only accepts base 10 or hexidecimal.


Code:
civ.scen.params.flags = 211
 
Thank you! This is great. I think I have the bitmask wrong, then, as the governments are still switching. Or maybe I can't use a saved game. Will do some tests.
 
I have been tinkering with the gen functions for impassable terrain. These are modifying unit abilities on the fly, which is nice.
But is there a way to make a specific tile impassable? I see how to do this with terrain types and with units, but not with coordinates. Any ideas for this?
 
Thank you! This is great. I think I have the bitmask wrong, then, as the governments are still switching. Or maybe I can't use a saved game. Will do some tests.
Is there any reason you're not using the cheat menu for the scenario parameters?

I have been tinkering with the gen functions for impassable terrain. These are modifying unit abilities on the fly, which is nice.
But is there a way to make a specific tile impassable? I see how to do this with terrain types and with units, but not with coordinates. Any ideas for this?
No, you can't make individual tiles impassable. The change has to be for an entire terrain type.

You can change the terrain of individual tiles, or temporarily place AI air units (or units from an allied tribe) on the terrain.

You can also use the onEnterTile execution point to teleport units back onto the previous square.
 
I like that last one! That's a great idea. Will tinker.

Prof. Garfield said:
Is there any reason you're not using the cheat menu for the scenario parameters?

As I work on the scenario, I find it easier to do so via .sav files instead of the .scn file. But editing scenario parameters in the cheat menu, and then saving a game, does not save the parameters (while saving the .scn file does). Unless I'm doing something wrong. Or maybe I should just be using the .scn file each time I edit the map.
 
Btw, @Prof. Garfield I had a question about counters. If I define the same counter in 2 separate .lua files, are they building / interacting with one another, or seen as different counters?
 
Btw, @Prof. Garfield I had a question about counters. If I define the same counter in 2 separate .lua files, are they building / interacting with one another, or seen as different counters?
If you make the same counter definition in two files, one of them should produce an error. You only need to make a definition once, even if the counter is used in multiple files. The same string (counter name) always refers to the same counter.

As I work on the scenario, I find it easier to do so via .sav files instead of the .scn file. But editing scenario parameters in the cheat menu, and then saving a game, does not save the parameters (while saving the .scn file does). Unless I'm doing something wrong. Or maybe I should just be using the .scn file each time I edit the map.
Ah, OK. I didn't realise that (except for the scenario name, which I happened to know doesn't stick in the saved game file). Definitely makes sense to use the .sav file for working.
 
That is very convenient. Hooray!

I'm trying to create a function along the lines of "comancheOnTile." Basically, I want the code to read when a resource should be deleted from the map at the end of a turn. In this case, the resource is deleted from the map if it: A. Is not in a tipi, or B. Does not have a carrier. A has been doable and is working. B I can't manage. I'm trying to just get the system to register that a Comanche unit is also on the tile (to give the player a little more flexibility). Here is my attempt:

Code:
local function comancheOnTile(unit)
    local tile = unit.location
    for possibleComanche in tile.units do
        if possibleComanche.owner == civ.getTribe(1) then
            return unit
        end
    end
    return nil
end

discreteEvents.onTribeTurnEnd(function(turn, tribe)
    for unit in civ.iterateUnits() do
    if tribe == civ.getTribe(1) and turn >= 1 and comancheOnTile(unit) == false then
            if (unit.type == unitAliases.Hides or unit.type == unitAliases.Guns or unit.type == unitAliases.Cattle or unit.type == unitAliases.Captives or unit.type == unitAliases.Loot) and unit.location.terrainType ~= 14 then
                gen.deleteUnit(unit)
                gen.justOnce("ExpireMessage",function()
                        civ.ui.text("Be careful! Supplies that are not transported to tipis or traded within your turn will be discarded, stolen, or expired.")  
                end)
            end
        end
    end
end)
 
A few things:

Unless you plan to use Lua to force units from multiple tribes occupy a tile at the same time, the comancheOnTile function could be replaced by unit.owner == object.pComanche (or civ.getTribe(1) if you aren't using an object file). Unless you want the possibility of getting a different unit on the tile?

Code:
comancheOnTile(unit) == false
Given your current definition of comancheOnTile, this will never be true, since comancheOnTile returns a unitObject or nil. The way to write the line would be

Code:
if tribe == civ.getTribe(1) and turn >= 1 and not comancheOnTile(unit) then

Note that this is incorrect:
Code:
unit.location.terrainType ~= 14
If the tile has a river (or an animated resource), even terrain 14 won't satisfy this. You'd need to do one of these:
Code:
unit.location.terrainType % 16 ~= 14
unit.location.baseTerrain.type ~= 14
unit.location.baseTerrain ~= object.bNameOfTerrainTypeFourteen
The last is preferable (do you need info on generating an object.lua file?).

I'd write the event like this, although some changes are just preference:

Code:
local unitTypeExpires = {
    [unitAliases.Hides.id] = true,
    [unitAliases.Guns.id] = true,
    [unitAliases.Cattle.id] = true,
    [unitAliases.Captives.id] = true,
    [unitAliases.Loot.id] = true,
}

discreteEvents.onTribeTurnEnd(function(turn, tribe)
    if turn < 1 or tribe ~= civ.getTribe(1) then
        return
    end
    for unit in civ.iterateUnits() do
        if unit.owner == tribe and unitTypeExpires[unit.type.id] and unit.location.baseTerrain.type ~= 14 then
            gen.deleteUnit(unit)
            gen.justOnce("ExpireMessage",function()
                civ.ui.text("Be careful! Supplies that are not transported to tipis or traded within your turn will be discarded, stolen, or expired.")  
            end)
        end
    end
end)
 
I like the placement of the various expire-able units in a table! Thanks for that.

"Comanche" is the tribe, not the unit. So I'm trying to delete every supply unit that is in a tile without a Comanche unit at the end of each turn. So a random Hides unit that is in the middle of nowhere would be deleted. Should I be changing "return unit" to "return tile"?
 
"Comanche" is the tribe, not the unit. So I'm trying to delete every supply unit that is in a tile without a Comanche unit at the end of each turn. So a random Hides unit that is in the middle of nowhere would be deleted.
OK, so the expiring unit shouldn't be deleted if it is on terrain 14 or it shares the tile with another (non-expiring) unit?
Code:
local guardianUnitTypes = {}

local function hasGuardian(unit)
    local tile = unit.location
    for possibleGuardian in tile.units do
        -- if not unitTypeExpires[possibleGuardian.type.id] then
        if guardianUnitTypes[possibleGuardian.type.id] then
            return true
        end
    end
    return false
end
The commented out line is there if you find it easier to just use any non-expiring unit as the "guard"

Then change the if line in the actual event to
Code:
        if unit.owner == tribe and unitTypeExpires[unit.type.id] and unit.location.baseTerrain.type ~= 14 and not hasGuardian(unit) then
 
Ah, this worked perfectly. For my own edification: I've used tile.units a few times, but not really knowing what it's drawing on. Is this "the tile's units," and are other "tile.xyz" functions possible? It may also be the case of a foundational lesson from months ago has already gone by the wayside (I periodically have to relearn stuff, as this is not my language ;) -- and for that, too, I apologize if I ever repeat my mistakes here).
 
Ah, this worked perfectly. For my own edification: I've used tile.units a few times, but not really knowing what it's drawing on. Is this "the tile's units," and are other "tile.xyz" functions possible? It may also be the case of a foundational lesson from months ago has already gone by the wayside (I periodically have to relearn stuff, as this is not my language ;) -- and for that, too, I apologize if I ever repeat my mistakes here).
An "iterator" is a function that makes a "generic" for loop work. The iterator provides all the items that the loop computes on. The pairs function takes a table as an argument and returns an iterator. civ.iterateUnits and civ.iterateCities are also functions that return iterators.

The tileObject gives an iterator when you access the "units" field (i.e. someTile.units). That iterator lets a for loop execute the loop code for all the units on the tile. All other fields for the tileObject give regular values. Unless I'm very much mistaken, no other civObject provides an iterator when getting a field's value.

I'm not sure what else to say. I write about generic for loops here, but mostly I talk about using the pairs function.
 
Thank you, this is great.

Prof. Garfield said:
The last is preferable (do you need info on generating an object.lua file?).
I have the info, but forgot to generate the object.lua before getting to work on this. I think I am used to the way I'm doing it right now, and feel worried to change it up. But I need to remember to make that for the next project.

I have a more general Lua question, but maybe this is also good for overall scenario design tips. What is the best way to go about "directing" AI in a scenario? I'm doing some things -- creating borders that can't be crossed until certain dates, units that pop in and out, etc., but is there a way to give "targets" to AI or something similar? Any advice here would be appreciated. I'm not really having issues with it yet, so maybe the AI will do great based on their war/peace footing, but just checking on this!
 
Sorry for the next question: I found out a way to "makeAggression" in the lua reference thread, but how about making peace? Is there a function for this?
 
I have the info, but forgot to generate the object.lua before getting to work on this. I think I am used to the way I'm doing it right now, and feel worried to change it up. But I need to remember to make that for the next project.
To generate it there is an option in the menu activated by CTRL+SHIFT+F4. Having it around won't screw up anything (in fact, there is a "dummy" file that comes with the Template). Of course, using a unitAliases table/file is essentially equivalent.

What is the best way to go about "directing" AI in a scenario? I'm doing some things -- creating borders that can't be crossed until certain dates, units that pop in and out, etc., but is there a way to give "targets" to AI or something similar? Any advice here would be appreciated. I'm not really having issues with it yet, so maybe the AI will do great based on their war/peace footing, but just checking on this!
I don't really have any advice for directing the AI, aside from giving goto orders to units. The scenario I did the most work on was two player.

Sorry for the next question: I found out a way to "makeAggression" in the lua reference thread, but how about making peace? Is there a function for this?
The diplomacy module has diplomacy.setPeaceTreaty.
 
Wow! Amazing module. Thanks for sharing this.

This brings me to another diplomacy question. With "unit retirements" through unitData, we have a way to retire a unit after X# turns. For setting flags, can the "flag" be canceled or "expire" after a certain # of turns? How would I mark this time scale?
 
This brings me to another diplomacy question. With "unit retirements" through unitData, we have a way to retire a unit after X# turns. For setting flags, can the "flag" be canceled or "expire" after a certain # of turns? How would I mark this time scale?
I'm not sure what you mean. There is nothing stopping you from changing any particular unit's retirement turn after it has been set the first time. I'm not sure what else you think you need.
 
This is for peace treaties. If I set a flag ("6 month peace treaty,") how do I set a timer on the flag, so that the peace treaty is cancelled after 6 turns?
 
Top Bottom