Code:
local newWagon = gen.createUnit(unitAliases.WagonTrain, civ.getTribe(6), {145,13,0}, {homeCity = nil, veteran = nil})
local newWagon = gen.createUnit(unitAliases.WagonTrain, civ.getTribe(6), {145,13,0}, {homeCity = nil, veteran = nil})
Here is my latest attempt:The way you've written it, newWagon is a table. newWagon[1] would be the actual wagon. gen.createUnit makes a table of units, not an individual unit.Code:local newWagon = gen.createUnit(unitAliases.WagonTrain, civ.getTribe(6), {145,13,0}, {homeCity = nil, veteran = nil})
if turn == 7 then
local independenceKansas = civ.getTile(145,13,0)
local santaFe = civ.getTile(34,60,0)
local newWagon = civ.createUnit(unitAliases.WagonTrain,civ.getTribe(6),independenceKansas)
gen.setToGoingTo(newWagon, santaFe)
end
I don't know how the AI decides when to clear goto orders, but you should probably have an onActivateUnit or onTribeTurnBegin event that renews the order.For the unit, I tried two things:
1. Made it like a helicopter; air unit with 0 range. It traveled the path, for 2-3 turns, then abruptly doubled back and went through some random hills for a while.
2. Made it like a bomber, air unit with 10 range. It traveled the path for a lot longer -- did pretty well! At one point, though, it doubled back and wound up not moving at all, by a river. Which is sort of how a wagon train might actually behave, so not a terrible outcome. I wonder, though, if I should be separating these goTo orders into smaller chunks along the map. Interestingly, in two tests of this, it did the exact same thing each time.
3. On the 3rd attempt, it went westward to the other side of the map!
4. 4th and 5th attempts, it doubled back again -- interestingly, over by Comanche lands.
I wonder if the AI senses danger/multiple units, and turns around, or if this is what you had mentioned about it canceling its goTo when it encounters an enemy unit.
As you suggested, it seems easiest to either be OK with the randomness of a goTo order -- and perhaps a unit retirement in place -- or do a teleport. I may even implement some version of both.I don't know how the AI decides when to clear goto orders, but you should probably have an onActivateUnit or onTribeTurnBegin event that renews the order.
local function riverNearby(tile)
if tile.river then
return true
end
for _,adjacentTile in pairs(gen.getAdjacentTiles(tile)) do
if adjacentTile.river then
return true
end
end
return false
end
local function waterNearby(tile)
if tile.baseTerrain == 10 then
return true
end
for _,adjacentTile in pairs(gen.getAdjacentTiles(tile)) do
if adjacentTile.baseTerrain == 10 then
return true
end
end
return false
end
discreteEvents.onTribeTurnBegin(function(turn, tribe)
if turn > 0 and tribe.isHuman then
for unit in civ.iterateUnits() do
if unit.type == unitAliases.Tipi and waterNearby(tile) or riverNearby(tile) then
tribe.money = math.max(0,tribe.money + 25)
gen.justOnce("tipisByWater",function()
civ.ui.text("Each tipi placed by water of any kind will generate a small number of horses each turn.")
end)
end
end
end
end)
if unit.type == unitAliases.Tipi and waterNearby(tile) or riverNearby(tile) then
if unit.type == unitAliases.Tipi and (waterNearby(tile) or riverNearby(tile)) then
if unit.type == unitAliases.Tipi and unit.owner == tribe and (waterNearby(tile) or riverNearby(tile)) then
waterNearby(tile)
riverNearby(tile)
waterNearby(unit.location)
riverNearby(unit.location)
local function riverNearby(tile)
if tile.river then
return true
end
for _,adjacentTile in pairs(gen.getAdjacentTiles(tile)) do
if adjacentTile.river then
return true
end
end
return false
end
if tile.river then
return true
end
Just noticed:Thank you, Prof.! This works well. The only issue is that it generates 25 gold flat, even if there are 10 tipis by water. Any ideas why this might be happening?
tile.baseTerrain == 10
adjacentTile.baseTerrain == 10
tile.baseTerrain.type == 10
adjacentTile.baseTerrain.type == 10
That did the trick! Thank you! Works like a charm.Just noticed:
should beCode:tile.baseTerrain == 10 adjacentTile.baseTerrain == 10
That might be it. If you're still not getting enough money, add a line printing information about the current unit to the console, to see if you can figure out what units are missing and why.Code:tile.baseTerrain.type == 10 adjacentTile.baseTerrain.type == 10
One of the Tipis probably had a river tile adjacent.Does this mean that the code was reading the same, single tile of water once, as opposed to all tiles of water? I did baseTerrain for this, but have also used tile.terrainType. I wonder if that would have the same results.
gen.setCityInvestigated will let you click on a foreign city and take a look inside, just as if you had sent a diplomat/spy to look inside the city earlier. I don't know of a way to automatically open a city window.Never making things easy for myself here... I'd like to somehow have an option in a dialog that, if selected, immediately "investigates a city" for the player -- e.g., shows that city's window as if you have spied on it! Is this possible? I have an empty slot in the dialog already wanting to be filled. Would I use, "gen.setCityInvestigated," or something along those lines? Is this even doable?
elseif choice == 3 then
local choice = nil
local dialog = civ.ui.createDialog()
dialog.title = "Anglos Headed to Santa Fe"
dialog.width = 500
local multiLineText = "What kind of information do you want?"
text.addMultiLineTextToDialog(multiLineText,dialog)
if tribe.money >= 500 then
dialog:addOption("How many US troops are there in total? (500 horses)", 1)
end
if tribe.money >= 300 then
dialog:addOption("Tell us about a US settlement (300 horses)", 2)
end
dialog:addOption("Nevermind",3)
choice = dialog:show()
if choice == 1 then
local dialog = civ.ui.createDialog()
dialog.title = "US Military: Total Numbers"
dialog.width = 500
local multiLineText = "All right. For your healthy horses, here is what we know:\n^\n^# of US Militia: " ..tostring(countUnits(unitAliases.USMilitia,civ.getTribe(6))) .. "\n^# of US Infantry: " ..tostring(countUnits(unitAliases.USSoldiers,civ.getTribe(6))) .. "\n^# of US Cavalry: " ..tostring(countUnits(unitAliases.USLgtCav,civ.getTribe(6))) .. "\n^# of US Cannon: " ..tostring(countUnits(unitAliases.USCannon,civ.getTribe(6))) .. "\n^# of US Officers: " ..tostring(countUnits(unitAliases.USCommander,civ.getTribe(6))) .. "\n^# of US Homesteaders: " ..tostring(countUnits(unitAliases.Homesteaders,civ.getTribe(6)))
text.addMultiLineTextToDialog(multiLineText,dialog)
dialog:show()
tribe.money = math.max(tribe.money -500)
elseif choice == 2 then
local menuTable = {}
local offset = 3
for city in civ.iterateCities() do
if city.owner == civ.getTribe(6) then
menuTable[offset+city.id] = city.name
end
end
local informationChoice = text.menu(menuTable,"Select a settlement to ask about:","Information for Horses")
if informationChoice >= offset then
local chosenCity = civ.getCity(informationChoice-offset)
if civ.isCity(chosenCity) then
gen.chartCity(chosenCity,civ.getTribe(1),1)
gen.setCityInvestigated(chosenCity)
tribe.money = math.max(tribe.money -300)
civ.ui.text("Note: You may now take a look at the city window for "..chosenCity.name.." until the end of this turn.")
end
end
elseif choice == 3 then
civ.ui.text("Take care, then.")
end
You also need to use gen.revealTile to show the tile. chartCity just makes the city visible on the tile, if it is already revealed.Yes, that works well. In addition to giving a text message to the player that it has gone through, I need to chart the city for the player so they can see it. I tried this, but it does not chart. Any ideas? (Note: All other aspects of the code below are working great!)
Thank you, Dadais! Slowly plugging away.That's pretty nice to see such a creative concept !
Use the data module.One area I am uncertain on, though, is how I might count the # of a certain unit type killed. For example, throughout the game, I want to keep track of the # of times the Comanche player raids a wagon train. How might I go about that?
Use the data module.
You'll need to define the counter and then you can change or increment it. When you need the value, you can get it.
I'm pretty sure you used flags and/or counters in your last project. The data module works in a very similar way, it just combines the flags and counters into one module, and has the same commands as the supplemental data modules (unitData, cityData, etc).
local function isNearWagonTrain(unit)
for nearbyUnit in gen.nearbyUnits(unit.location,1,unit.location.z) do
if nearbyUnit.type == unitAliases.WagonTrain then
return true
end
end
return false
end
Instead of returning true, return the wagonTrain unit. A unitObject is truthy, (will function like true in if statements), so you can use that function the same way if you need to. Instead of returning false, return nil if there is no wagon train.This is great for units approaching the wagon in a later discreteEvent. However, how do I reference the actual wagon train in that code? "isNearWagonTrain.nearbyUnit" ? Or do I need to define a whole new function for that?
local function getNearbyWagonTrain(unit)
for nearbyUnit in gen.nearbyUnits(unit.location,1,unit.location.z) do
if nearbyUnit.type == unitAliases.WagonTrain then
return nearbyUnit
end
end
return nil
end
local wagon = getNearbyWagonTrain(unit)
if wagon then
-- do something with the found wagon train, since it exists
end