Specific Bug Reports

There is an undocumented change in CvPlayerAI::AI_calculateTotalBombard(DomainTypes eDomain) circa line 20152. Code was added that gives an extra 50% value to bombard units that ignore building defense.

Original BTS code:

Code:
			if (iBombardRate > 0)
			{
				iTotalBombard += iBombardRate * getUnitClassCount((UnitClassTypes)iI);
			}

BetterAI code:

Code:
				if (iBombardRate > 0)
				{
					if( GC.getUnitInfo(eLoopUnit).isIgnoreBuildingDefense() )
					{
						iBombardRate *= 3;
						iBombardRate /= 2;
					}

					iTotalBombard += iBombardRate * getUnitClassCount((UnitClassTypes)iI);
				}
 
ad City Razing: I believe it was no bug, the AI really is not supposed to use the leaderhead's razeprob on cities that have a closeness > 0. The madness should at least be heavily reduced, that massive razing hurts too much.

(bullai r105)

related: I got an access violation here:
Code:
                 pCity->doTask(TASK_RAZE);
                 logBBAI("    Player %d (%S) decides to to raze city %S!!!", getID(), getCivilizationDescription(0), pCity->getName().GetCString() );
The reason is simple: the city no longer exist when you try to get the CString of its name. Reversing the order fixes that.


Potential enemies are ultimately ignored due to the second conditional; and isVisibleEnemyUnit just checks for visible enemy units (could be non-military), whereas getNumVisibleEnemyDefenders checks for visible enemy military units. The entire first conditional is superfluous.

AI_potentialEnemy takes the players that the AI has warplans for into consideration as enemies. Including the AI_potentialEnemy check essentially means that a unit calling this function could start a war.

AI_leaveAttack is called from the following 4 methods:

  1. AI_collateralMove
  2. AI_reserveMove
  3. AI_cityDefenseMove
  4. AI_cityDefenseExtraMove

It seems to me that a unit that is supposed to be defending a city shouldn't be starting wars, even if such a war is in the AI's plan. So potential defenders should be ignored in at least the last two circumstances.

It is probably appropriate for units with the first two AIs to start wars, but they can start wars in their AI_anyAttack or AI_cityAttack calls. So my vote is to ignore potential enemies altogether in AI_leaveAttack.
Everything you said is correct. Only one comment: reserve and collateral are both defender roles too.
But even if that wasn't so, (pLoopPlot->getNumVisibleEnemyDefenders(this) > 0) makes the other check obsolete and even costs the same.
I also vote for the complete removal of the entire
if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot)))
(functionally identical, less code, (minimally) better performance)


Found another unmarked change in CvUnitAI::AI_specialSeaTransportSpy(). The 02/23/10 efficiency modification needs to have the lower comment moved down so that it contains the entire modification.

Spoiler :
The original code was this:

Code:
				if (iValue > 0)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
					{
						if (generatePath(pLoopPlot, 0, true, &iPathTurns))
						{
							iValue *= 1000;

							iValue /= (iPathTurns + 1);

The current BetterAI code is this:

Code:
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/23/10                                jdog5000      */
/*                                                                                              */
/* Efficiency                                                                                   */
/************************************************************************************************/
				iValue *= 1000;

				if (iValue > iBestValue)
				{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
					{
						if (generatePath(pLoopPlot, 0, true, &iPathTurns))
						{
							iValue /= (iPathTurns + 1);

This line was moved above the conditional:

Code:
iValue *= 1000;

However, the deletion of the original line is unmarked. The comment should be moved down so that the code looks like this:

Code:
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/23/10                                jdog5000      */
/*                                                                                              */
/* Efficiency                                                                                   */
/************************************************************************************************/
				iValue *= 1000;

				if (iValue > iBestValue)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
					{
						if (generatePath(pLoopPlot, 0, true, &iPathTurns))
						{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
That's just a different style. jdog doesn't want to have incomplete code blocks between start and END.
 
Hi guys

First of all: thank you for this incredible mod, it's a must have really.
I don't know if this "bug" has been discussed here before neither if it's really a bug but here it is:
During my last BetterAI game I've signed a pact of defense with mighty Portugal. After a couple of turns Mayas decided to run a war against my lusitanians friends. I've been naturaly involved in this war thus the pact of defense worked well but... as the war was being declared the pact was being removed in the same time!
Is this normal?
 
Yes, the pact means that should either partner be attacked, the other will DoW the attacker. Any DoW by either partner on any player automatically dissolves the pact. Your retaliatory DoW--necessitated by the pact itself--caused the pact to be canceled.
 
If you want to keep your Defensive Pacts you can edit BBAI_Game_Options_GlobalDefines.xml: set BBAI_DEFENSIVE_PACT_BEHAVIOR to 1.
 
Thank you for your reponses guys!
So you think PoD should break itself automatically in case of one or other civ involved in the pact declaring a war to another civ (I suppose this is what you call "DoW")?
Thus it has been a specific change made in Better AI mod?

Anyway my guess is that if you think it's not a bug and it's better to have it this way... so do I!;)
 
The normal game without BetterAI breaks defensive pacts when either member makes an aggressive move, a declaration of war (DoW). This is not a bug, nor is it changed by BetterAI normally.

BetterAI does add an option to allow a defensive pact to remain in place when a member DoWs in response to the other member being attacked, and I think there's a third option to allow DPs to survive even preemptive strikes.
 
targetSize calculation for cities is a bit broken.

original:
Code:
	int iHealth = goodHealth() - badHealth();
	int iTargetSize = std::min(iGoodTileCount, getPopulation()+(happyLevel()-unhappyLevel()));
	iTargetSize = std::min(iTargetSize, 1 + getPopulation() + iHealth);

Better AI:
Code:
	int iHealth = goodHealth() - badHealth();
[COLOR="Green"]/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/30/09                                jdog5000      */
/*                                                                                              */
/* City AI                                                                                      */
/************************************************************************************************/[/COLOR]
	int iTargetSize = iGoodTileCount;

	if( getEspionageHealthCounter() > 0 )
	{
		iTargetSize = std::min(iTargetSize, 2+ getPopulation());
	}
	else
	{
		iTargetSize = std::min(iTargetSize, 2 + getPopulation() + (iHealth)/2);
	}

	if( iTargetSize < getPopulation() )
	{
		iTargetSize = std::max(iTargetSize, getPopulation() - (AI_countWorkedPoorTiles()/2));
	}
	
	[COLOR="Green"]// Target city size should not be perturbed by espionage, other short term effects[/COLOR]
	if( getEspionageHappinessCounter() > 0 )
	{
		iTargetSize = std::min(iTargetSize, getPopulation());
	}
	else
	{
		iTargetSize = std::min(iTargetSize, getPopulation()+(happyLevel()-unhappyLevel()));
	}
[COLOR="Green"]/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/[/COLOR]

What I think is right:
Code:
	int iHealth = goodHealth() - badHealth();
[COLOR="Green"]/********************************************************************************/
/*	Better Evaluation							09.03.2010		Fuyu		    */
/********************************************************************************/[/COLOR]
	[COLOR="Gray"]int iHappyAdjust = 0;[/COLOR] [COLOR="Green"]// <-Don't redefine these variables where are already defined.[/COLOR]
	[COLOR="Gray"]int iHealthAdjust = 0;[/COLOR] [COLOR="Green"]// <-Don't redefine these variables where are already defined.[/COLOR]
	if (getProductionBuilding() != NO_BUILDING)
	{
		iHappyAdjust += getAdditionalHappinessByBuilding(getProductionBuilding());
		iHealthAdjust += getAdditionalHealthByBuilding(getProductionBuilding());
	}
[COLOR="Green"]/********************************************************************************/
/*	BE	END																		*/
/********************************************************************************/
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/02/10                         jdog5000 & Fuyu      */
/*                                                                                              */
/* City AI                                                                                      */
/************************************************************************************************/[/COLOR]
	int iTargetSize = iGoodTileCount;

	[COLOR="Green"][s]//iTargetSize = std::min(iTargetSize, 2 + getPopulation() + goodHealth() - badHealth() + getEspionageHealthCounter() + std::max(0, iHealthAdjust));[/s][/COLOR]
	iTargetSize -= std::max(0, (iTargetSize - (1 + getPopulation() + goodHealth() - badHealth() + getEspionageHealthCounter() + std::max(0, iHealthAdjust))) / 2);
	
	if( iTargetSize < getPopulation() )
	{
		iTargetSize = std::max(iTargetSize, getPopulation() - (AI_countWorkedPoorTiles()/2));
	}
	
	[COLOR="Green"]// Target city size should not be perturbed by espionage, other short term effects[/COLOR]
	iTargetSize = std::min(iTargetSize, getPopulation() + (happyLevel() - unhappyLevel() + getEspionageHappinessCounter() + std::max(0, iHappyAdjust)));
[COLOR="Green"]/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/[/COLOR]

Once again it was Afforess how noticed that the AI isn't focusing enough on city growth, I believe that might have been one reason.
 
Is anyone collecting these issues and updating BBAI?
 
I am collecting everything and updating Better BUG AI, which will supersede replace Better BTS AI for a while at least if no one else picks up Better BTS AI, now that jdog left with very little intentions to come back won't be available again anytime soon.
 
Fuyu, there is a function that computes the target city size (called from CvGameTextMgr), so it would be nice to update that function, and call it instead of repeating the same code in 3 places in CvCityAI.
 
Yes I noticed and replaced one of these occurances. For updateBestPlotBuild I left it was it is though, since this function goes to greater length to calculate H/Hadjust values than the standard AI_getTargetSize().
 
I am collecting everything and updating Better BUG AI, which will supersede Better BTS AI if n one else picks up Better BTS AI, now that jdog left with very little intentions to come back.

Wow, really? I am out of town this weekend and it's sad to hear this? Is this a Civ5 things or a "i'm done with kidding thing?
 
Wow, really? I am out of town this weekend and it's sad to hear this? Is this a Civ5 things or a "i'm done with kidding thing?
It's neither - it's Real Life (TM) eating his free time; see here.

Cheers, LT.
 
I might have missed/ignored the "this fall" part but the rest of his post was so formal it just sounded like a resignation letter. But I hope I'm wrong and that he'll be back in winter.
 
I also probably won't have a computer capable of running 5 well for at least six months.

Someone really should continue his work in the meanwhile.
 
There are some really stupid war decisions in the current version, especially within the first rounds. I've seen the AI "rushing" with 2 archers and failing. The AI should have at least X power before any war get declared against anyone.

Can someone take a look at it?
 
There are some really stupid war decisions in the current version, especially within the first rounds. I've seen the AI "rushing" with 2 archers and failing. The AI should have at least X power before any war get declared against anyone.

Can someone take a look at it?

I agree. The AI seemed to try to start a war wayyy too early. I added some code to block it. Feel free to nitpick it:

Code:
void CvTeamAI::AI_doWar()
{
...
	// if no war plans, consider starting one!
	if (getAnyWarPlanCount(true) == 0 || iEnemyPowerPercent < 45)
	{
		bool bAggressive = GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI);
/************************************************************************************************/
/* Afforess	                  Start		 07/27/10                                               */
/*                                                                                              */
/* Avoid War when there is plenty of room left                                                  */
/************************************************************************************************/
		if (GET_PLAYER(getLeaderID()).getCurrentEra() < GC.getNumEraInfos() / 2)
		{
			if (GET_PLAYER(getLeaderID()).getNumCities() < GC.getMapINLINE().getWorldSize() + 1)
			{
				return;
			}
			CvCity* pCapital = GET_PLAYER(getLeaderID()).getCapitalCity();
			//bool bEarlyGame = (100 * GC.getGameINLINE().getElapsedGameTurns()) / std::max(1, GC.getGameINLINE().getEstimateEndTurn()) < 20;
			int iAverage = GC.getMapINLINE().getGridWidthINLINE() + GC.getMapINLINE().getGridHeightINLINE() / 2;
			bool bPrimaryArea = true;
			if (pCapital != NULL)
				bPrimaryArea = AI_isPrimaryArea(pCapital->area());
			int iThreshold = bAggressive ? 40 : 30;
			if (pCapital != NULL)
			{
				if (GC.getMapINLINE().percentUnoccupiedLand(true, true, true, bPrimaryArea ? pCapital->area() : NULL, /*bEarlyGame ?  */iAverage / 5/* : -1*/, bPrimaryArea ? pCapital->plot() : NULL) > iThreshold)
				{
					return;
				}
			}
		}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/		
		int iFinancialTroubleCount = 0;
		int iDaggerCount = 0;
...
}
Which requires a new function in CvMap:

Code:
/************************************************************************************************/
/* Afforess	                  Start		 07/27/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
int CvMap::percentUnoccupiedLand(bool bExcludeWater, bool bIncludeBarbarian, bool bExcludePeaks, CvArea* pArea, int iRange, CvPlot* pRangeFromPlot)
{
	int iNumTiles = 0;
	int iNumTilesValid = 0;
	for (int iI = 0; iI < numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = plotByIndexINLINE(iI);
		if (!pLoopPlot->isWater() || !bExcludeWater)
		{
			if (pArea == NULL || pLoopPlot->area() == pArea)
			{
				if (!pLoopPlot->isPeak() || !bExcludePeaks)
				{
					if ((iRange == -1 || pRangeFromPlot == NULL) || (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pRangeFromPlot->getX_INLINE(), pRangeFromPlot->getY_INLINE()) <= iRange))
					{
						iNumTiles++;
						if (pLoopPlot->getOwnerINLINE() == NO_PLAYER || (bIncludeBarbarian && pLoopPlot->getOwnerINLINE() == BARBARIAN_PLAYER))
						{
							iNumTilesValid++;
						}
					}
				}
			}
		}
	}
	if (iNumTiles > 0)
	{
		GC.getGame().logMsg("%d Tiles were in %d Range, out of %d total in range tiles", iNumTilesValid, iRange, iNumTiles);
		return (iNumTilesValid * 100) / iNumTiles;
	}
	return 0;
}		
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/


CvMap.h

Code:
/************************************************************************************************/
/* Afforess	                  Start		 07/27/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	int percentUnoccupiedLand(bool bExcludeWater = true, bool bIncludeBarbarian = false, bool bExcludePeaks = true, CvArea* pArea = NULL, int iRange = -1, CvPlot* pRangeFromPlot = NULL);
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
 
Thanks, here is another code that differs from AND:

(cvteam.cpp)

PHP:
DenialTypes CvTeamAI::AI_embassyTrade(TeamTypes eTeam) const
...
if (eAttitude <= GC.getLeaderHeadInfo(kLoopPlayer.getPersonalityType()).getOpenBordersRefuseAttitudeThreshold())


AD:

PHP:
DenialTypes CvTeamAI::AI_embassyTrade(TeamTypes eTeam) const
...
if (eAttitude <= GC.getLeaderHeadInfo(kLoopPlayer.getPersonalityType()).getEmbassyRefuseAttitudeThreshold())
 
Back
Top Bottom