Report Questionable Behavior

AI refuses to take empty cities.

I can confirm this behaviour since version 1.0. Unfortunately it's while playing Planetfall, so a save probably is of no use to you.

If I move the sole defender out of a city threatened by five enemy units, the enemy moves towards another city instead. If I leave the defender where it is, the enemy attacks and conquers the city...

I have a debug DLL, so I can have a look myself into the possible problem. Though of course some hints can always help speed things up: do you know what code should normally allow the AI to capture empty cities? The enemy stack is led by a UNITAI_ATTACK_CITY unit;
 
Looks still like the AI is razing to many cities (BBAI 1.01f) ... nearly 50% get razed, no matter which leaderhead is active.

For example this city got razed (size was ~5 maybe):





Edit: No logging active.
 
Possible AI problem: Moving workers and/or ships into doomed cities unnecessarily

I had two situations now where the AI moved workers or empty ships into cities that were clearly doomed. Example: The AI has two cities left on the mainland. I'm attacking the AI capital. After the attack, the capital is defended by one heavily wounded Longbowman, whereas I have several strong attackers ready for the next turn. So the city is clearly doomed. Nevertheless the AI, in its turn, moves several workers from somewhere near the second AI city into the doomed capital, where I capture them in the next turn.
Should the AI recognise doomed cities and try to evacuate units that can't defend?
 
Sometimes you can observe that the AI will change away from police state (and switch to univeral suffrage) and not change fast enough back even with 35+:mad: caused by war (-> city population decreases).
 
I guess the AI could still spend money better on universal suffrage:Thats nearly 50 modern armors within one round... or even more, dunno.
Universal Suffrage seems not to have anythng to do with it.
Do you know what gamespeed that was? I think there is a bug in CvPlayerAI::AI_goldTarget() : Right now, +2 turns on normal speed equal +1 gold for goldTarget. 2 turns on normal are equivalent to 6 turns on marathon, and should add +3 gold for goldTarget (which would make perfect sense since everything is 3 times as expensive), but it gets multiplied with the multiplier too so you get +9.
My fix:
Code:
		int iMultiplier = 0;
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getResearchPercent();
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
		iMultiplier /= 3;

		iGold += ((getNumCities() * 3) + (getTotalPopulation() / 3));

[COLOR="Green"]/************************************************************************************************/
/* UNOFFICIAL_PATCH                       07/16/10                                Fuyu          */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* original bts code
		iGold += (GC.getGameINLINE().getElapsedGameTurns() / 2);

		iGold *= iMultiplier;
		iGold /= 100;
*/[/COLOR]
[B]		iGold *= iMultiplier;
		iGold /= 100;

		iGold += ( (iMultiplier * GC.getGameINLINE().getElapsedGameTurns()) / (2 * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getVictoryDelayPercent()) );[/B]
[COLOR="Green"]/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/[/COLOR]

But that shouldn't matter all that much. There are other factors, namely:
  1. wars/warplans: if there are any that gives +50%
  2. AI_avoidScience(): +900% (combined with war/warplan: +1400%)
  3. AI_goldToUpgradeAllUnits(): plus half the gold needed to upgrade every single unit in the empire, and plus the other half if there are warplans/wars.

Code:
		bool bAnyWar = GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0;
		if (bAnyWar)
		{
			iGold *= 3;
			iGold /= 2;
		}

		if (AI_avoidScience())
		{
			iGold *= 10;
		}

		iGold += (AI_goldToUpgradeAllUnits() / (bAnyWar ? 1 : 2));
Corporation spread cost should rarely matter much, and AI_getExtraGoldTarget() will always return 0 unless you did something to it yourself (it's not touched by stock BTS or Better AI).
So the most likely culprits are AI_avoidScience() and unit upgrade costs.

well, in the makefile? not active atm, therefore: dunno
(...)
You should really enable logging. It's just a /DLOG_AI cflag.
 
I think universal suffrage has something to do with cause the gold will not decrease every round that much -> AI is not buying enough units/buildings...

is there any code that the AI will only hurry with US if production of that unit/building is already above X%?
 
The AI is not supposed to gold-rush that much, your problem was that it saves up that much gold in the first place (or so I thought?) - which is not related to US.
Rush decisions are made in CvCityAI::AI_doHurry(). Units should be rushed if there's no financial trouble, and the player has 12 times the hurry cost, and if there are more then iMinturns productionTurns left.

Sometimes you can observe that the AI will change away from police state (and switch to univeral suffrage) and not change fast enough back even with 35+:mad: caused by war (-> city population decreases).
What is not fast enough? On normal, you can only change civics once every 5 turns iirc.
I did find a bug introduced by the unofficial patch that can cause an underestimation of the value of police state when it is already the chosen civic but even if that is what's happening, I can't tell you why the AI wouldn't change back as soon as possible.
 
your problem was that it saves up that much gold in the first place

right, as you can see on the screenshot, the AI is researching with 50% instead of 100%.

but also: if the AI was already researching with 100%, how to spend the gold then? it should buy more units in this case...



What is not fast enough?

well, it should never switch away from police state with 35:mad: by war - if possible, since the AI should have no knowledge about the :mad: without police state when under police state right?

we need something like: "if X :mad: by war even with police state, do not switch." reason: when the cities have for example 10:mad: by war while under police state - it should be 10 * Y :mad: without police state.

I did find a bug introduced by the unofficial patch that can cause an underestimation of the value of police state when it is already the chosen civic but even if that is what's happening, I can't tell you why the AI wouldn't change back as soon as possible.

is it already fixed? I have UP 1.60 (by BBAI) in my mod.
 
But does the AI need more units or have something else to rush? When you get more units, you have to pay more from the upkeep. So I would think, if the AI doesn't have like buildings to hurry, that the problem might lie in the saving value. Spending 50% to gold when you have already that much isn't the first idea I would have.
 
right, as you can see on the screenshot, the AI is researching with 50% instead of 100%.

but also: if the AI was already researching with 100%, how to spend the gold then? it should buy more units in this case...
All I can say is I couldn't find anything wrong there. Will have to observe some AIs to see if that gold hoarding happens too often and with no purpose.

well, it should never switch away from police state with 35:mad: by war - if possible, since the AI should have no knowledge about the :mad: without police state when under police state right?.
Wrong, the AI knows/should know exactly what happens when it switches, the methods of evaluation just aren't very exact, and because of some UP change, even wrong.

is it already fixed? I have UP 1.60 (by BBAI) in my mod.
lol how could it already be fixed, I just found it while I was looking for a possible reason of the behavior you reported.
Note that the problem exists in many cases, this is merely one of them
Code:
	if (kCivic.getWarWearinessModifier() != 0)
	{
		int iAngerPercent = getWarWearinessPercentAnger();
		int iPopulation = 3 + (getTotalPopulation() / std::max(1, getNumCities()));

		int iTempValue = (-kCivic.getWarWearinessModifier() * iAngerPercent * iPopulation) / (GC.getPERCENT_ANGER_DIVISOR() * 100);
		if (iTempValue != 0)
		{
[COLOR="Green"]/************************************************************************************************/
/* UNOFFICIAL_PATCH                       10/21/09                                jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* orginal bts code
			iValue += (11 * getNumCities() * AI_getHappinessWeight(isCivic(eCivic) ? -iTempValue : iTempValue, 1)) / 100;
*/[/COLOR]
[COLOR="Red"]/* jdog's UP code
			iValue += (11 * getNumCities() * AI_getHappinessWeight(iTempValue, 1)) / 100;
*/[/COLOR]
[B][COLOR="Green"]// correct code[/COLOR]
			iValue += (11 * getNumCities() * (isCivic(eCivic)? -AI_getHappinessWeight(-iTempValue, 1) : AI_getHappinessWeight(iTempValue, 1))) / 100;[/B]
[COLOR="Green"]/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/[/COLOR]
		}
	}
However even with that "correct" code not everything works as it should. As soon as both the current an another (non-current) civic in a cathegory both increase happiness in some way, the non-currect civic will get underestimated, ie a change from Representation to Police State, or vice-versa, gets highly unlikely. Not sure how to correct that ..
 
Gold hoarding was one of the first things I modded for the AI, because the logic is totally brainless in BTS.

BTS function
Code:
int CvPlayerAI::AI_goldTarget() const
{
	int iGold = 0;

	if (GC.getGameINLINE().getElapsedGameTurns() >= 40)
	{
		int iMultiplier = 0;
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getResearchPercent();
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
		iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
		iMultiplier /= 3;

		iGold += ((getNumCities() * 3) + (getTotalPopulation() / 3));

		[COLOR="Red"]iGold += (GC.getGameINLINE().getElapsedGameTurns() / 2);[/COLOR]

		iGold *= iMultiplier;
		iGold /= 100;
		
		bool bAnyWar = GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0;
		if (bAnyWar)
		{
			iGold *= 3;
			iGold /= 2;
		}

		if (AI_avoidScience())
		{
			iGold *= 10;
		}

		iGold += (AI_goldToUpgradeAllUnits() / (bAnyWar ? 1 : 2));

		CorporationTypes eActiveCorporation = NO_CORPORATION;
		for (int iI = 0; iI < GC.getNumCorporationInfos(); iI++)
		{
			if (getHasCorporationCount((CorporationTypes)iI) > 0)
			{
				eActiveCorporation = (CorporationTypes)iI;
				break;
			}
		}
		if (eActiveCorporation != NO_CORPORATION)
		{
			int iSpreadCost = std::max(0, GC.getCorporationInfo(eActiveCorporation).getSpreadCost() * (100 + calculateInflationRate()));
			iSpreadCost /= 50;
			iGold += iSpreadCost;
		}
	}

	return iGold + AI_getExtraGoldTarget();

There are a couple WTF's right off:

First off, gold target is a factor of elapsed turns. Not exactly smart. Second, it doesn't scale for inflation. Oops. Third, gold is useless if there is no tech trading, and less useful if no tech brokering, but this doesn't take that into account.

Here's my function:

Code:
/************************************************************************************************/
/* Afforess	                  Start		 02/01/10                                               */
/*                                                                                              */
/*  This function has been re-written                                                           */
/************************************************************************************************/
int CvPlayerAI::AI_goldTarget() const
{
	int iGold = 0;

	int iMultiplier = 0;
	iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getResearchPercent();
	iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
	iMultiplier += GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
	iMultiplier /= 3;

	iGold += ((getNumCities() * 3) + (getTotalPopulation() / 3));

	iGold += (GC.getGameINLINE().getElapsedGameTurns() / 8);
	
	iGold *= (100 + calculateInflationRate());
	iGold /= 100;

	iGold *= iMultiplier;
	iGold /= 100;
	
	bool bAnyWar = GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0;
	if (bAnyWar)
	{
		iGold *= 3;
		iGold /= 2;
	}

// Don't bother saving gold if we can't trade it for anything
	if (!GET_TEAM(getTeam()).isGoldTrading() || !(GET_TEAM(getTeam()).isTechTrading()) || (GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_TRADING)))
	{
		iGold /= 3;
	}

	if (AI_avoidScience())
	{
		iGold *= 10;
	}

	iGold += (AI_goldToUpgradeAllUnits() / (bAnyWar ? 1 : 2));

	CorporationTypes eActiveCorporation = NO_CORPORATION;
	for (int iI = 0; iI < GC.getNumCorporationInfos(); iI++)
	{
		if (getHasCorporationCount((CorporationTypes)iI) > 0)
		{
			eActiveCorporation = (CorporationTypes)iI;
			break;
		}
	}
	if (eActiveCorporation != NO_CORPORATION)
	{
		int iSpreadCost = std::max(0, GC.getCorporationInfo(eActiveCorporation).getSpreadCost() * (100 + calculateInflationRate()));
		iSpreadCost /= 50;
		iGold += iSpreadCost;
	}

	return iGold + AI_getExtraGoldTarget();
}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/

I left gold to be a factor of time, but significantly reduced it's effect. I've been using this code for months now, and ,I don't get complaints about stupid AI hoarding anymore.
 
Random events? They seem to scale in cost roughly by elapsed turns / 2.

Random event's are not worth the money the majority of the time. Plus, if that is your reasoning, shouldn't it check to see if random events are disabled? ;)

Anyway, scaling for inflation should increase the amount plenty, without resorting to illogical additions.
 
Random event's are not worth the money the majority of the time. Plus, if that is your reasoning, shouldn't it check to see if random events are disabled? ;)

Anyway, scaling for inflation should increase the amount plenty, without resorting to illogical additions.
The central bank event alone is a very valid reason to store 1k g :p But yes, the code is far from elegant, functional and effective ;)
 
The central bank event alone is a very valid reason to store 1k g

Counting on random events to win you the game is very poor strategy though. I doubt the AI should really need to worry about that.
 
Inflation event != win ;) I just gave a event related reason for making the AI consider holding 1k in the bank, since you said that most of them were not useful enough ( true ).

But yes, the AI needs to learn other tricks before this one :p
 
Inflation event != win ;) I just gave a event related reason for making the AI consider holding 1k in the bank, since you said that most of them were not useful enough ( true ).

Most of them aren't useful enough. I didn't say all, did I?

Anyway, the Federal Reserve event isn't even set to occur in all games, if you look at the XML:
Code:
	<iPercentGamesActive>90</iPercentGamesActive>

And if the real reason for making the AI hoard gold is for events, it should have a gameoption check. I don't think it's even remotely smart to have the AI hoard gold at the expense of it's research.
 
All true. I guess we are discussing peanuts here ;) The code as it comes of the box is bad and any improvement would be welcome :D But you are certainly pushing the bar when you said that gold hoarding was useless besides tech trades. There is corp spread monies, events, upgrades and $rush beyond that ( and probably some more that I am not remembering now ), so even your code needs some refinement ( since it has no bias towards saving cash in case of being able to $rush, as it IMHO should have ;) )
 
Most of them aren't useful enough. I didn't say all, did I?

Anyway, the Federal Reserve event isn't even set to occur in all games, if you look at the XML:

The events are generally more useful, and they are all set to be enabled in all games, in my mod... Just mentioning that. ;)

I've added a modified version of Afforess' function to my code (that does in fact check for the No Events game option btw), so I wanted to say thanks for posting that, and for the whole discussion in general since I'd never thought to look at this issue before. *hugs*
 
I did find a bug introduced by the unofficial patch that can cause an underestimation of the value of police state when it is already the chosen civic but even if that is what's happening, I can't tell you why the AI wouldn't change back as soon as possible.

When I've gone out on a limb and made a claim about something I've been proven partially or completely wrong several times lately, and I hate being wrong so this sucks... Nevertheless :p, I'm going to go out on a limb here and say I don't believe your proposed changes to AI_civicValue() are correct Fuyu, and JDog's lines should be left as-is. The way this system works is the AI computes the total value of the civic they are on, and the total value of a proposed alternative civic, completely seperately, and then compares them. Civic value should be analyzed in a vacuum so to speak, and have nothing to do with whether they are currently active or not.

That being said, I believe what you are seeing is a result of the following in CvPlayerAI::AI_doCivics():

Code:
	// Threshold to make AI hold off on civics changes, threshold is percentage to add to
	// value of current civics
	int iThreshold = 7;

	if( (getAnarchyTurns() > 0) && !isGoldenAge() )
	{
		iThreshold += 13;
	}

	int iCurValue;
	int iBestValue;
	for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
	{
		paeBestCivic[iI] = AI_bestCivic((CivicOptionTypes)iI, &iBestValue);
		iCurValue = AI_civicValue( getCivics((CivicOptionTypes)iI) );
		
		iCurValue += (iCurValue * iThreshold) / 100;

		if ( paeBestCivic[iI] == NO_CIVIC || iBestValue < iCurValue )
		{
			paeBestCivic[iI] = getCivics((CivicOptionTypes)iI);
			iBestValue = iCurValue;
		}

		iCurCivicsValue += iCurValue;
		iBestCivicsValue += iBestValue;
	}

This effectively means a new civic must exceed the computed value of the existing/current one by either 7 or 20% in order to justify a switch, depending on whether the Spiritual trait, a Golden Age, etc are present. However I'm not sure the base requirement of +7% is necessary, and you might be able to set that to zero... In addition, the iCurCivicsValue and iBestCivicsValue variables in this function are incremented in the loop so there's no compiler warning about unused variables, however they aren't actually used for anything so they should be removed.
 
Top Bottom