Afforess
The White Wizard
Civic value should be analyzed in a vacuum so to speak, and have nothing to do with whether they are currently active or not.
I agree, and am fairly confident you are correct this time LunarMongoose.
Civic value should be analyzed in a vacuum so to speak, and have nothing to do with whether they are currently active or not.
/************************************************************************************************/
/* BETTER_BTS_AI_MOD 07/19/09 jdog5000 */
/* */
/* Civic AI */
/************************************************************************************************/
void CvPlayerAI::AI_doCivics()
{
CivicTypes* paeBestCivic;
//
// Mongoose AICivicFix BEGIN
//
//
// Mongoose AICivicFix END
//
int iI;
FAssertMsg(!isHuman(), "isHuman did not return false as expected");
/************************************************************************************************/
/* BETTER_BTS_AI_MOD 07/20/09 jdog5000 */
/* */
/* Barbarian AI, efficiency */
/************************************************************************************************/
if( isBarbarian() )
{
return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD END */
/************************************************************************************************/
if (AI_getCivicTimer() > 0)
{
AI_changeCivicTimer(-1);
return;
}
if (!canRevolution(NULL))
{
return;
}
FAssertMsg(AI_getCivicTimer() == 0, "AI Civic timer is expected to be 0");
paeBestCivic = new CivicTypes[GC.getNumCivicOptionInfos()];
// Threshold to make AI hold off on civics changes, threshold is percentage to add to
// value of current civics
//
// Mongoose AICivicFix BEGIN
//
int iThreshold;
if ((getAnarchyTurns() == 0) || isGoldenAge())
{
iThreshold = 105;
}
else
{
iThreshold = 120;
}
//
// Mongoose AICivicFix END
//
int iCurValue;
int iBestValue;
for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
{
paeBestCivic[iI] = AI_bestCivic((CivicOptionTypes)iI, &iBestValue);
iCurValue = AI_civicValue( getCivics((CivicOptionTypes)iI) );
//
// Mongoose AICivicFix BEGIN
//
iCurValue = (iCurValue * iThreshold) / 100;
//
// Mongoose AICivicFix END
//
if ( paeBestCivic[iI] == NO_CIVIC || iBestValue < iCurValue )
{
paeBestCivic[iI] = getCivics((CivicOptionTypes)iI);
iBestValue = iCurValue;
}
//
// Mongoose AICivicFix BEGIN
//
//
// Mongoose AICivicFix END
//
}
// XXX AI skips revolution???
if (canRevolution(paeBestCivic))
{
revolution(paeBestCivic);
AI_setCivicTimer((getMaxAnarchyTurns() == 0) ? (GC.getDefineINT("MIN_REVOLUTION_TURNS") * 2) : CIVIC_CHANGE_DELAY);
}
SAFE_DELETE_ARRAY(paeBestCivic);
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD END */
/************************************************************************************************/
That is the problem. There is no such vacuum.Civic value should be analyzed in a vacuum so to speak, and have nothing to do with whether they are currently active or not.
Exactly.This still doesn't solve the problem with unrest specifically introduced by switching off a +happiness civic, or irreversible city shrinkage from switching off a +health civic. It will consider the value of extra health and happiness, but not realize harm in giving them up if they're being fully utilized
[COLOR="Gray"] int iHappyNow = iCityHappy;
int iHappyThen = iCityHappy + iHappy;[/COLOR]
[COLOR="Green"]//these lines are missing:[/COLOR]
[B] iHappyNow = std::min(5, iHappyNow)
iHappyThen = std::min(5, iHappyThen)[/B]
Mind sharing it when complete? Removing civic effects, temporary adding effects of best civics, and restoring the old civic effects are the parts I have doubts I could figure out all that quickly. Maybe I could actually switch civics during those processes?I agree the procedure you outlined is the only way to REALLY solve this. Soooo... I'm currently attempting to write the code to do exactly that. Wish me luck.
If you mean the 2 missing lines: Beware of my lack of concentration, I was using std::max when it should have been min.Thank you for doing that, especially since it yielded an additional code improvement.
I was thinking it is actually smart to only factor in the cities that matter most but it should probably be done in a different way: Use all cities but weight every city's happyWeight by its population. So if you have one city with 20 pop and one with 1 pop, the first city will profit from happy and the other won't, and the return value would be (20*first city happyWeight + 1*second city happyWeight / totalpop)Edit 2 - The average of the player's first 7 cities? Grr, stupid... Maybe if you picked 7 cities at random from his whole empire that'd be okay as a statistical average, but the FIRST 7 are likely to be the most developed and, more importantly, have the highest population, at least for a while before populations reach their limits and stabilize around the world. I assume you agree that, despite the speed cost, it'd be better to check all of them?
Mind sharing it when complete? Removing civic effects, temporary adding effects of best civics, and restoring the old civic effects are the parts I have doubts I could figure out all that quickly. Maybe I could actually switch civics during those processes?)
If you mean the 2 missing lines: Beware of my lack of concentration, I was using std::max when it should have been min.
I was thinking it is actually smart to only factor in the cities that matter most but it should probably be done in a different way: Use all cities but weight every city's happyWeight by its population. So if you have one city with 20 pop and one with 1 pop, the first city will profit from happy and the other won't, and the return value would be (20*first city happyWeight + 1*second city happyWeight / totalpop)
Yes, and therefore the value for this city will be low (or zero, or even below if you don't cap the happyNow/Then values to 5), and that will greatly reduce the average, which is what is returned.My concern with that would be, that I thought population was already being more-or-less taken into account by the existing AI_getHappinessWeight() code: if a city is small it will automatically be nowhere near its happiness limit.
Well the assumption is 1) that the big city might grow slower but also has a lot of buildings that make the additional pop more valueable, 2) that the small cities will rarely have happiness prolems anyway and if they do, in general doing something about it is easier for small cities than it is for bigger ones.I personally would probably consider a size 20 city being able to slowly grow to 22 no more valuable than a size 2 city suddenly being able to quickly grow to 4 from a civic, so my initial inclination would be to stick with even weights.
My policy currently is to share fixes and not share mods, so yeah I would.
My policy currently is to share fixes and not share mods, so yeah I would.
Yes, and therefore the value for this city will be low (or zero, or even below if you don't cap the happyNow/Then values to 5), and that will greatly reduce the average, which is what is returned.
Hmm, isn't using the average happiness increase as a basis for evaluating the power of a civic a major error in the original code? It's very hard to get a good comparison between the effects of civics when you immediately start using averages. If you divide by the number of cities (take the average effect) in every civic evaluation, then it has no effect in the evaluation of the civics. If you only use this average in the evaluation of some civics, then the comparison between civics becomes very uninsightful and vague.
And of course, one of the main elements which was discussed here, switching between civics with different levels of happiness boost should be taken into account. So you'd have to count from a basic zero-level civic where no happiness effect is present.
[COLOR="Green"]//Civic vacuum[/COLOR]
for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
{ eOldCivic = getCivics((CivicOptionTypes)iI);
if (eOldCivic != NO_CIVIC)
{
processCivics(eOldCivic, [B]-1[/B]);
}
}
for (iI = 0; iI < GC.getNumCivicOptionInfos(); iI++)
{ eOldCivic = getCivics((CivicOptionTypes)iI);
if (eOldCivic != NO_CIVIC)
{
processCivics(eOldCivic, [B]1[/B]);
}
}
[COLOR="Green"]//Civic vacuum END[/COLOR]
Edit for Great Justice - The averages are part of the AI_getHappinessWeight() and AI_getHealthWeight() functions, but they are multiplied by getNumCities() in the AI_civicValue() code that started all this 30 posts ago, turning them back into full, unbounded values. See? I toldja this was complicated lol.
I am now working on the code that uses that, which is in AI_civicValue(), AI_H/HWeight() and... gulp... AI_doCivics(). There's at least one additional improvement to make here btw: BBAI is unchanged from vanilla, and assumes 3 military units will be present in general slash on average when calculating the value of the Monarchy happiness effect. I'm going to change that to something along the lines of the civ's land-unit army size divided by their number of cities... Please suggest a scale coefficient for that if you want one.
As for the military happiness: count your units with UNITAI_CITY_DEFENCE to find out how much happiness you will gain. Or if there are more unitais that mostly stay in cities, add them too, total units is too much though, you can't count on them staying in cities.