Creating modifiers for number of a captured cities revolt turns

Joined
Jun 27, 2007
Messages
2,248
Location
Hamilton, Ontario
I plan to add three factors to alter the time a captured city stays in revolt:
-A promotion, for suppressing captured population, which I will use the existing iRevoltProtection field for.
-A field from a civic of the player who lost the city which represents the loyalty of the population to their government
-A field from a civic of the the capturing player which represents how well captured population can integrate into the society.

CvPlayer::acquireCity is where the calculation for the turns a captured city stays in revolt is, but I'm not sure what variables are referring to which player, or if it has the capturing unit in the function. I'm assuming the function is activated on the player acquiring the city, but there are more than one reference to other owners. I think eOldOwner is the one I want to check for. That just leaves the capturing unit. Can someone point out how in this function I can pick out the unit capturing the city?
 
In the case of a stack attack, I am not sure "one" unit can be given the credit. Could you assume that any units belonging to the capturing player, which are in the same plot as the city, were responsible? It would be easy to write code to print out this list, and see what happens after a single unit captures or after a stack captures. I am pretty sure this would work, although I suppose the function might be called before any units are moved in.
 
Stack attack is just a UI convenience. In the underlying game mechanics, each unit in the stack attacks alone until they have all attacked or one unit kills the last defender on the plot. While all units that have MPs left (plus the winner) move to the target plot, I believe you are correct that this happens after the city has changed hands.
 
This
Code:
if (pLoopUnit && pLoopUnit->getTeam() != getTeam())
checks that the owner of a unit isn't the one who is taking the city, but I think that's for units that would already be stationed in the city, like spies so I don't know if when this function runs the attacking units have moved into the tile.
The key part of doing this is to have a specific civ have this ability, which I was going to give through a free promotion, but I could just have it be on the leader trait. Having a promotion that did it was only a "If I do this, I could also do this" idea.
 
CvPlayer::acquireCity() is called from CvUnit::setXY(). If the new plot contains an enemy city and the unit can fight, it captures the city. This is where the WW and War Success is added [I don't like its placement].

Code:
		pNewCity = pNewPlot->getPlotCity();

		if (pNewCity != NULL)
		{
			if (isEnemy(pNewCity->getTeam()) && !canCoexistWithEnemyUnit(pNewCity->getTeam()) && canFight())
			{
				GET_TEAM(getTeam()).changeWarWeariness(pNewCity->getTeam(), *pNewPlot, GC.getDefineINT("WW_CAPTURED_CITY"));
				GET_TEAM(getTeam()).AI_changeWarSuccess(pNewCity->getTeam(), GC.getDefineINT("WAR_SUCCESS_CITY_CAPTURING"));

				PlayerTypes eNewOwner = GET_PLAYER(getOwnerINLINE()).pickConqueredCityOwner(*pNewCity);

				if (NO_PLAYER != eNewOwner)
				{
					[B]GET_PLAYER(eNewOwner).acquireCity(pNewCity, true, false, true); // will delete the pointer[/B]
					pNewCity = NULL;
				}
			}
		}

You could add the unit to the parameter list of acquireCity()--default NULL--since it isn't exported by the DLL. Or you could knock some time off the timer after acquireCity() returns [I don't like this either; it belongs to CvPlayer].
 
So I could add this to CvPlayer::acquireCity
Code:
void CvPlayer::acquireCity(CvCity* pOldCity, bool bConquest, bool bTrade, bool bUpdatePlotGroups, [B]CvUnit* pCapturing[/B])
and add the unit using "this" in this to include the unit activation acquireCity
Code:
GET_PLAYER(eNewOwner).acquireCity(pNewCity, true, false, true, [B]this[/B]); // will delete the pointer
then I can check the unit's promotions. However you say to have it default NULL since it's not always a conquest that activates this. So how does one have it default as NULL?
 
Yes, and you set the default value in the .h file.

Code:
void acquireCity(CvCity* pOldCity, bool bConquest, bool bTrade, bool bUpdatePlotGroups, [B][COLOR="Red"]CvUnit* pCapturing = NULL[/COLOR][/B])
 
I haven't written in the code yet, but I've been thinking about how to put in the AI calculations for the civics. It's hard to determine how much of a disadvantage/advantage these things are for someone. First, they should probably be ignored if there isn't an AI warplan in effect. The best factor I can think of to base how important assimilation time on is the size of your empire. For instance if you had one city and captured a second, having that city stay in revolt for a long time means you're paying increased maintenance from it but getting nothing from it, having half your empire be dead weight. If you have a large empire then it doesn't matter as much.
The loyalty factor is hard to understand, since it's not that much of a disadvantage to you if your city defects as soon as captured, it's lost either way. It's an advantage to your enemy, but how much depends more on them than you. I guess it would be the opposite of the assimilation time. If I assume having a big empire means others are smaller, then easily assimilated cities is an advantage for them. So bigger empires should care more about colony loyalty than small ones.
The way I plan to have this set by a percentage to 100 is normal. One civic will have 0% loyalty so there is no revolt when captured. The assimilation time for civics will range from 20% to 250%.
Now there are a lot of numbers in CvPlayerAI::AI_civicValue so it's hard to determine how to set it up so it would be a factor, but doesn't overshadow other things. So I don't know what do multiply or divide these numbers (100 being the default) by to put them in the right range for that, although ignoring it when not in a warplan will remove some of the danger of possible over emphasis, but I still don't know what base multiplier should be used. Assimilation can probably be divided the number of cities, but loyalty is harder because you can't base it on a specific players number of cities like you can with your own, so it would have to be some combination of factors including your cities with the total cities and number of players.
Can anyone help with what numbers I should be using?
 
Can anyone help with what numbers I should be using?

Large ones. Sorry I can't be more specific. Firaxis liked having civic values well into the hundreds. If you are using Better AI in your mod, with cheat mode, you can use the SHIFT ALT CONTROL keys to see the AI values for your civics, which is incredibly useful when coding the AI.
 
Problem. I can't get the code where your civics alter the revolt time of cities you capture. I can get it to work when the civics of the civ losing the city effect revolt time, but not the civics of the invader.
The getLoyalty function has worked as intended, but I don't know how to use the getCaptureTime function (which is set up identically but will be used differently), specifically I don't know how to replace GET_PLAYER(pOldCity->getOriginalOwner()) with something that will refer to the capturing player rather than the player losing the city. So can someone look into CvPlayer::acquireCity and tell me how it's done?

Code:
//city revolt time M.A.
		iRevoltModUnit = 100;
		for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
		{
			if (pCapturing->isHasPromotion((PromotionTypes)iI))
			{
				if (100 - GC.getPromotionInfo((PromotionTypes)iI).getRevoltProtection()<iRevoltModUnit)
				{
					iRevoltModUnit = 100 - (GC.getPromotionInfo((PromotionTypes)iI).getRevoltProtection());
				}
			}
		}
[COLOR="Red"]		if (GET_PLAYER(pOldCity->getOriginalOwner()).getLoyalty() != 0)
		{
			iRevoltModUnit *= ((100 + (GET_PLAYER(pOldCity->getOriginalOwner()).getLoyalty())) / 100);
		}[/COLOR]
		if (iTeamCulturePercent < GC.getDefineINT("OCCUPATION_CULTURE_PERCENT_THRESHOLD"))
		{
			pNewCity->changeOccupationTimer(((((GC.getDefineINT("BASE_OCCUPATION_TURNS") + ((pNewCity->getPopulation() * GC.getDefineINT("OCCUPATION_TURNS_POPULATION_PERCENT")) / 100)) * (100 - iTeamCulturePercent)) / 100)*iRevoltModUnit) / 100);
		}
//city revolt time M.A. end
 
Lol, sounds like a case of not seeing the forest through the trees. CvPlayer::AquireCity is called for the invading player, so you would be using this->, (and you can drop the this-> and call it directly).

So like this:
Code:
		if (GET_PLAYER(pOldCity->getOriginalOwner()).getLoyalty() != 0)
		{
			iRevoltModUnit *= ((100 + (getLoyalty())) / 100);
		}
 
You know what's weird? I tried it like that and it didn't work. It said it was an invalid use of a "+" sign, or something like that, but now it has worked. :confused:
 
Back to working on the AI, are there functions that count the total cities on the map or count your own cities? I assume there are, but can someone point them out for me?

Also, while using the chipotle code I saw that while testing the taking of cities and holding alt near the city had a number (600) representing some danger level. So it seems there is some function that rates the danger level for a plot. It seems like this could be used to determine if a city is in danger of being captured. So does anyone know if this can be used this way, or if there is another function that looks for cities in danger of capture? This would be useful for determining when city loyalty is important, otherwise it would just be based on warplans.

Lastly, for city capture time it would also only be important if the AI is at war, and on the offensive. The civic value AI does check for warplans, but only if there is one. I know there are different kinds of warplans, but I'm not sure if there are ones that are specific, like offensive or defensive. So, does anyone know if there are warplans like that would could help gauge the likely hood that cities will change hands?
 
Back to working on the AI, are there functions that count the total cities on the map or count your own cities? I assume there are, but can someone point them out for me?

CvPlayer::getNumCities()

Also, while using the chipotle code I saw that while testing the taking of cities and holding alt near the city had a number (600) representing some danger level. So it seems there is some function that rates the danger level for a plot. It seems like this could be used to determine if a city is in danger of being captured. So does anyone know if this can be used this way, or if there is another function that looks for cities in danger of capture? This would be useful for determining when city loyalty is important, otherwise it would just be based on warplans.

CvCityAI::AI_isDanger()

Lastly, for city capture time it would also only be important if the AI is at war, and on the offensive. The civic value AI does check for warplans, but only if there is one. I know there are different kinds of warplans, but I'm not sure if there are ones that are specific, like offensive or defensive. So, does anyone know if there are warplans like that would could help gauge the likely hood that cities will change hands?

CvTeam::getAnyWarPlanCount(True)


Sometimes I think it's scary how I've memorized these.
 
Sometimes I think it's scary how I've memorized these.

[offtopic]
Not so much memorized but understood them over and over again. It had always been the case that whatever I understood over and over from a course stays with me decades after the gritty details had faded away. I may not remember specifics of derivatives and integrals from my Calculus courses but I do understand how they can be applied to a bigger world :D.

Better analogy would be your skills at biking. You may be rusty when you return to it ten years after you leave it. But your mind and body will still "understand" biking skills. And behold the skills rise again from the ashes :eek:! :lol:

So, right now you may seem to memorize these calls but in reality you had understood them to some extent repeatedly so you can easily toss out the functions of SDK :D.
[/offtopic]
 
CvCityAI::AI_isDanger()
Good. Now can anyone point out a part in the code where it loops over all of a players cities so I can copy that? Actually I don't even know how to write it to access the city's AI. It seems like CvCityAI is the only part that uses functions from CvCityAI, so I don't know what it would look like in other places.
CvTeam::getAnyWarPlanCount(True)
I actually already knew about that one. I was hoping there was a specific warplan that was used when the AI is planning to take cities as opposed to when they're just building up forces.
 
CvPlayer::doTurn() probably does this; there are other places. Search for uses of CvPlayer::nextCity().

Given a CvCity* you can cast it to a CvCityAI*:

Code:
CvCity* pLoopCity = ...
[B]CvCityAI* pLoopCityAI = (CvCityAI*) pLoopCity;[/B]
 
I found this in CvTeamAI:
Code:
				int iLoop;
				CvCity* pOurLoopCity;
				
				for (pOurLoopCity = kPlayer.firstCity(&iLoop); pOurLoopCity != NULL; pOurLoopCity = kPlayer.nextCity(&iLoop))
				{
					if (pOurLoopCity->AI_isDanger())
					{
						iOurEndangeredCities++;
					}
				}
Although I have to find what kPlayer should be replaced with, this seems to suit my purposes of counting up endangered cities of determining the value of lost city loyalty.

For capture time I was going to have it's influence decrease with the number of cities, but I've noticed most civics gain value with more cities, so by just leaving it as a flat value while others effects increase with city count then it in effect does decrease relative to everything else.
 
OK someone needs to write me an IF statements to use in CvPlayerAI.cpp that checks if that player's team is at war (it already tests for war plans, but I need one for actually being at war), because I can't find another place that does it in a way that can me used here and I've tried it several different ways without success. Often it compiles but in use it always comes up true.
 
Back
Top Bottom