Disable Found City When Insufficient Terrain Yields

Whys

Between the Lines
Joined
Oct 20, 2007
Messages
461
I'm using ModBuddy, LiveTuner, and SQLite. I've created a test mod that loads an SQL database update and a Lua gameplay script, both as in-game actions. The test shows everything is loading as intended.

I want to enable/disable the found city button for settlers for both players and AI, depending on the terrain yields of the settler's plot and adjacent plots. I don't want settlers to found cities unless there is at least one initial city plot that yields at least 2 food.

As best I can tell, I think I want to replace the UnitPanel.lua, but that won't work for the AI, correct? Can this possibly be achieved through dynamic modifiers?
 
Last edited:

Whys

Between the Lines
Joined
Oct 20, 2007
Messages
461
I keep poking around and I'm thinking I might be able to do it using Events.PlayerTurnActivated and Events.UnitMoveComplete, by scanning through the player's unit list, finding all the settlers, checking the corresponding plot yields, and then disabling city founding for any settlers that don't meet the criteria at their current map location. But I'm not seeing an obvious way to disable the found city operation. I see that the unit table in the database has a "FoundCity" column, but how would I alter it on a unit instance in lua?
 

Jakamo Jones

Chieftain
Joined
Sep 4, 2022
Messages
2
SetBuildDisabled is to disallow the production of specific units, not to prevent the founding of cities.

Replacing UnitPanel.lua is how certain game modes do things, but I had trouble replacing UnitPanel.lua because Gathering Storm already replaces it and I'm not sure how to replace a replacement.

Assuming you can figure out how to make it do, the other game modes override this function:

Code:
function GetUnitActionsTable(pUnit : object)
    local pBaseActionsTable : table = BASE_GetUnitActionsTable(pUnit);
    ...
    -- insert game mode specific actions here
    ...
    return pBaseActionsTable;
end

but there's no reason you couldn't remove actions that you want to forbid, like founding a city.


EDIT: since UnitPanel.lua is just the UI, it'd only disable for players as you mentioned in your first post.
 

Whys

Between the Lines
Joined
Oct 20, 2007
Messages
461
Thank you for your reply. It has confirmed what I needed to know.

So... work around time. What if I create an additional dummy settler unit that can't found city, as per the database? Then I scan through player units as I described earlier and where ever a settler doesn't meet the criteria, I replace it with the dummy settler that can't found city. Then when it moves, I check again and if it does meet the criteria, I replace it with the usual settler unit?

I think that could work. I'll try it and give an update.
 
Last edited:

Whys

Between the Lines
Joined
Oct 20, 2007
Messages
461
The following code is working reasonably well, but I don't know the function arguments for PlayerUnits:Create( ??? ).

Spoiler Test Code :
Code:
--------------------------------------------------------------------------------
function testPlayerTurnActivated()
 
    -- do-nothing.

end
--------------------------------------------------------------------------------
function testUnitMoveComplete(playerID, unitID, iX, iY)
 
    pPlay = PlayerManager.GetPlayer(playerID);
    pUnit = pPlay:GetUnits():FindID(unitID);
    pPlot = Map.GetPlot(pUnit:GetX(), pUnit:GetY());
    yield = pPlot:GetYield(0); -- 0: food, 1: production.
 
    if pUnit:GetName() == "LOC_UNIT_SETTLER_NAME" then
        if yield < 3 then
            pPlay:GetUnits():Create( ??? );
            pPlay:GetUnits():Destroy(pUnit);
        end
    else
        if pUnit:GetName() == "LOC_UNIT_DUMMY_NAME" and yield >= 3 then
            pPlay:GetUnits():Create( ??? );
            pPlay:GetUnits():Destroy(pUnit);
        end
    end
 
end
--------------------------------------------------------------------------------
function init()
 
    Events.PlayerTurnActivated.Add(testPlayerTurnActivated);
    Events.UnitMoveComplete.Add(testUnitMoveComplete);

end
--------------------------------------------------------------------------------

init();

Edit: Nevermind, I finally found this: Create(GameInfo.Units["UNIT_DUMMY"].Index, x, y).

But now, at the start of the game, when it creates the dummy and then destroys the settler, it invokes the defeat sequence and the game is over. There's also a unit creation sound, visual effect, and temporarily two unit flags before one fades away. Hmm... not exactly the work around I was hoping for.

Additionally, I'm concered that the AI will simply leave the dummy settler at its desired found city location, until captured. I think a better work around might be to watch the GameEvents.CityBuilt and if it doesn't meet the criteria, make it a barbarian camp instead of a city. That way the AI will be less inclined to simply send another settler to the same spot... I think.
 
Last edited:
Top Bottom