Unofficial BTS 3.13 patch

@ Thronsen, those posters are basically talking about bad Mojo.
And the inexplicable thing, that sometimes a complete wipe of the game and reinstall will fix things on the MultiPlayer compatibility front, for apparently no reason.

All Bhuric's patch does is replace a DLL file + a python file (if you choose the addenum that re-enables a screen). Thus its really not necessary to reinstall to add this in: unless you are experiencing problems, then you might fall into the bad mojo category :-)
 
On a side note, even for 3.13 without Bhuiric's patch you sometimes needed to do a clean install to un-frump multiplayer.

3.13 was not exactly the cleanest patch ever. It leaves some binary cache's behind that are unpatched. The safest thing to do is a clean install including deleting the directory tree.
 
Does anybody have a version of this Bhruic Patch v1.21 that ALSO includes the ability to play with 40 civs?

I have a modified Bhruic Patch v1.11 that allows 40-civs, but not the new version Bhruic released.
I noticed no reply as of yet to Wolfshanze's question. I'm also am looking for this.
If what I have read in a few other threads is correct. Then you cannot create a colony if you play a Huge map w/ 18 Civs :/
 
Wolfshanze found one or reverse-engineered one. You can get the dll from his mod's forum, just look at the first post and scroll down.

Wodan
 
(EDIT: Turns out I was misreading the code, but Yakk found a very much related bug just a few posts down ...)

Alright, I think I found another potential bug which might have a bit more impact than the last one ...

In CvTeamAI::AI_startWarVal, one of the factors considered is "closeness":

Code:
	int iClosenessValue = AI_teamCloseness(eTeam);
	if (iClosenessValue == 0)
	{
		iValue /= 4;
	}
	iValue += iClosenessValue / 4;

The declaration of AI_teamCloseness reads:

Code:
	int AI_teamCloseness(TeamTypes eIndex, [B]int iMaxDistance = -1[/B]) const;

Looking at the definition, right at the beginning it has:

Code:
	if (iMaxDistance == -1)
	{
		iMaxDistance = DEFAULT_PLAYER_CLOSENESS;
	}

Since iMaxDistance is not specified in AI_startWarVal it is set to -1 and no matter the actual physical proximity of the teams will always return the same value. Since war decisions are made partly by comparing values from AI_startWarVal and the closeness value is always the same (6 to be precise) no matter what, that section of AI_startWarVal does nothing. Clearly that is not the intended behavior, but what is?

Here's my proposal: AI_teamCloseness basically just calls CvPlayerAI::AI_playerCloseness for all players on the team, which in turn calls CvCityAI::AI_playerCloseness for each of the player's cities. The default value for iMaxDistance for CvCityAI is 7 and this value is used in many other places as well. The one other value I found is 5 + iCurrentEra which is only used to determine whether to run AI_STRATEGY_PEACE (which in turn has no effect ...). The other clue is that in debug mode when closeness values are shown for player and team they are for iMaxDistance = 7.

So, I think that the code in CvTeamAI::AI_startWarVal should be:

Code:
	int iClosenessValue = AI_teamCloseness(eTeam, [B]7[/B]);
	if (iClosenessValue == 0)
	{
		iValue /= 4;
	}
	iValue += iClosenessValue / 4;

That said, this will make AI_startWarVal take a fair bit longer and it will have a significant effect on AI war declarations. I don't think the time is a big deal as the function isn't called that often (most of the time when it's called the AI will declare war on someone). The effect on war choices is a bit more of a question mark though but the good news is that debug mode will show you which teams are considered close and with what values for iMaxDistance = 7 already.

The only other significant place AI_teamCloseness is used is in choosing when to use AI_STRATEGY_CRUSH where:

Code:
						if (GET_TEAM(getTeam()).AI_teamCloseness((TeamTypes)iI) > 0)
						{
							iWarCount++;
						}

is again somewhat pointless since it will always be 6 and > 0 ... I'm not sure how often this runs and whether it is really worth changing or not. From what I understand AI_STRATEGY_CRUSH involves basically rushing with everything but a bare-bones defense which wouldn't make much sense if the enemy was really far away. Maybe instead things could be reordered so the check for real wars only happened if iCrushValue was high enough?

Thoughts?
 
I'm not sure this has been posted yet but in a recent ALC game here

http://forums.civfanatics.com/showthread.php?p=6901593&page=44#865

The Ai built the University of Sankore Wonder (did I spell that right? *shrugs*) but none of it's cities had any religons therefore it was obviously NOT running a state religon, this was one of those games where 1 of the AI on another continent was hogging all the religions.

Sounds like a bug to me...
 
I'm not sure this has been posted yet but in a recent ALC game here

http://forums.civfanatics.com/showthread.php?p=6901593&page=44#865

The Ai built the University of Sankore Wonder (did I spell that right? *shrugs*) but none of it's cities had any religons therefore it was obviously NOT running a state religon, this was one of those games where 1 of the AI on another continent was hogging all the religions.

Sounds like a bug to me...

Not to me. If Mansa Musa has religions and I'm running Free Religion, I'll still build Sankore and Spiral Minaret just to deny them to him.
 
Alright, I think I found another potential bug which might have a bit more impact than the last one ...
[...snip...]

So I wasn't delusional when I said that the AI doesn't seem to be attacking its direct neighbors any more than someone far away.

And the fanbois all told me I was an idiot.
 
Not to me. If Mansa Musa has religions and I'm running Free Religion, I'll still build Sankore and Spiral Minaret just to deny them to him.

I don't think the AI was programed to build wonders for denial purposes (I could be wrong though) besides I reckon he could've used those hammers for something more beneficial... like an army...
 
So I wasn't delusional when I said that the AI doesn't seem to be attacking its direct neighbors any more than someone far away.

And the fanbois all told me I was an idiot.

There's still a factor for proximity of capitals which has been in there since the beginning. This new "closeness" measure was added for BTS and I'm pretty sure one of the advertised BTS changes was that the AI will pick closer wars more often ... the closeness effect on war choices (if implemented as I believe it was intended) would have a much larger impact than the old capital proximity code (which is also still there).
 
jdogg, your description seems wrongish.

Team closeness is the sum of player closeness.

Player closeness is the sum of city closeness.

City closeness is the max over city-to-city closeness, plus 1/4 the sum over city-to-city closeness.

City-to-city closeness is 0 if they are further than max distance, and
[20+CitySize]*[(Distance under max+1)/(max+1)]*[small island reducer]*[barbarian reducer]
otherwise

Now, there is a bug! Looking at the call stack, at the AI_playerCloseness level:
Code:
for (pLoopCity = GET_PLAYER(eIndex).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(eIndex).nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}
That is summing the closeness metric between the civ eIndex ... and the civ eIndex!

Fix:
Code:
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}
Which now iterates over the cities of _this_ player, and finds out if they are close to the other player.

The iMaxDistance parameter just ends up acting as a "cut off" on the city-to-city closeness measure. It isn't a bug -- saying that "cities further than 6 away aren't close" is all it says.

You could also reduce this, and loop over the cities of the other player, and add up their "closeness" to this player. The difference will be on the formula:
[20+CitySize]*[(Distance under max+1)/(max+1)]*[small island reducer]*[barbarian reducer]
should we consider someone's closeness more if their city is large, or more if our city is large?

If we value the size of their city more than ours, then a "beachhead" invasion will encourage more warfare with that civilization. If we value our city size, we will tend to attack cities that are near our big cities rather than large cities that are near our cities, if that makes sense. :)
 
jdogg, your description seems wrongish ...

Yeah, you're totally right ... for some reason in my mind AI_teamCloseness was returning DEFAULT_PLAYER_CLOSENESS when iMaxDistance was -1 :crazyeye: I'll blame the name DEFAULT_PLAYER_CLOSENESS ...

Anyway, I think you may be on to something with the possible switch of city players but given my recent confusion I'll take a closer look at the code first.
 
Well done Yakk, I'm convinced you really did find an important bug! The code was certainly suspect so I created a second version of CvPlayer::AI_playerCloseness as you described and checked it out in game using debug mode.

The English are a one-city civ on an island off the coast of the Indian empire. When querying their closeness (hold down CTRL while hovering over their land in debug mode) here's what I got:



The numbers mean:

Closeness:
Gandhi(iMaxDistance used) : CvCity::AI_playerCloseness (CvPlayer::AI_playerCloseness, CvPlayer::AI_playerCloseness2, CvTeam::AI_teamCloseness)

where CvPlayer::AI_playerCloseness is the one that seems to be bugged and CvPlayer::AI_playerCloseness2 is the fixed version as Yakk described.

The CvCity::AI_playerCloseness measure gives the closeness for London to Ghandi as 22, the CvPlayer and CvTeam versions should just be the sum of the city values for England and their team (which is only them in this case). This is what the fixed version CvPlayer::AI_playerCloseness2 does, while the Firaxis version really seems to give Ghandi's closeness to himself (his closeness to England is 3, three cities having a closeness value of 1). When I check the closess value for Mansa Musa's city to Ghandi, CvPlayer::AI_playerCloseness again returns 242 ... the sum of Ghandi's closeness to himself, not the sum for Mansa Musa's cities to Ghandi.

Definitely a bug!
 
Ok, so that leaves the question -- which way should we sum?

Ie, which is "more close":
A> Any size Loyal city next to Large Enemy city.
or
B> Large Loyal city next to any size Enemy city.
or:
C> Factor in both this city and that city size in our city-to-city closeness.

(A) means that if we have a small colony right next to the heart of the enemy empire, we will consider that empire to be close. Ie, it is "looking for targets" -- large numbers of ripe large enemy cities that are near our territory.

(B) means that we consider a small enemy city near the heart of our empire to be a key target. Ie, it is "round out the empire" -- take out targets that are close to the "empire heart".

(C) would be changing the code more, and would require lots of work, probably, and be riskier.

(A): (Large cities that are near our cities are targets)
Code:
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}

(B): (Cities that are near our large cities are targets)
Code:
for (pLoopCity = GET_PLAYER(eIndex).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(eIndex).nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(this->getID(), iMaxDistance);
}
(AI_playerCloseness uses the size of the passed in player's city to determine how many closeness points they are worth.)
 
For loop change 1:
Code:
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}
For loop original:
Code:
for (pLoopCity = GET_PLAYER(eIndex).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(eIndex).nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(this->getID(), iMaxDistance);
}

@Yakk and Jdog - you people rock :goodjob:
I've been following this discussion with a lot of enjoyable interest although I don't fully understand all aspects. In light of the context of this forum as tracking down bugs, you'd have to look at the "human error" nature of the issue wouldn't you? It appears to be a simple confusion between (this)player and player(eIndex) inside the function CvPlayerAI::AI_playerCloseness(...). If you look at the original for loop construction, that is everywhere through the BTS code. Considering that the for loop construction is the most likely candidate for human error (not the AI_playerCloseness function call), you would have to go with Yakk's option (A) as the fix wouldn't you? (fixes referencing error leaving structure intact). Although option (A) doesn't sound right either, it would seem to be what Firaxis intended?.....

There is one little code detail I cannot understand could you help me? In CvTeamAI you get the code:
Code:
iValue += GET_PLAYER((PlayerTypes)iI).AI_playerCloseness((PlayerTypes)iJ, iMaxDistance);

I assume that (PlayerTypes) is a casting of iJ but iJ is just an integer not an object yes? What is (PlayerTypes)iJ doing?

Cheers.
 
In C++, there are enumrations and there are integers.

Enumerations are very weakly typed, but are a slightly different type than integers.

PlayerTypes is an enumeration that refers to which player is involved. In this case, it refers to the index of the player in question. GET_PLAYER is a macro that takes the index of the player involved, and returns a CvPlayer& (I think that's the type it returns at least).

Both (A) and (B) are really close to the original code. It is pretty certainly an example of programmer error, but which way it was actually intended is questionable. (C) would be a modification (or one could say improvement): both the size of your city, and the size of the other city, do matter when trying to work out how much "closeness" between your empire and their empire the two cities contribute.

Ie, two small cities close together -- that isn't really a serious amount of closeness, compared to two large cities close together. In the large city case, a war both means that you are going to make your empire "better shaped", and you can grab tasty bits off of your opponent.

The cases of small+large is what differs between (A) and (B). It means that empire X might think that they are "close" to empire Y, but empire Y might think they are far away from empire X. Sort of strange.

Should civilizations try to take out any cities that are "close" to their large cities, or should civilizations try to take out large cities that are "close" to any of their cities?

The second is a matter of "ooo, that's a tasty city". The first is matter of "hey, what are you doing with that city near my imperial core?"

If we go with the first, then a civilization that (say) drops a micro-city right in the middle of the main part of your empire will consider that empire to be a very high target for aggressive war. If we go with the second, the targeting swaps.

Already, there is a bias towards going after targets which make your empire "concave" -- the inner player will have their city being "close" to a single one of the outer cities, while the outer cities can all individually be "close" to the inner one.

...

Regardless, if we fix it in either way, we should get a better "closeness" metric for the AIs involved. There is concern that it will end up being overkill.

(Note that as it stands, "Closeness" meant "Target has large numbers of tightly packed large cities")
 
It wouldn't be too hard to implement option C, in CvCityAI::AI_playerCloseness we could change:

Code:
iTempValue = 20 + [B]pLoopCity->getPopulation() * 2[/B];

which is just based on the size of the other city, to:

Code:
iTempValue = 20 + [B]pLoopCity->getPopulation() + getPopulation()[/B];

where the second population is the population of the city for which the function was called. Doesn't disrupt the expected magnitude of values and also doesn't add any computation time while achieving what to me is the desirable middle ground.
 
Yakk said:
(Note that as it stands, "Closeness" meant "Target has large numbers of tightly packed large cities")

lol those silly AIs crack me up! :)

By the way, thanks for the good work guys. :goodjob: Do these fixes end up in Bhruic's patch or do you give them to Firaxis?
 
It wouldn't be too hard to implement option C, in CvCityAI::AI_playerCloseness we could change:
Code:
iTempValue = 20 + [B]pLoopCity->getPopulation() + getPopulation()[/B];

Thanks for your thoughts. Here are some of my own. I now am starting to think that the "human error" was that option B was intended let me explain.

Point 1:
The for-loop construction using the macro GET_PLAYER (thanks Yakk) is so common in the BTS code. The design of the function:
int CvPlayerAI::AI_playerCloseness(PlayerTypes eIndex, int iMaxDistance)
would surely have been intended utilising that standardised for-loop construction. I cannot imagine that all of the coders and quality control would have opted for the option A non-standard for loop construction. It just looks "different" and would have raised questions.

Point 2:
Because of point 1, the error has to be in the summing code inside that loop. The correct code by inference must be:
Code:
for (pLoopCity = GET_PLAYER(eIndex).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(eIndex).nextCity(&iLoop))
{
iValue += pLoopCity->AI_playerCloseness(this->getID(), iMaxDistance);
}

Point 3:
Assuming the correctness of point 1 and point 2, there is an over-arching "strategic" flavour to the whole issue of "closeness". If option A were correct, that is a tactical issue. In other words "can I capture a large ripe enemy target from my any size close city". That question is tactical because it depends on a matter of unit deployment. In the case of a war on another continent, it would be how many galleons full of invasion forces did I bring?

Point 4:
If point 3 is correct, option B is a strategic question in line with the flavour of the actual "closeness" code. In other words "can I capture any size enemy target city close to my integrated cities". It is strategic because "large numbers of tightly packed large cities" have automatic strategic defenses already in place usually with the capacity for attack as well. That would fit with the measure of strategic "closeness" to me as it is in the code right now.

Point 5:
Here are all the references to AI_playerCloseness that I can find:
A) int CvCityAI::AI_cityThreat(bool bDangerPercent)
Here it seems to be asking whether a "crush strategy" is possible (strategy not tactic).

B) void CvPlayerAI::AI_conquerCity(CvCity* pCity)
Here it seems to work out whether it is possible to raze a city from a "structural" perspective (strategy)
Code:
int iCloseness = pCity->AI_playerCloseness(getID());
                    if (iCloseness > 0)
                    {
                    	iRazeValue -= 25;
                    	iRazeValue -= iCloseness * 2;
}

C) int CvPlayerAI::AI_getStrategyHash()
Here it seems to be working out the strategic effect on diplomacy based on "closeness". All of these questions seem to be "strategic" not "tactical" to me.

As for Jdog's wonderfully simple idea, isn't it a fascinating though? What was really intended was not:
pLoopCity->getPopulation() * 2 (arbitrary short term fix looks to me!)
with:
pLoopCity->getPopulation() + getPopulation()! (yeah right on!???)

I would *love* to understand the effect of that simple alteration. Is it right and good or is it not? I can only look at the code and guess. I have no debugger yet. I find it hard work to deciphor the difference without practical experiment.

As Yakk said, there is a chance of "overkill". The option B fix looks to me to be a bug fix, while Jdog's suggestion looks to be a "better ai" fix. Maybe we should release dll's with the Option B fix combined with Jdog's two variations of the closeness equations so that people can try for themselves?

Cheers and thanks.
 
Back
Top Bottom