Detecting City Ownership Change / Raze?

sp00n

Prince
Joined
Jan 4, 2007
Messages
371
Is there any decent way to detect when a city changes its owner? Or when it is razed?
There are events for CityAddedToMap and CityRemovedFromMap, and apparently a city is first "removed" from the map when being conquered, and then "added" back in when assigned to another player. The problem is that the cities don't have a global unique ID, they only have a player unique ID, i.e. that ID changes when another player takes control of the city, so you can't just compare the city ID from CityRemovedFromMap to the one from CityAddedToMap. Of course I could simply assume that if the two events happen in consecutive order, that a city has changed it's ownership, regardless of the city ID. But that seems like a very weak condition.
To make matters worse, once the city has been removed from the map, you can't even check if a new city is in that plot right now in the CityRemovedFromMap event function. Firstly, you cannot use Player:GetCities():FindID() request for that city ID, as the city just has been removed. And secondly, you also can't check if the plot currently has a city with Plot:IsCity() (if you somehow managed to the the x,y coordinations for this city before it was removed), apparently there really is no city before the CityAddedToMap event takes place.

Is there an established way to detect city ownership changes?
 
I had noted this for later usage, Events seems to fire in this order:
Code:
InGame:
InGame:  Event :    DistrictRemovedFromMap               
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 6
InGame: 6    917517    393221    88    29    0
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    CityVisibilityChanged                 
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 3
InGame: 6    393221    0
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    CityRemovedFromMap                   
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 2
InGame: 6    393221
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    CityAddedToMap                       
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 4
InGame: 9    458758    88    29
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    CityVisibilityChanged                 
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 3
InGame: 9    458758    2
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    CityInitialized                       
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 4
InGame: 9    458758    88    29
InGame: ------------------------------------------------------------------------------------ End >
InGame:
InGame:  Event :    DistrictDamageChanged                 
InGame: ---------------------------------------------------------------------------------- Start <
InGame: num arguments = 5
InGame: 9    1376276    1587009065    50    0
InGame: ------------------------------------------------------------------------------------ End >

So if I were you I'd get the coordinate (88,29) from DistrictRemovedFromMap (the city center in that case, I suppose you could do an extra check using player and city IDs from CityRemovedFromMap) and compare them to the coordinates from CityAddedToMap.
 
Interesting, so DistrictRemovedFromMap does include the coordinates, while CityRemovedFromMap does not. :rolleyes:

However you cannot use the city ID provided within the CityRemovedFromMap for anything at all it seems, because at that point the city simply doesn't exist anymore for the previous owner. Or any city for whatever player apparently, none of the get city functions I tried returned anything (i.e. CityManager.GetCityAt(x,y), Cities.GetCityInPlot(x,y), Map.GetPlot(x,y):IsCity(), Map.GetPlot(x,y):GetDistrictType()). The "new" city for the new player seems to be created just after that event.


For detecting city ownership changes via conquest I currently settled using the City:GetJustConqueredFrom() return value from within Events.CityAddedToMap. If this value is different to -1 you just took over the city, but have not yet made a choice in the Keep/Raze/Liberate popup.
You can also hook into that popup with LuaEvents.CityPanel_ShowOverviewPanel, however the various choices you can make there don't seem to have an event representation. There is an Events.CityCommandStarted event, but there doesn't seem to be a way to differentiate between the various choices (keep, raze, liberate) - all of them use the same general CityCommandTypes.DESTROY command type, and the actual action to perform is defined in an additional parameter. And you guessed it, exactly this parameter does not show up in the variables for Events.CityCommandStarted.

I also experimented with replacing the callback functions for the choice buttons to add some custom code in, but I'd rather not overwrite any core game mechanic. It's possible though.


Let's see, maybe detecting the city conquest as is right now is enough, and I don't need to know any razed or liberated cities. If not, I might try to make use of that DistrictRemovedFromMap event.
 
Something which caught me by surprise is that CityAddedToMap triggers, for all cities on the map, whenever a savegame is loaded, in addition to triggering when the city is founded or changes ownership. Same goes for DistrictAddedToMap.

CityInitialized seems to only trigger when the city is founded or changes ownership, not when a savegame is loaded.
 
Something which caught me by surprise is that CityAddedToMap triggers, for all cities on the map, whenever a savegame is loaded, in addition to triggering when the city is founded or changes ownership. Same goes for DistrictAddedToMap.

CityInitialized seems to only trigger when the city is founded or changes ownership, not when a savegame is loaded.
This is pretty much consistent with the way Civ5 worked. Loading a save and having the game place all the units that were on the map as part of this process was seen as "creating a unit" for example, so all the events that would fire from a unit creation also fired when the saved game was being loaded.

The final argument ("0") shown by Gedemon for DistrictRemovedFromMap would appear to be the ID (Index) # of the city center district from table <Districts>. The first argument ("6") would appear to be the ID # of the Player who lost the city. The arguments in multiple events showing "393221" would appear to be the CityID # of the city under the old owner. It would also seem likely that "917517" is the ID# of the individual CityCenter District for the captured city before everything was removed and re-created for the new city owner.


--------------------------------------

BTW, the way cityIDs are handled is identical to the way they were handled in Civ5. You were always better off in Civ5 to track by the plot location (x,y) or the plot index # because these don't change regardless of whether there is a city on the plot, or who owns the plot.
 
Last edited:
The final argument ("0") shown by Gedemon for DistrictRemovedFromMap would appear to be the ID (Index) # of the city center district from table <Districts>. The first argument ("6") would appear to be the ID # of the Player who lost the city. The arguments in multiple events showing "393221" would appear to be the CityID # of the city under the old owner. It would also seem likely that "917517" is the ID# of the individual CityCenter District for the captured city before everything was removed and re-created for the new city owner.

Yeah, this was in one of the base game files:
Code:
Events.DistrictRemovedFromMap.Add(
    function(playerID:number, districtID:number, cityID:number, districtX:number, districtY:number, districtType:number)
        if ( districtType == GameInfo.Districts["DISTRICT_CITY_CENTER"].Index ) then
        end
    end
);
 
Last edited:
Back
Top Bottom