TASK_REMOVE_SPECIALIST failing to work

Machiavelli24

Mod creator
Joined
May 9, 2012
Messages
818
I have a while loop that is suppose to remove every specialists from a building (so it can safely be deleted) that is getting stuck in an infinite loop during an AI turn. TASK_REMOVE_SPECIALIST seems to fail to remove the specialist from the building.

The odd thing is that while I can consistently produce the infinite loop during the AI turn, if I use fireturner to execute the TASK_REMOVE_SPECIALIST for the AI during my turn it correctly removes the specialist. This implies 1) I have a syntax error in the code below or 2) TASK_REMOVE_SPECIALIST really is failing to remove the specialist but only during the AI's turn.

Code:
while(cityToRemove:GetNumSpecialistsInBuilding(buildingID) > 0) do
	cityToRemove:DoTask(TaskTypes.TASK_REMOVE_SPECIALIST, 0, buildingID, 0);
end

Looking through the C++ code I originally thought it could be an issue with the citizen being automatically reassigned as a specialist to the same building, since DoAddBestCitizenFromUnassigned gets called as part of TASK_REMOVE_SPECIALIST.

From CvCity.cpp
Code:
	case TASK_REMOVE_SPECIALIST:
		GetCityCitizens()->DoRemoveSpecialistFromBuilding(/*eBuilding*/ (BuildingTypes) iData2, true);
		GetCityCitizens()->DoAddBestCitizenFromUnassigned();
		break;
So I added lines to set city:DoTask(TaskTypes.TASK_NO_AUTO_ASSIGN_SPECIALISTS, 0, 0, 1) (and change it back afterward) and tested it. It correctly turned off autoAssign (verified via city:IsNoAutoAssignSpecialists()) but the specialists count continued to remain stuck at 1 and the infinite loop persisted.
--------------
Another theory was that DoRemoveSpecialistFromBuilding was failing to remove the specialist. It will return out if pkBuildingInfo == NULL, but I don't see how that can happen during an AI turn but not during a human turn.

From CvCitizens.cpp
Code:
void CvCityCitizens::DoRemoveSpecialistFromBuilding(BuildingTypes eBuilding, bool bForced, bool bEliminatePopulation)
{
	CvAssert(eBuilding > -1);
	CvAssert(eBuilding < GC.getNumBuildingInfos());

	CvBuildingEntry* pkBuildingInfo = GC.getBuildingInfo(eBuilding);
	if(pkBuildingInfo == NULL)
	{
		return;
	}
...
normal processing
...

Has anyone else seen behavior like this before? Removing specialists to safely delete a building is such a common thing I expect this is a well trod area.
 
Try sending TASK_NO_AUTO_ASSIGN_SPECIALISTS(true) before the TASK_REMOVE_SPECIALIST and then TASK_NO_AUTO_ASSIGN_SPECIALISTS(false) afterwards as that should stop the attempt to reassign the newly unemployed citizen back into the building
 
That is something I already tried and TASK_REMOVE_SPECIALIST continued to fail to reduce the specialist count in the building. I've edited the original post to more clearly communicate what I've done.

Factors that are probably irrelevant: 1) the AI civilization was Korea. 2) The building the specialist could not be removed from is a building added by a mod (but I have no reason to believe it is malformed).
 
Since BNW it is impossible to change working citizens during AI turn, so it may be that TASK_REMOVE_SPECIALIST is somehow linked with human being currently active (it would explain command working in fireturner).

However, TaskTypes.TASK_NO_AUTO_ASSIGN_SPECIALISTS and DoReallocateCitizens() seem to be working. I would try:
-NO_AUTO_ASSIGN true
-DoReallocateCitizens()
-RemoveBuilding
-NO_AUTO_ASSIGN false
-DoReallocateCitizens()
 
I tried:

cityToRemove:DoTask(TaskTypes.TASK_NO_AUTO_ASSIGN_SPECIALISTS, 0, 0, 1);
cityToRemove:DoReallocateCitizens();

and that did not reduce the specialist count. I'm pretty sure DoReallocateCitizens won't move specialists if NO_AUTO_ASSIGN is true.
-----------
Perhaps a different approach will provide a solution. The reason to remove the specialists before deleting the building is to avoid messing up the citizen data. What happens when a building with specialists is removed is that the city's population doesn't change but the citizens that were specialists are erased and forgotten about. Perhaps there is a way to repair this damage?
 
ChangePopulation(1, true)
ChangePopulation(-1, false)
or
ChangePopulation(-1, false)
ChangePopulation(1, true)
Well, in second case, it is possible to set population to 0 and I never tested it, because first one works fine for me [though It could mess up with mods using SetPopulation event (for example: bonus when first time city reach 10 population would be aquired by the city with 9 population)].
 
I won't be able to investigate changing population as a means to repair the citizen state until later today. I am concern about the impact it will have on the SetPopulation event (since I've used that event in my own mods) but it is less concerning than malformed citizen data.

If there was a change when BNW came out -- with respect to TASK_REMOVE_SPECIALIST during AI turns -- it would explain why the code worked back when I originally wrote it in the pre-G&K days. But this problem seems to imply that there is no safe way to delete buildings with specialists except during the human turn. Given how widely buildings are used in civ modding I would expect this limitation would be well known or its work-around would be.
 
Back
Top Bottom