Deity snowballers discussion

Grind is just a side effect of a less efficient war. We are discussing it, because warring is much better than peace most of the time which cause imbalance. It's all in this thread.

So... as I said, is anyone here really enjoying the war grind right now? Because the anti warmonger penalties and the low ranged units already make it a grind. It’s not about it being less efficient, I’m saying that it’s already not possible to just stomp the Deity AI because of their bonuses. Then most people here seem to want to nerf warring more, instead of buffing peace as @ElliotS said. Highly upgraded units are the only way to take enemy cities on land. If you nerf warring more, it just won’t happen.

The skill expression required to take an enemy AI capital when the AI is multiple techs ahead is greater than peace. I’ll go ahead and say that. Also, I’ll note that this has turned from a deity snowballed discussion into a discussion about whether authority and war is overpowered relative to the other policies and peace. But on lower difficulties, winning mostly peacefully is a clear option.

On the last patch, the XP bug made warring fun. Highly upgraded units were a hoot. Currently, players can get enough gold to upgrade units until about Field Guns and then it’s much harder to do so without going Imperialism or Autocracy. This makes sense and adds meaning to the policy tree selection.
 
Also, in terms of making war harder, and more fair to the AI, can anyone explain why the AI doesn’t pick certain level 4 upgrades like range, logistics, stalwart? I get that they may not use them as well as humans, but that would certainly do something.
 
Also, in terms of making war harder, and more fair to the AI, can anyone explain why the AI doesn’t pick certain level 4 upgrades like range, logistics, stalwart? I get that they may not use them as well as humans, but that would certainly do something.
Isn't it more a matter of that their units rarely survive that long. I have seen AI logistic units etc. They are just rare cause of the way that the AI does war -- full attack with everything all the time while the human player holds back the valuable units and pick of the inevitable wall that comes against you.
 
What do you guys think would make war "equal" to peace? Give me your dream patchnotes, because nothing I've seen suggested looks like it would accomplish that.

Not sure why people are saying it should either be perfectly balanced or not bother changing anything. Any change to make it more balanced would be an improvement since it would allow players to be able to choose different strategies to suite particular situations. Also if it is closer to equal we can continue suggesting small changes in the future until we feel it is equal.

To me I agree that there should be some small reduction in benefits of capturing cities. Maybe unhappiness could cause more problems as I honestly feel like it would be possible to just truck through it when conquering but that doesn't feel right. (Also it's not really hard to manage, you just keep populations low).

However my main thing that I think would be easy to change is that the pacing of Deity AIs is quite off. They are too fast at the start/mid game and then slow down a lot at the end. Being able to get Religion/Some Wonders is pretty important to a lot of peaceful strategies but right now it can be impossible to get a religion or any wonders after the 3rd tech tier ones too often. Especially since the tech goes faster on Deity so the only people with enough policies to build medieval/renaissance wonders are snowballing AIs. This obviously encourages war as you have all to gain and nothing to lose. Also AI cities come out much faster than yours which also tends to force your hand towards war.

Also I do agree that authority is generally better than the other policies for humans (even without warring) as production is so important. Nerfing it doesn't seem correct though as AIs seem to struggle with it. AIs do get mostly production bonuses already though so this may be why the extra production doesn't do as much for them as the culture/science from tradition and progress.
 
Also, I’ll note that this has turned from a deity snowballed discussion into a discussion about whether authority and war is overpowered relative to the other policies and peace. But on lower difficulties, winning mostly peacefully is a clear option.
Yeah, and if you nerf warmongering, so peaceful play is at similar level and balance Deity difficulty accordingly, then you could win on Deity either via peace or war. You wouldn't be forced to 1 strategy, which would be more balanced. That's the point.
 
Also, in terms of making war harder, and more fair to the AI, can anyone explain why the AI doesn’t pick certain level 4 upgrades like range, logistics, stalwart? I get that they may not use them as well as humans, but that would certainly do something.

From what I've heard, the promotion selection AI is garbage. I'm not certain if that's still the case.
 
So guys, in order to summarize things up as @ElliotS suggested I will now list what I consider a good starting point changes, feel free to discuss it, so we can work something out:

Authority should be a tree to war, and I don't intend to make war more of a grind so:
Free settler from authority to progress and rework, the simplest and one of the most impactful change we can make. I would like imperium policy to grant science and culture only on city's capture. It would also lead to an indirectly increased difficulty. Because I fear that free settler much more in the hands of Russia and Carthage than Napoleon. Authority AIs should be buffed by increase in their early aggressiveness. Alternative would be eliminating this free settler altogether and giving progress a bonus to production of them.
Free culture and science only on city's capture, it goes hand in hand with authority spirit, weakens authority but not where it's supposed to shine, e.g. at war.
Plus one production dropped from authority's opener, i completes the stripping authority of early development bonuses which deserve to be in progress. You still will have plus five production total but later so it will be not as OP as now.
All of that don't make authority worse at war, or war more of a grind, which I would also like to avoid, but they take away development advantages which make authority so good when they are on top of war bonuses. Gold and production from borders stays and still will be abundant.

Making authority and war more AI friendly, we may implement:
Eliminating heal on kill, but in order to not make war more a grind replacing it with static attack bonus which both player and AI will be able to utilize.
Reducing units experience or making them much more expensive to upgrade, proposed by @Rhys DeAnno and @Recursive in this thread. Especially ranged units could take a hit in halving experience, as they are notorious to being more player friendly.

In a move to make authority more manageable and even more war oriented I suggest this:
One happiness and two culture from barracks instead from a garrison, authority should shine at war. Now it can't make use of that policy, I know I can't when I am conquering because of the lack of units due to cap. They can't be in the city, all my units must be at the field conquering. This is a simple solution to make war a less of a grind.

Stuff to make peace a bit better:
Making trade routes more valuable when at peace, maybe bonus for both tradition and progress and not only when you are behind. Culture for interacting with other cultures through trade? Production from learning new business models and developing new tools? Commerce should be naturally buffed in peace-seeking nations, it's logical. Trade units price should stay as it is in my view. Credit for the idea goes to @chicorbeef
Introducing more penalties for atrocities, maybe you will think twice before exterminating or starving population to raze the city,or conquering the whole continent, if nobody bar your strongest ally or a vassal wouldn't like to have anything with you including buying or selling any luxuries at all for a long time.

My others proposals, harder to implement, for future debate:
Loyalty and rebellions when you are seen a week leader, for example you finished authority, so the foundation of your state lies at authority and strength you exert. If you are loosing any war or cities let a third of your units rebel with a first strike and fight you and pillage tiles in you empire. Or if you are not at war for a long time, without any conquest, let happiness drop by one in all your cities until you invade someone and conquer a valuable city or kill enough units.
Courthouses for every city and rework of how occupation works, I never liked an idea for a courthouse to be occupied city only building. Maybe it should be normal building with yield improvement for culture, science, golden age points, or flat one happiness and culture or science reward akin to circus? And maybe then authority should not be able to use it in any city, as it represents independent justice, granting of freedoms, and protection from the state (not exactly, especially in classical era, but you get the idea, tyrannies are not just to the citizen). Then we could have yield penalties for conquered cities. From the lack of better idea, I propose triple times the duration of resistance for halved yields and usual happiness hit which now is taken care of by courthouse, then gain three times the resistance turns with -25% for all yields without happiness hit.

However I don't think that a proposal of tradition not taking a food hit is a good one. Too much of snowballing potential in the hands of AI.

@Recursive my reply to you was also tongue-in-cheek so no hard feelings.
Policies: I'll echo again that I don't think authority is a problem branch. Outside of very early UUs that I really want to take advantage of, progress is quite good at war. In fact we had a point where we stripped authority of its production bonus on the opener, and it basically killed the whole tree IIRC.

If anything is to be changed with policies, progress should give some yields when units are built (Full manually, half for bought, like XP), and tradition should give +10% CS in owned territory and +5% CS in neutral. (Or maybe new units get +1 XP per specialist in a city? Worried about that's power late.) Let them get in on the military game a bit more.

Also wouldn't moving authority's happiness/culture to barracks be a huge buff to the player?

XP Reduction: While not a bad idea in terms of balance, it would be unfun. The change had been proposed before, and even tried at times, but it's generally seen as the balance gains are not worth the penalty to fun. I agree with that opinion. It would close the gap between player and AI in warfare a bit, but the loss of fun isn't worth it.

The other argument is that XP is the major place where a player is supposed to use his skill to win. The point of civ is to use your big human brain to beat the AI, and unit XP has always been a major place to do that. Getting a bunch of highly promoted units feels good and is a great way to win. I'll also bet that lower-skilled players would be hit harder by an XP-reduction than us Deity players.

My suggestion is that if anything we add [yet another] toggle for reduced XP, (or a ModMod) but I don't support making it default. It goes against too many people's idea of fun.

Peace buffs: Honestly buffing trade routes isn't a terrible idea, but not sure the way you're suggesting is best. Here's my idea: Trade routes get bonus yields when at peace(+25%?), and bonus yields when completed based on the target's opinion of you.

This promotes more than fleeting peace, and adds another positive award for good diplomacy that is severely lacking. It also is an active bonus for peace, which is important. No need to add anything to tradition or progress here either. If Authority wants to stay at peace and build relations they can feel free to do that.

We might need to do more to make peace feel rewarding, but I'd do this and see where it takes us.

More penalties for atrocities: I've never felt like it was too easy to keep good relations while warmongering. If anything I think minor warmongering shouldn't totally push you out of the diplomatic game, so you are not forced to go all-or-nothing. The balance seems pretty close there as it is.

Yield Reduction in annexed cities: This one seems like a pretty good idea. Slows down the snowball a bit, and makes turning vassalage off even more of a increase to war difficulty for those who want it. That said wouldn't there need to be a small hit to puppet yields as well? Also if we're nerfing puppets, can we allow faith-buying in them? Not being able to buy faith buildings in puppets is annoying.

AI Change: Finally I think if we're nerfing a bunch of this AI should lose the production from A/B/C bonuses, and we could maybe increase their building production cost discount by 5% to compensate a bit. Production seems to be what causes the most problems, and if combined with making shrines full price (like wonders) it would solve the other issue people have mentioned on the pantheon front.
 
Yeah, and if you nerf warmongering, so peaceful play is at similar level and balance Deity difficulty accordingly, then you could win on Deity either via peace or war. You wouldn't be forced to 1 strategy, which would be more balanced. That's the point.

Count me in the buff peaceful play over nerfing warmongering then. My peaceful games at lower difficulty take much less real time than my warmongering games. I’d like peaceful games, just not at the expense of nerfing war. It’s already a grind. I also think it’s not quite as reductionist as you’ve framed it.

As @Milae pointed out, the Deity AI pacing is off. There are certain wonders that a human player can maybe get and everything from the 4th tech level on is pretty much out of reach. I can play peaceful at Emperor difficulty because I have a shot at Oracle, Hagia Sophia, Borobudur. I can be an early founder. Right now, that’s not the case on Deity. I favor tweaks to pacing and Deity bonuses to enable the strongest human peaceful play to match the Deity AI. My test for this would be whether the strongest early game peaceful civilizations in human hands could. Get certain key wonders. If a peaceful Arabia isn’t possible on Deity because of the timing, that should tell us the early game timing is off.

You’re saying to nerf warmongering but it’s not that warmongering is overpowered as much as it’s the only option available to the human to win on a setting where the AI will found faster and get wonders. If you can’t snowball through religion or wonders, a peaceful game isn’t possible. You can nerf warmongering and it won’t solve this issue on Deity difficulty. The game will just be more of a grind and I’ll be left wondering why the AI can snowball peacefully while I can’t. It’s not that warmongering is overpowered, it’s the best option when the AI (Poland in this case) can build Stonehenge and found a city by turn 30.

There could be Deity specific tweaks that enable peaceful play related to the timing that should be examined first.
 
From what I've heard, the promotion selection AI is garbage. I'm not certain if that's still the case.

On the last patch with the xp bug, the Zulu would have level 5 or 6 units that were like 3 Drill and 3 Shock. I’m not sure that I’ve seen AI building city assault melee units. Anyone?
 
Regardless of what changes are made, is it possible for these changes to largely only apply to Immortal and/or Deity?

It seems to me that a lot of changes for VP are influenced heavily by higher difficulty players. This is causing the situation where changes proposed here or by high difficulty players are also applying to lower difficulty. Maybe the more experienced players have no problem playing on any difficulties but, if the resulting changes make lower difficulties tougher, then it's likely not good for the player base overall.

My biggest worry is that balancing the game to make Deity viable for peaceful and warmonger play styles will have unexpected impact on the lower difficulties.
 
Regardless of what changes are made, is it possible for these changes to largely only apply to Immortal and/or Deity?

It seems to me that a lot of changes for VP are influenced heavily by higher difficulty players. This is causing the situation where changes proposed here or by high difficulty players are also applying to lower difficulty. Maybe the more experienced players have no problem playing on any difficulties but, if the resulting changes make lower difficulties tougher, then it's likely not good for the player base overall.

My biggest worry is that balancing the game to make Deity viable for peaceful and warmonger play styles will have unexpected impact on the lower difficulties.
I think you're kinda right and kinda wrong. Some of the changes suggested (especially XP nerfs) I think would have a massive negative impact on lower-skilled players and lower difficulties. Changes with negative spill-over effects are bad.

However at the same time Deity often pushes players to play the most optimally possible. If a strategy is OP in deity it's likely just as OP in lower difficulties, but not quite so apparent. Reigning in the best strategies in Deity often has a positive spill-over that makes every level of play more balanced. (An exception is stuff like Terracotta Army, which is better in Deity because the AI has more units.)
 
I think you're kinda right and kinda wrong. Some of the changes suggested (especially XP nerfs) I think would have a massive negative impact on lower-skilled players and lower difficulties. Changes with negative spill-over effects are bad.

However at the same time Deity often pushes players to play the most optimally possible. If a strategy is OP in deity it's likely just as OP in lower difficulties, but not quite so apparent. Reigning in the best strategies in Deity often has a positive spill-over that makes every level of play more balanced. (An exception is stuff like Terracotta Army, which is better in Deity because the AI has more units.)

I think the question we're struggling with here is:

1. Is warmongering generally OP?

Or

2. Is warmongering OP because peaceful play isn't viable on Deity?

On Deity, Terracotta Army and Authority are stronger because the AI has more units to kill but wonders supporting peaceful play are almost impossible to get.

There's a reverse effect for peaceful wonders in that they're available at lower difficulties but almost impossible to get on Deity. Spreader beliefs and wonders that help spreading (Borobodur and Hagia Sophia) are thus nerfed for Deity but very strong on lower levels where the AI doesn't found as quickly.

It's possible to snowball on a lower difficulty because wonders are available. On Deity, if wonders aren't available, then warmongering does seem to be optimal but that isn't the case at lower difficulties where a human can get the wonders needed for tall.

On the current patch, I'm not sure that I've ever gotten a wonder on the 4th tech tier. Except for Terracotta Army, which the AI doesn't value as heavily, I've also not gotten a wonder on the 3rd tech tier. I've played out the first hundred turns on deity quite a few times, feeling out setups
 
Last edited:
I think you're kinda right and kinda wrong. Some of the changes suggested (especially XP nerfs) I think would have a massive negative impact on lower-skilled players and lower difficulties. Changes with negative spill-over effects are bad.

However at the same time Deity often pushes players to play the most optimally possible. If a strategy is OP in deity it's likely just as OP in lower difficulties, but not quite so apparent. Reigning in the best strategies in Deity often has a positive spill-over that makes every level of play more balanced. (An exception is stuff like Terracotta Army, which is better in Deity because the AI has more units.)

My issue is this most optimal play which seems to suggest that the player is limited to what they can do to win. There are these optimal choices you have to make to win or less optimal choices that will lose you the game. I like VP because it makes it possible to play diverse ways. However, I won't enjoy the game very much if optimal strategies are mandatory for lower difficulties. For example, I might want to play a civilization sub-optimally on Emperor or lower and try to win the game that way. That won't be possible if the changes revolving around the optimal strategy that Deity utilize start creeping into lower difficulties. The more I think about it, the more I think that these belong to modmod territory. Otherwise, there are too many unintended spill-over effects that could ruin the experience of lower difficulty and newer players.
 
A point that doesn't seem to have been raised is whether games are being played on Standard, Epic or Marathon. As far as I know, game play is balanced off Standard.
 
A point that doesn't seem to have been raised is whether games are being played on Standard, Epic or Marathon. As far as I know, game play is balanced off Standard.
Yeah, I assume whole discussion is about Standard speed.
 
I think the question we're struggling with here is:

1. Is warmongering generally OP?

Or

2. Is warmongering OP because peaceful play isn't viable on Deity?

On Deity, Terracotta Army and Authority are stronger because the AI has more units to kill but wonders supporting peaceful play are almost impossible to get.

There's a reverse effect for peaceful wonders in that they're available at lower difficulties but almost impossible to get on Deity. Spreader beliefs and wonders that help spreading (Borobodur and Hagia Sophia) are thus nerfed for Deity but very strong on lower levels where the AI doesn't found as quickly.

It's possible to snowball on a lower difficulty because wonders are available. On Deity, if wonders aren't available, then warmongering does seem to be optimal but that isn't the case at lower difficulties where a human can get the wonders needed for tall.

On the current patch, I'm not sure that I've ever gotten a wonder on the 4th tech tier. Except for Terracotta Army, which the AI doesn't value as heavily, I've also not gotten a wonder on the 3rd tech tier. I've played out the first hundred turns on deity quite a few times, feeling out setups
I mean in that case how much could be solved by reducing earlier bonuses and buffing the scaling A/B/C bonuses (especially C) to compensate? The whole point of A/B/C bonuses was so that the AI could keep pace with a human of that difficulty, starting relatively on-par and staying near the whole game. (As opposed to vanilla which starts ahead and loses if you approach parity.)
A point that doesn't seem to have been raised is whether games are being played on Standard, Epic or Marathon. As far as I know, game play is balanced off Standard.
Yeah if anyone is playing on epic or marathon their opinion is obviously going to be way biased towards warfare, but I doubt anyone is doing that here.
 
Yeah if anyone is playing on epic or marathon their opinion is obviously going to be way biased towards warfare, but I doubt anyone is doing that here.

I raised the point because I've noticed a lot of game references to Deity/Epic, etc. in various threads. Warfare on Epic is going to seem easier. And if that's how you normally play, transposing an evaluation to Standard wouldn't be easy.
 
I mean in that case how much could be solved by reducing earlier bonuses and buffing the scaling A/B/C bonuses (especially C) to compensate? The whole point of A/B/C bonuses was so that the AI could keep pace with a human of that difficulty, starting relatively on-par and staying near the whole game. (As opposed to vanilla which starts ahead and loses if you approach parity.)
.

Agreed. I think the bonuses are off a little too much.

What I'd like to see is:

1. The bonuses reduced early, so that a human had a shot at wonders through medieval. Ideally, the AI gets production cost reductions, not instant production. Right now, Deity feels a bit like vanilla Civ 5. When I've got 14 techs, the AI has 20 and I'm not sure why or how. (Particularly for unsuccessful Authority AI.)

2. Promotion selection changed to give the AI better promotion choices. The AI sometimes has melee units with Drill II and amphibious. I'm unsure why it isn't Drill II and City Assault, if we want Authority AIs to actually take cities. (Disclaimer : not sure if possible.)
 
From what I've heard, the promotion selection AI is garbage. I'm not certain if that's still the case.

Oboy...https://github.com/LoneGazebo/Community-Patch-DLL/issues/6762

2. Promotion selection changed to give the AI better promotion choices. The AI sometimes has melee units with Drill II and amphibious. I'm unsure why it isn't Drill II and City Assault, if we want Authority AIs to actually take cities. (Disclaimer : not sure if possible.)

Possible: Yes. Easy: No.

Code:
//   --------------------------------------------------------------------------------
void CvUnit::AI_promote()
{
   VALIDATE_OBJECT
   PromotionTypes eBestPromotion = NO_PROMOTION;
   int iBestValue = 0;
   int iNumValidPromotions = 0;

   for(int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
   {
       const PromotionTypes ePromotion(static_cast<PromotionTypes>(iI));

       CvPromotionEntry* pkPromotionEntry = GC.getPromotionInfo(ePromotion);

       if (pkPromotionEntry == NULL)
           continue;

       if(canPromote(ePromotion, -1))
       {
           iNumValidPromotions++;
           int iValue = AI_promotionValue(ePromotion);

           //value lower-level promotions a bit less.
           if (pkPromotionEntry->GetPrereqOrPromotion1() == NO_PROMOTION)
               iValue /= max(1, getLevel());

           for (int iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
           {
               const PromotionTypes eNextPromotion(static_cast<PromotionTypes>(iJ));
               CvPromotionEntry* pkNextPromotionEntry = GC.getPromotionInfo(eNextPromotion);
               if (!pkNextPromotionEntry)
                   continue;

               //for some basic forward planning, look at promotions this promotion unlocks and add those to the value.
               if (   pkNextPromotionEntry->GetPrereqOrPromotion1() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion2() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion3() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion4() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion5() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion6() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion7() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion8() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion9() == ePromotion)
               {
                   iValue += AI_promotionValue(eNextPromotion) / 2;
               }

           }
          
           if(GC.getLogging() && GC.getAILogging())
           {
               CvPromotionEntry* pkPromotionEntry = GC.getPromotionInfo(ePromotion);
               CvString strPromotionDesc = (pkPromotionEntry != NULL) ? pkPromotionEntry->GetDescription() : "Unknown Promotion";
               CvString strUnitName = getName();
               CvString strCivName = GET_PLAYER(getOwner()).getName();
               strPromotionDesc.Replace(' ', '_'); strPromotionDesc.Replace('(', '_'); strPromotionDesc.Replace(')', '_');
               strUnitName.Replace(' ', '_');
               strCivName.Replace(' ', '_');

               FILogFile* pLog = LOGFILEMGR.GetLog("PromotionLog.csv", FILogFile::kDontTimeStamp | FILogFile::kDontFlushOnWrite );
               CvString strLog;
               strLog.Format("%03d, %s, ", GC.getGame().getElapsedGameTurns(), strCivName.c_str());
               CvString strMsg;
               strMsg.Format("Promotion, %s, For %s, Ranged %d, Domain %d, Value: %d, Damage: %d", strPromotionDesc.c_str(), strUnitName.c_str(), isRanged() ? 1 : 0, getDomainType(), iValue, getDamage());

               strLog += strMsg;
               pLog->Msg(strLog);
           }

           //add some randomness
           if(iValue > 0)
               iValue += GC.getGame().getSmallFakeRandNum(iValue/2, plot()->GetPlotIndex() + iI);

           if(iValue > iBestValue)
           {
               iBestValue = iValue;
               eBestPromotion = ePromotion;
           }
       }
   }

   if(eBestPromotion != NO_PROMOTION)
   {
       promote(eBestPromotion, -1);

       CvPromotionEntry* pkPromoInfo = GC.getPromotionInfo(eBestPromotion);
       if (pkPromoInfo && GC.getLogging() && GC.getAILogging())
       {
           CvString strPromotionDesc = pkPromoInfo->GetDescription();
           CvString strUnitName = getName();
           CvString strCivName = GET_PLAYER(getOwner()).getName();
           strPromotionDesc.Replace(' ', '_'); strPromotionDesc.Replace('(', '_'); strPromotionDesc.Replace(')', '_');
           strUnitName.Replace(' ', '_');
           strCivName.Replace(' ', '_');

           FILogFile* pLog = LOGFILEMGR.GetLog("PromotionLog.csv", FILogFile::kDontTimeStamp | FILogFile::kDontFlushOnWrite );
           CvString strLog;
           strLog.Format("%03d, %s, ", GC.getGame().getElapsedGameTurns(), strCivName.c_str());
           CvString strMsg;
           strMsg.Format("--> Chosen Promotion, %s, Received by %s, ID %d, Lvl %d, XP %d, Ranged %d, Domain %d, X: %d, Y: %d, Damage: %d",
               strPromotionDesc.c_str(), strUnitName.c_str(), GetID(), getLevel(), getExperienceTimes100(), isRanged() ? 1 : 0, getDomainType(), getX(), getY(), getDamage());

           strLog += strMsg;
           pLog->Msg(strLog);
       }

       //do it again until we're done
       AI_promote();
   }
}

//   --------------------------------------------------------------------------------
// XXX make sure we include any new UnitAITypes...
int CvUnit::AI_promotionValue(PromotionTypes ePromotion)
{
   VALIDATE_OBJECT

   CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(ePromotion);
   if(pkPromotionInfo == NULL)
   {
       //This function really really really should not be called with an invalid promotion type.
       CvAssert(pkPromotionInfo);
       return 0;
   }

   int iValue = 0;

   int iTemp;
   int iExtra;
   int iI;

   bool bWarTimePromotion = plot()->getOwner() != NO_PLAYER && GET_PLAYER(plot()->getOwner()).IsAtWarWith(getOwner());

   // Get flavor info we can use
   CvFlavorManager* pFlavorMgr = GET_PLAYER(m_eOwner).GetFlavorManager();
   int iFlavorOffense = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_OFFENSE"))) * bWarTimePromotion ? 2 : 1;

   int iFlavorDefense = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_DEFENSE"))) * bWarTimePromotion ? 1 : 2;

   int iFlavorRanged = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RANGED")));

   int iFlavorRecon = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RECON")));

   int iFlavorMobile = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_MOBILE")));

   int iFlavorNaval = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_NAVAL")));

   int iFlavorAir = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_AIR")));
   iFlavorAir += max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_ANTIAIR")));

   // If we are damaged, insta heal is the way to go
   if(pkPromotionInfo->IsInstaHeal())
   {
       // Half health or less?
       if(getDamage() >= (GetMaxHitPoints() / 2))
       {
           iValue += 1000;   // Enough to lock this one up
       }
   }

#if defined(MOD_BALANCE_CORE_MILITARY_PROMOTION_ADVANCED)
   iTemp = pkPromotionInfo->GetCombatPercent();
   if(iTemp != 0)
   {
       iExtra = iTemp + getExtraCombatPercent();
       iValue += iExtra + iFlavorOffense + iFlavorDefense;
   }
   iTemp = pkPromotionInfo->GetRangedAttackModifier();
   if(iTemp != 0)
   {
       iExtra = iTemp + GetRangedAttackModifier();
       iValue += iExtra + iFlavorOffense;
   }

   if (pkPromotionInfo->IsGainsXPFromSpotting())
   {
       iExtra = iTemp + visibilityRange();
       iExtra = (iExtra * 5);

       iValue += iExtra + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetLandAirDefenseValue();
   if (iTemp != 0)
   {
       MilitaryAIStrategyTypes eStrategy = (MilitaryAIStrategyTypes)GC.getInfoTypeForString("MILITARYAISTRATEGY_NEED_AIR");
       if(GET_PLAYER(getOwner()).GetMilitaryAI()->IsUsingStrategy(eStrategy))
       {
           iTemp *= 2;
       }

       iTemp += getLandAirDefenseValue() + getUnitInfo().GetBaseLandAirDefense();

       iValue += iTemp + iFlavorDefense;
   }

   if (pkPromotionInfo->IsGainsXPFromPillaging())
   {
       iExtra = maxMoves();
       iTemp = (iExtra * 5);

       iValue += iTemp + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetGoodyHutYieldBonus();
   if (iTemp != 0 && !GC.getGame().isOption(GAMEOPTION_NO_GOODY_HUTS))
   {
       iExtra = maxMoves();
       iTemp += (iExtra * 5);

       iValue += iTemp + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetDamageReductionCityAssault();
   if (iTemp != 0)
   {
       iExtra = GetDamageReductionCityAssault();

       iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetPlagueChance();
   if (iTemp != 0)
   {
       iValue += iTemp + (iTemp/2) + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetPlagueIDImmunity();
   if (iTemp != 0)
   {
       iValue += iFlavorDefense + (iFlavorDefense/3);
   }

   iTemp = pkPromotionInfo->GetCaptureDefeatedEnemyChance();
   if (iTemp != 0)
   {
       iValue += iFlavorOffense + iTemp;
   }
#endif

   iTemp = pkPromotionInfo->GetOpenAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraOpenAttackPercent();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetOpenDefensePercent();
   if(iTemp != 0)
   {
       iExtra = getExtraOpenDefensePercent();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetOpenFromPercent();
   if (iTemp != 0)
   {
       iExtra = getExtraOpenFromPercent();
       if (noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetRoughFromPercent();
   if (iTemp != 0)
   {
       iExtra = getExtraRoughFromPercent();
       if (noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetRoughAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraRoughAttackPercent();
       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetRoughDefensePercent();
   if(iTemp != 0)
   {
       iExtra = getExtraRoughDefensePercent();

       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetOpenRangedAttackMod();
   if(iTemp != 0 && isRanged())
   {
       iExtra = getExtraOpenRangedAttackMod();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorRanged;
   }

   iTemp = pkPromotionInfo->GetRoughRangedAttackMod();
   if(iTemp != 0 && isRanged())
   {
       iExtra = getExtraRoughRangedAttackMod();
       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorRanged;
   }

   iTemp = pkPromotionInfo->GetVisibilityChange();
   if((AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE))
   {
       iValue += iTemp + iFlavorRecon * 5;
   }
   else
   {
       iValue += iTemp + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetCityAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraCityAttackPercent()/2;

       if (canMoveAfterAttacking() || AI_getUnitAIType() == UNITAI_CITY_BOMBARD)
           iValue += iTemp + iExtra + iFlavorOffense;
       else
           iValue += iTemp + iExtra/2 + iFlavorOffense/2;

       if(isRanged())
       {
           iValue += iTemp/2 * max(1, GetRange());
       }
   }

   iTemp = pkPromotionInfo->GetCityAttackPlunderModifier();
   if (iTemp != 0)
   {
       iExtra = GetCityAttackPlunderModifier();
       iValue += iTemp + iExtra + iFlavorOffense;
       if (isRanged())
       {
           iValue += iExtra * GetRange();

           if (canMoveAfterAttacking())
               iValue += iExtra;
       }
   }

   iTemp = pkPromotionInfo->GetCityDefensePercent();
   if(iTemp != 0)
   {
      
       iExtra = getExtraCityDefensePercent();
       if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAttackFortifiedMod();
   if(iTemp != 0)
   {
       if (isRanged())
       {
           iExtra = getExtraAttackFortifiedMod();
           iValue += iTemp + iExtra + iFlavorRanged;
       }
       else
       {
           iExtra = getExtraAttackFortifiedMod();
           iValue += iTemp + iExtra + iFlavorOffense;
       }
   }

   iTemp = pkPromotionInfo->GetHillsAttackPercent();
   if (iTemp != 0)
   {
       if (isRanged())
       {
           iExtra = getExtraHillsAttackPercent();
           iValue += iTemp + iExtra + iFlavorRanged;
       }
       else
       {
           iExtra = getExtraHillsAttackPercent();
           iValue += iTemp + iExtra + iFlavorOffense;
       }
   }
   iTemp = pkPromotionInfo->GetHillsDefensePercent();
   if (iTemp != 0)
   {
       iExtra = getExtraHillsDefensePercent();
       iValue += iTemp + iFlavorDefense + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetNearbyEnemyCombatMod();
   if (iTemp != 0)
   {
       iExtra = getNearbyEnemyCombatMod();
       iValue += iTemp + iExtra + iFlavorOffense;
   }
   iTemp = pkPromotionInfo->GetNearbyEnemyCombatRange();
   if (iTemp != 0)
   {
       iValue += iTemp + iFlavorOffense * 5;
   }

   iTemp = pkPromotionInfo->GetEnemyHealChange();
   if((AI_getUnitAIType() == UNITAI_PARADROP) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA))
   {
       iValue += iTemp + getExtraEnemyHeal() + iFlavorOffense * 2;
   }
   else
   {
       iValue += iTemp + getExtraEnemyHeal() + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetNeutralHealChange();
   if((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
   {
       iValue += iTemp + getExtraNeutralHeal() + iFlavorRecon * 2;
   }
   else
   {
       iValue += iTemp + getExtraNeutralHeal() + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetFriendlyHealChange();
   if((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getExtraFriendlyHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getExtraFriendlyHeal() + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetSameTileHealChange();
   if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
       (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAdjacentTileHealChange();
   if((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense;
   }

   if(pkPromotionInfo->IsAmphib())
   {
       if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_ATTACK))
       {
#if defined(MOD_BALANCE_CORE_MILITARY_PROMOTION_ADVANCED)
           iValue += iFlavorMobile * 2;
#else
           iValue += 40 + iFlavorOffense * 2;
#endif
       }
       else
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile;
#else
           iValue += 10 + iFlavorOffense * 2;
#endif
       }
   }

   if(pkPromotionInfo->IsRiver())
   {
       if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_ATTACK))
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile * 2;
#else
           iValue += 40 + iFlavorOffense * 2;
#endif
       }
       else
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile;
#else
           iValue += 10 + iFlavorOffense * 2;
#endif
       }
   }

   iTemp = pkPromotionInfo->GetRangedDefenseMod();
   if(iTemp != 0)
   {
       iExtra = getExtraRangedDefenseModifier();
       // likely not a ranged unit
       if((AI_getUnitAIType() == UNITAI_DEFENSE) || (AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_ATTACK))
       {
           iExtra *= 2;
       }
       // a slow unit
       if (maxMoves() / GC.getMOVE_DENOMINATOR() <= 2)
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetOutsideFriendlyLandsModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorRecon * 2;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorRecon;
       }      
   }
   iTemp = pkPromotionInfo->GetFriendlyLandsModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   iTemp = pkPromotionInfo->GetCapitalDefenseModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   iTemp = pkPromotionInfo->GetFriendlyLandsAttackModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   if(pkPromotionInfo->IsRangeAttackIgnoreLOS() && isRanged())
   {
       iValue += iFlavorRanged * 50;
   }

   iTemp = pkPromotionInfo->GetAttackWoundedMod();
   if(iTemp != 0)
   {
       iExtra = getExtraAttackWoundedMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAttackFullyHealedMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackFullyHealedMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAttackAboveHealthMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackAboveHealthMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorDefense;
   }
   iTemp = pkPromotionInfo->GetAttackBelowHealthMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackBelowHealthMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetMaxHitPointsChange() * 4;
   if (iTemp != 0)
   {
       iExtra = getMaxHitPointsChange() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorDefense;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetMaxHitPointsModifier() * 2;
   if (iTemp != 0)
   {
       iExtra = getMaxHitPointsModifier() * 5;

       if (isRanged())
           iValue += iTemp + iExtra + iFlavorDefense;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetSplashDamage();
   if (iTemp != 0)
   {
       iExtra = getSplashDamage() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAdjacentMod();
   if (iTemp != 0)
   {
       iExtra = GetAdjacentModifier() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAttackMod();
   if (iTemp != 0)
   {
       iExtra = getAttackModifier() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetFlankAttackModifier();
   if(iTemp > 0)
   {
       iExtra = iFlavorMobile * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }

   if (pkPromotionInfo->IsHealOutsideFriendly() && getDomainType() == DOMAIN_SEA)
   {
       iValue += iFlavorNaval * 5;
   }

   iTemp = pkPromotionInfo->GetMovesChange();
   if((AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ASSAULT_SEA) ||
           (AI_getUnitAIType() == UNITAI_SETTLER_SEA) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
   {
       iExtra = iFlavorMobile * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }
   else
   {
       iExtra = iFlavorOffense * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }

   if(pkPromotionInfo->IsAlwaysHeal())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iFlavorOffense * 5;
       }
       else
       {
           iValue += iFlavorDefense * 5;
       }
   }

   if (pkPromotionInfo->IsNoSupply())
   {
       iValue += iFlavorMobile + iFlavorNaval;
   }

   if(pkPromotionInfo->IsBlitz())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += (iFlavorMobile + iFlavorOffense) * 5;
       }
       else
       {
           iValue += (iFlavorMobile + iFlavorOffense) * 5;
       }
   }

   iTemp = pkPromotionInfo->GetAdjacentEnemySapMovement();
   if (iTemp != 0)
   {
       iTemp += GetAdjacentEnemySapMovement();
       if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_COUNTER) ||
           (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   iTemp = pkPromotionInfo->IsIgnoreZOC();
   if (iTemp != 0)
   {
       iTemp += getMoves();
       if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_COUNTER) ||
           (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   if(pkPromotionInfo->IsCanMoveAfterAttacking())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   iTemp = pkPromotionInfo->GetExtraAttacks();
   if(iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }


   iTemp = pkPromotionInfo->GetHPHealedIfDefeatEnemy();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }
   iTemp = pkPromotionInfo->GetGoldenAgeValueFromKills();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense);
   }

   iTemp = pkPromotionInfo->GetGoldenAgeValueFromKills();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense);
   }

   iTemp = pkPromotionInfo->GetExtraWithdrawal();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorMobile) * 2;
   }

   iTemp = pkPromotionInfo->GetReconChange();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorRecon) * 5;
   }

   iTemp = pkPromotionInfo->IsFreePillageMoves();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }

   iTemp = pkPromotionInfo->IsHealOnPillage();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }

   iTemp = pkPromotionInfo->GetCargoChange();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorAir) * 5;
   }

   iTemp = pkPromotionInfo->GetRangeChange();
   if(isRanged())
   {
       iValue += (iTemp + iFlavorRanged) * 5;
   }

   iTemp = pkPromotionInfo->ChangeDamageValue();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorDefense) * 5;
   }

   iTemp = pkPromotionInfo->GetInterceptionCombatModifier();
   if(iTemp != 0 && canAirPatrol(NULL))
   {
       iExtra = GetInterceptionCombatModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetInterceptChanceChange();
   if (iTemp != 0)
   {
       iExtra = getInterceptChance();
       //AA units prioritize
       if (getDomainType() == DOMAIN_LAND && GetAirInterceptRange() > 0)
       {
           iExtra *= GetAirInterceptRange() * 2;
       }
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetAirInterceptRangeChange();
   if (iTemp != 0)
   {
       iExtra = GetExtraAirInterceptRange() * 5;
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetAirSweepCombatModifier();
   if(iTemp != 0 && canAirSweep())
   {
       iExtra = GetAirSweepCombatModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetEvasionChange();
   if (iTemp != 0)
   {
       iExtra = getExtraEvasion();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetNumInterceptionChange();
   if(iTemp != 0)
   {
       iValue += iTemp + iFlavorAir * 5;
   }

   iTemp = pkPromotionInfo->GetInterceptionDefenseDamageModifier();
   if(iTemp != 0 && getDomainType() == DOMAIN_AIR)
   {
       iExtra = GetInterceptionDefenseDamageModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetDefenseMod();
   if(iTemp != 0)
   {
       iExtra = getDefenseModifier();
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   for(iI = 0; iI < GC.getNumTerrainInfos(); iI++)
   {
       const TerrainTypes eTerrain = static_cast<TerrainTypes>(iI);
       CvTerrainInfo* pkTerrainInfo = GC.getTerrainInfo(eTerrain);
       if(pkTerrainInfo)
       {
           iTemp = pkPromotionInfo->GetTerrainAttackPercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraTerrainAttackPercent(eTerrain);
               if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorOffense;
           }

           iTemp = pkPromotionInfo->GetTerrainDefensePercent(iI);
           if(iTemp != 0)
           {
               iExtra =  getExtraTerrainDefensePercent(eTerrain);
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iExtra *= 2;
               }

               iValue += iTemp + iExtra + iFlavorDefense;
              
           }

           iTemp = pkPromotionInfo->GetTerrainDoubleHeal(iI);
           if (iTemp != 0)
           {
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iTemp *= 5;
               }
               iValue += iTemp + iFlavorDefense * 5;
           }

          

           if(pkPromotionInfo->GetTerrainDoubleMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue += iFlavorMobile;
               }
           }

#if defined(MOD_PROMOTIONS_HALF_MOVE)
           if(pkPromotionInfo->GetTerrainHalfMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue -= 4 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue -= 2 * (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue -= 2 * iFlavorMobile;
               }
           }

           if (pkPromotionInfo->GetTerrainExtraMove(iI))
           {
               if (AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile) * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
               else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile) * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
               else
               {
                   iValue += iFlavorMobile * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
           }
#endif
       }
   }

   for(iI = 0; iI < GC.getNumFeatureInfos(); iI++)
   {
       const FeatureTypes eFeature = static_cast<FeatureTypes>(iI);
       CvFeatureInfo* pkFeatureInfo = GC.getFeatureInfo(eFeature);
       if(pkFeatureInfo)
       {
           iTemp = pkPromotionInfo->GetFeatureAttackPercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraFeatureAttackPercent(eFeature);
               if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorOffense;
              
           }

           iTemp = pkPromotionInfo->GetFeatureDefensePercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraFeatureDefensePercent(eFeature);
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorDefense;
              
           }

           iTemp = pkPromotionInfo->GetFeatureDoubleHeal(iI);
           if (iTemp != 0)
           {
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iTemp *= 5;
               }
               iValue += iTemp + iFlavorDefense;
              
           }

           if(pkPromotionInfo->GetFeatureDoubleMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue += iFlavorMobile;
               }
           }

#if defined(MOD_PROMOTIONS_HALF_MOVE)
           if(pkPromotionInfo->GetFeatureHalfMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue -= 5 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue -= 3 * (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue -= 3 * iFlavorMobile;
               }
           }
           if (pkPromotionInfo->GetFeatureExtraMove(iI))
           {
               if (AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 3 * (iFlavorRecon + iFlavorMobile) * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
               else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += 2 * (iFlavorOffense + iFlavorMobile) * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
               else
               {
                   iValue += iFlavorMobile * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
           }
#endif
       }
   }

   int iOtherCombat = 0;
   int iSameCombat = 0;

   for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)
   {
       const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);
       CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);
       if(pkUnitCombatInfo)
       {
           if(eUnitCombat == getUnitCombatType())
           {
               iSameCombat += unitCombatModifier(eUnitCombat);
           }
           else
           {
               iOtherCombat += unitCombatModifier(eUnitCombat);
           }
       }
   }

   for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)
   {
       const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);
       CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);
       if(pkUnitCombatInfo)
       {
           iTemp = pkPromotionInfo->GetUnitCombatModifierPercent(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatModifierPercent(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatAttackModifier(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatDefenseModifier(iI);

           if (iTemp <= 0)
               continue;

           int iCombatWeight = 0;
           //Fighting their own kind
           if((UnitCombatTypes)iI == getUnitCombatType())
           {
               if(iSameCombat >= iOtherCombat)
               {
                   iCombatWeight = iFlavorOffense;//"axeman takes formation"
               }
               else
               {
                   iCombatWeight = iFlavorDefense;
               }
           }
           else
           {
               //fighting other kinds
               if(unitCombatModifier(eUnitCombat) >= 10)
               {
                   iCombatWeight = iFlavorDefense;//"spearman takes formation"
               }
               else
               {
                   iCombatWeight = iFlavorOffense;
               }
           }

           if((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_RANGED))
           {
               iValue += (iTemp * iCombatWeight) / 25;
           }
           else if((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_DEFENSE))
           {
               iValue += (iTemp * iCombatWeight) / 50;
           }
           else
           {
               iValue += (iTemp * iCombatWeight) / 100;
           }
       }
   }

   for(iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
   {
       iTemp = pkPromotionInfo->GetDomainModifierPercent(iI);
       if (iTemp <= 0)
           continue;

       iTemp += getExtraDomainModifier((DomainTypes)iI);

       if (DomainTypes(iI) == DOMAIN_SEA)
           iTemp *= iFlavorDefense;
       else if (DomainTypes(iI) == DOMAIN_AIR)
           iTemp *= iFlavorAir;
       else
           iTemp *= iFlavorOffense;

       iTemp /= 5;

       if ((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_RANGED))
       {
           iValue += (iTemp * 2);
       }
       else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_DEFENSE))
       {
           iValue += iTemp;
       }
       else if ((AI_getUnitAIType() == UNITAI_CITY_BOMBARD))
       {
           iValue += (iTemp / 2);
       }
       else
       {
           iValue += (iTemp / 2);
       }
   }

   return iValue;
}
 
Oboy...https://github.com/LoneGazebo/Community-Patch-DLL/issues/6762



Possible: Yes. Easy: No.

Code:
//   --------------------------------------------------------------------------------
void CvUnit::AI_promote()
{
   VALIDATE_OBJECT
   PromotionTypes eBestPromotion = NO_PROMOTION;
   int iBestValue = 0;
   int iNumValidPromotions = 0;

   for(int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
   {
       const PromotionTypes ePromotion(static_cast<PromotionTypes>(iI));

       CvPromotionEntry* pkPromotionEntry = GC.getPromotionInfo(ePromotion);

       if (pkPromotionEntry == NULL)
           continue;

       if(canPromote(ePromotion, -1))
       {
           iNumValidPromotions++;
           int iValue = AI_promotionValue(ePromotion);

           //value lower-level promotions a bit less.
           if (pkPromotionEntry->GetPrereqOrPromotion1() == NO_PROMOTION)
               iValue /= max(1, getLevel());

           for (int iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
           {
               const PromotionTypes eNextPromotion(static_cast<PromotionTypes>(iJ));
               CvPromotionEntry* pkNextPromotionEntry = GC.getPromotionInfo(eNextPromotion);
               if (!pkNextPromotionEntry)
                   continue;

               //for some basic forward planning, look at promotions this promotion unlocks and add those to the value.
               if (   pkNextPromotionEntry->GetPrereqOrPromotion1() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion2() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion3() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion4() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion5() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion6() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion7() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion8() == ePromotion
                   || pkNextPromotionEntry->GetPrereqOrPromotion9() == ePromotion)
               {
                   iValue += AI_promotionValue(eNextPromotion) / 2;
               }

           }
         
           if(GC.getLogging() && GC.getAILogging())
           {
               CvPromotionEntry* pkPromotionEntry = GC.getPromotionInfo(ePromotion);
               CvString strPromotionDesc = (pkPromotionEntry != NULL) ? pkPromotionEntry->GetDescription() : "Unknown Promotion";
               CvString strUnitName = getName();
               CvString strCivName = GET_PLAYER(getOwner()).getName();
               strPromotionDesc.Replace(' ', '_'); strPromotionDesc.Replace('(', '_'); strPromotionDesc.Replace(')', '_');
               strUnitName.Replace(' ', '_');
               strCivName.Replace(' ', '_');

               FILogFile* pLog = LOGFILEMGR.GetLog("PromotionLog.csv", FILogFile::kDontTimeStamp | FILogFile::kDontFlushOnWrite );
               CvString strLog;
               strLog.Format("%03d, %s, ", GC.getGame().getElapsedGameTurns(), strCivName.c_str());
               CvString strMsg;
               strMsg.Format("Promotion, %s, For %s, Ranged %d, Domain %d, Value: %d, Damage: %d", strPromotionDesc.c_str(), strUnitName.c_str(), isRanged() ? 1 : 0, getDomainType(), iValue, getDamage());

               strLog += strMsg;
               pLog->Msg(strLog);
           }

           //add some randomness
           if(iValue > 0)
               iValue += GC.getGame().getSmallFakeRandNum(iValue/2, plot()->GetPlotIndex() + iI);

           if(iValue > iBestValue)
           {
               iBestValue = iValue;
               eBestPromotion = ePromotion;
           }
       }
   }

   if(eBestPromotion != NO_PROMOTION)
   {
       promote(eBestPromotion, -1);

       CvPromotionEntry* pkPromoInfo = GC.getPromotionInfo(eBestPromotion);
       if (pkPromoInfo && GC.getLogging() && GC.getAILogging())
       {
           CvString strPromotionDesc = pkPromoInfo->GetDescription();
           CvString strUnitName = getName();
           CvString strCivName = GET_PLAYER(getOwner()).getName();
           strPromotionDesc.Replace(' ', '_'); strPromotionDesc.Replace('(', '_'); strPromotionDesc.Replace(')', '_');
           strUnitName.Replace(' ', '_');
           strCivName.Replace(' ', '_');

           FILogFile* pLog = LOGFILEMGR.GetLog("PromotionLog.csv", FILogFile::kDontTimeStamp | FILogFile::kDontFlushOnWrite );
           CvString strLog;
           strLog.Format("%03d, %s, ", GC.getGame().getElapsedGameTurns(), strCivName.c_str());
           CvString strMsg;
           strMsg.Format("--> Chosen Promotion, %s, Received by %s, ID %d, Lvl %d, XP %d, Ranged %d, Domain %d, X: %d, Y: %d, Damage: %d",
               strPromotionDesc.c_str(), strUnitName.c_str(), GetID(), getLevel(), getExperienceTimes100(), isRanged() ? 1 : 0, getDomainType(), getX(), getY(), getDamage());

           strLog += strMsg;
           pLog->Msg(strLog);
       }

       //do it again until we're done
       AI_promote();
   }
}

//   --------------------------------------------------------------------------------
// XXX make sure we include any new UnitAITypes...
int CvUnit::AI_promotionValue(PromotionTypes ePromotion)
{
   VALIDATE_OBJECT

   CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(ePromotion);
   if(pkPromotionInfo == NULL)
   {
       //This function really really really should not be called with an invalid promotion type.
       CvAssert(pkPromotionInfo);
       return 0;
   }

   int iValue = 0;

   int iTemp;
   int iExtra;
   int iI;

   bool bWarTimePromotion = plot()->getOwner() != NO_PLAYER && GET_PLAYER(plot()->getOwner()).IsAtWarWith(getOwner());

   // Get flavor info we can use
   CvFlavorManager* pFlavorMgr = GET_PLAYER(m_eOwner).GetFlavorManager();
   int iFlavorOffense = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_OFFENSE"))) * bWarTimePromotion ? 2 : 1;

   int iFlavorDefense = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_DEFENSE"))) * bWarTimePromotion ? 1 : 2;

   int iFlavorRanged = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RANGED")));

   int iFlavorRecon = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RECON")));

   int iFlavorMobile = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_MOBILE")));

   int iFlavorNaval = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_NAVAL")));

   int iFlavorAir = max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_AIR")));
   iFlavorAir += max(1, pFlavorMgr->GetIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_ANTIAIR")));

   // If we are damaged, insta heal is the way to go
   if(pkPromotionInfo->IsInstaHeal())
   {
       // Half health or less?
       if(getDamage() >= (GetMaxHitPoints() / 2))
       {
           iValue += 1000;   // Enough to lock this one up
       }
   }

#if defined(MOD_BALANCE_CORE_MILITARY_PROMOTION_ADVANCED)
   iTemp = pkPromotionInfo->GetCombatPercent();
   if(iTemp != 0)
   {
       iExtra = iTemp + getExtraCombatPercent();
       iValue += iExtra + iFlavorOffense + iFlavorDefense;
   }
   iTemp = pkPromotionInfo->GetRangedAttackModifier();
   if(iTemp != 0)
   {
       iExtra = iTemp + GetRangedAttackModifier();
       iValue += iExtra + iFlavorOffense;
   }

   if (pkPromotionInfo->IsGainsXPFromSpotting())
   {
       iExtra = iTemp + visibilityRange();
       iExtra = (iExtra * 5);

       iValue += iExtra + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetLandAirDefenseValue();
   if (iTemp != 0)
   {
       MilitaryAIStrategyTypes eStrategy = (MilitaryAIStrategyTypes)GC.getInfoTypeForString("MILITARYAISTRATEGY_NEED_AIR");
       if(GET_PLAYER(getOwner()).GetMilitaryAI()->IsUsingStrategy(eStrategy))
       {
           iTemp *= 2;
       }

       iTemp += getLandAirDefenseValue() + getUnitInfo().GetBaseLandAirDefense();

       iValue += iTemp + iFlavorDefense;
   }

   if (pkPromotionInfo->IsGainsXPFromPillaging())
   {
       iExtra = maxMoves();
       iTemp = (iExtra * 5);

       iValue += iTemp + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetGoodyHutYieldBonus();
   if (iTemp != 0 && !GC.getGame().isOption(GAMEOPTION_NO_GOODY_HUTS))
   {
       iExtra = maxMoves();
       iTemp += (iExtra * 5);

       iValue += iTemp + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetDamageReductionCityAssault();
   if (iTemp != 0)
   {
       iExtra = GetDamageReductionCityAssault();

       iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetPlagueChance();
   if (iTemp != 0)
   {
       iValue += iTemp + (iTemp/2) + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetPlagueIDImmunity();
   if (iTemp != 0)
   {
       iValue += iFlavorDefense + (iFlavorDefense/3);
   }

   iTemp = pkPromotionInfo->GetCaptureDefeatedEnemyChance();
   if (iTemp != 0)
   {
       iValue += iFlavorOffense + iTemp;
   }
#endif

   iTemp = pkPromotionInfo->GetOpenAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraOpenAttackPercent();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetOpenDefensePercent();
   if(iTemp != 0)
   {
       iExtra = getExtraOpenDefensePercent();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetOpenFromPercent();
   if (iTemp != 0)
   {
       iExtra = getExtraOpenFromPercent();
       if (noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetRoughFromPercent();
   if (iTemp != 0)
   {
       iExtra = getExtraRoughFromPercent();
       if (noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetRoughAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraRoughAttackPercent();
       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetRoughDefensePercent();
   if(iTemp != 0)
   {
       iExtra = getExtraRoughDefensePercent();

       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetOpenRangedAttackMod();
   if(iTemp != 0 && isRanged())
   {
       iExtra = getExtraOpenRangedAttackMod();
       if(noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorRanged;
   }

   iTemp = pkPromotionInfo->GetRoughRangedAttackMod();
   if(iTemp != 0 && isRanged())
   {
       iExtra = getExtraRoughRangedAttackMod();
       if(!noDefensiveBonus())
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorRanged;
   }

   iTemp = pkPromotionInfo->GetVisibilityChange();
   if((AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE))
   {
       iValue += iTemp + iFlavorRecon * 5;
   }
   else
   {
       iValue += iTemp + iFlavorMobile;
   }

   iTemp = pkPromotionInfo->GetCityAttackPercent();
   if(iTemp != 0)
   {
       iExtra = getExtraCityAttackPercent()/2;

       if (canMoveAfterAttacking() || AI_getUnitAIType() == UNITAI_CITY_BOMBARD)
           iValue += iTemp + iExtra + iFlavorOffense;
       else
           iValue += iTemp + iExtra/2 + iFlavorOffense/2;

       if(isRanged())
       {
           iValue += iTemp/2 * max(1, GetRange());
       }
   }

   iTemp = pkPromotionInfo->GetCityAttackPlunderModifier();
   if (iTemp != 0)
   {
       iExtra = GetCityAttackPlunderModifier();
       iValue += iTemp + iExtra + iFlavorOffense;
       if (isRanged())
       {
           iValue += iExtra * GetRange();

           if (canMoveAfterAttacking())
               iValue += iExtra;
       }
   }

   iTemp = pkPromotionInfo->GetCityDefensePercent();
   if(iTemp != 0)
   {
     
       iExtra = getExtraCityDefensePercent();
       if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAttackFortifiedMod();
   if(iTemp != 0)
   {
       if (isRanged())
       {
           iExtra = getExtraAttackFortifiedMod();
           iValue += iTemp + iExtra + iFlavorRanged;
       }
       else
       {
           iExtra = getExtraAttackFortifiedMod();
           iValue += iTemp + iExtra + iFlavorOffense;
       }
   }

   iTemp = pkPromotionInfo->GetHillsAttackPercent();
   if (iTemp != 0)
   {
       if (isRanged())
       {
           iExtra = getExtraHillsAttackPercent();
           iValue += iTemp + iExtra + iFlavorRanged;
       }
       else
       {
           iExtra = getExtraHillsAttackPercent();
           iValue += iTemp + iExtra + iFlavorOffense;
       }
   }
   iTemp = pkPromotionInfo->GetHillsDefensePercent();
   if (iTemp != 0)
   {
       iExtra = getExtraHillsDefensePercent();
       iValue += iTemp + iFlavorDefense + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetNearbyEnemyCombatMod();
   if (iTemp != 0)
   {
       iExtra = getNearbyEnemyCombatMod();
       iValue += iTemp + iExtra + iFlavorOffense;
   }
   iTemp = pkPromotionInfo->GetNearbyEnemyCombatRange();
   if (iTemp != 0)
   {
       iValue += iTemp + iFlavorOffense * 5;
   }

   iTemp = pkPromotionInfo->GetEnemyHealChange();
   if((AI_getUnitAIType() == UNITAI_PARADROP) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA))
   {
       iValue += iTemp + getExtraEnemyHeal() + iFlavorOffense * 2;
   }
   else
   {
       iValue += iTemp + getExtraEnemyHeal() + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetNeutralHealChange();
   if((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
   {
       iValue += iTemp + getExtraNeutralHeal() + iFlavorRecon * 2;
   }
   else
   {
       iValue += iTemp + getExtraNeutralHeal() + iFlavorRecon;
   }

   iTemp = pkPromotionInfo->GetFriendlyHealChange();
   if((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getExtraFriendlyHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getExtraFriendlyHeal() + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetSameTileHealChange();
   if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
       (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAdjacentTileHealChange();
   if((AI_getUnitAIType() == UNITAI_DEFENSE) ||
           (AI_getUnitAIType() == UNITAI_COUNTER))
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense * 2;
   }
   else
   {
       iValue += iTemp + getSameTileHeal() + iFlavorDefense;
   }

   if(pkPromotionInfo->IsAmphib())
   {
       if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_ATTACK))
       {
#if defined(MOD_BALANCE_CORE_MILITARY_PROMOTION_ADVANCED)
           iValue += iFlavorMobile * 2;
#else
           iValue += 40 + iFlavorOffense * 2;
#endif
       }
       else
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile;
#else
           iValue += 10 + iFlavorOffense * 2;
#endif
       }
   }

   if(pkPromotionInfo->IsRiver())
   {
       if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_ATTACK))
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile * 2;
#else
           iValue += 40 + iFlavorOffense * 2;
#endif
       }
       else
       {
#if defined(MOD_BALANCE_CORE_MILITARY)
           iValue += iFlavorMobile;
#else
           iValue += 10 + iFlavorOffense * 2;
#endif
       }
   }

   iTemp = pkPromotionInfo->GetRangedDefenseMod();
   if(iTemp != 0)
   {
       iExtra = getExtraRangedDefenseModifier();
       // likely not a ranged unit
       if((AI_getUnitAIType() == UNITAI_DEFENSE) || (AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_ATTACK))
       {
           iExtra *= 2;
       }
       // a slow unit
       if (maxMoves() / GC.getMOVE_DENOMINATOR() <= 2)
       {
           iExtra *= 2;
       }
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetOutsideFriendlyLandsModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorRecon * 2;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorRecon;
       }     
   }
   iTemp = pkPromotionInfo->GetFriendlyLandsModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   iTemp = pkPromotionInfo->GetCapitalDefenseModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   iTemp = pkPromotionInfo->GetFriendlyLandsAttackModifier();
   if (iTemp != 0)
   {
       if ((AI_getUnitAIType() == UNITAI_EXPLORE) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense;
       }
       else
       {
           iValue += iTemp + getOutsideFriendlyLandsModifier() + iFlavorDefense * 2;
       }
   }

   if(pkPromotionInfo->IsRangeAttackIgnoreLOS() && isRanged())
   {
       iValue += iFlavorRanged * 50;
   }

   iTemp = pkPromotionInfo->GetAttackWoundedMod();
   if(iTemp != 0)
   {
       iExtra = getExtraAttackWoundedMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAttackFullyHealedMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackFullyHealedMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorDefense;
   }

   iTemp = pkPromotionInfo->GetAttackAboveHealthMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackAboveHealthMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorDefense;
   }
   iTemp = pkPromotionInfo->GetAttackBelowHealthMod();
   if (iTemp != 0)
   {
       iExtra = getExtraAttackBelowHealthMod();
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetMaxHitPointsChange() * 4;
   if (iTemp != 0)
   {
       iExtra = getMaxHitPointsChange() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorDefense;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetMaxHitPointsModifier() * 2;
   if (iTemp != 0)
   {
       iExtra = getMaxHitPointsModifier() * 5;

       if (isRanged())
           iValue += iTemp + iExtra + iFlavorDefense;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetSplashDamage();
   if (iTemp != 0)
   {
       iExtra = getSplashDamage() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAdjacentMod();
   if (iTemp != 0)
   {
       iExtra = GetAdjacentModifier() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetAttackMod();
   if (iTemp != 0)
   {
       iExtra = getAttackModifier() * 5;
       if (isRanged())
           iValue += iTemp + iExtra + iFlavorRanged;
       else
           iValue += iTemp + iExtra + iFlavorOffense;
   }

   iTemp = pkPromotionInfo->GetFlankAttackModifier();
   if(iTemp > 0)
   {
       iExtra = iFlavorMobile * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }

   if (pkPromotionInfo->IsHealOutsideFriendly() && getDomainType() == DOMAIN_SEA)
   {
       iValue += iFlavorNaval * 5;
   }

   iTemp = pkPromotionInfo->GetMovesChange();
   if((AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ASSAULT_SEA) ||
           (AI_getUnitAIType() == UNITAI_SETTLER_SEA) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
   {
       iExtra = iFlavorMobile * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }
   else
   {
       iExtra = iFlavorOffense * maxMoves() / GC.getMOVE_DENOMINATOR();
       iExtra *= iTemp;
       iExtra /= 100;
       iValue += iExtra;
   }

   if(pkPromotionInfo->IsAlwaysHeal())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iFlavorOffense * 5;
       }
       else
       {
           iValue += iFlavorDefense * 5;
       }
   }

   if (pkPromotionInfo->IsNoSupply())
   {
       iValue += iFlavorMobile + iFlavorNaval;
   }

   if(pkPromotionInfo->IsBlitz())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += (iFlavorMobile + iFlavorOffense) * 5;
       }
       else
       {
           iValue += (iFlavorMobile + iFlavorOffense) * 5;
       }
   }

   iTemp = pkPromotionInfo->GetAdjacentEnemySapMovement();
   if (iTemp != 0)
   {
       iTemp += GetAdjacentEnemySapMovement();
       if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_COUNTER) ||
           (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   iTemp = pkPromotionInfo->IsIgnoreZOC();
   if (iTemp != 0)
   {
       iTemp += getMoves();
       if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
           (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
           (AI_getUnitAIType() == UNITAI_COUNTER) ||
           (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
           (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
           (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
           (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   if(pkPromotionInfo->IsCanMoveAfterAttacking())
   {
       if((AI_getUnitAIType() == UNITAI_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||
               (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||
               (AI_getUnitAIType() == UNITAI_COUNTER) ||
               (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
               (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
               (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
               (AI_getUnitAIType() == UNITAI_PARADROP))
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
       else
       {
           iValue += iTemp + (iFlavorMobile + iFlavorOffense);
       }
   }

   iTemp = pkPromotionInfo->GetExtraAttacks();
   if(iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }


   iTemp = pkPromotionInfo->GetHPHealedIfDefeatEnemy();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }
   iTemp = pkPromotionInfo->GetGoldenAgeValueFromKills();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense);
   }

   iTemp = pkPromotionInfo->GetGoldenAgeValueFromKills();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense);
   }

   iTemp = pkPromotionInfo->GetExtraWithdrawal();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorMobile) * 2;
   }

   iTemp = pkPromotionInfo->GetReconChange();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorRecon) * 5;
   }

   iTemp = pkPromotionInfo->IsFreePillageMoves();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }

   iTemp = pkPromotionInfo->IsHealOnPillage();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorOffense) * 5;
   }

   iTemp = pkPromotionInfo->GetCargoChange();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorAir) * 5;
   }

   iTemp = pkPromotionInfo->GetRangeChange();
   if(isRanged())
   {
       iValue += (iTemp + iFlavorRanged) * 5;
   }

   iTemp = pkPromotionInfo->ChangeDamageValue();
   if (iTemp != 0)
   {
       iValue += (iTemp + iFlavorDefense) * 5;
   }

   iTemp = pkPromotionInfo->GetInterceptionCombatModifier();
   if(iTemp != 0 && canAirPatrol(NULL))
   {
       iExtra = GetInterceptionCombatModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetInterceptChanceChange();
   if (iTemp != 0)
   {
       iExtra = getInterceptChance();
       //AA units prioritize
       if (getDomainType() == DOMAIN_LAND && GetAirInterceptRange() > 0)
       {
           iExtra *= GetAirInterceptRange() * 2;
       }
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetAirInterceptRangeChange();
   if (iTemp != 0)
   {
       iExtra = GetExtraAirInterceptRange() * 5;
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetAirSweepCombatModifier();
   if(iTemp != 0 && canAirSweep())
   {
       iExtra = GetAirSweepCombatModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetEvasionChange();
   if (iTemp != 0)
   {
       iExtra = getExtraEvasion();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetNumInterceptionChange();
   if(iTemp != 0)
   {
       iValue += iTemp + iFlavorAir * 5;
   }

   iTemp = pkPromotionInfo->GetInterceptionDefenseDamageModifier();
   if(iTemp != 0 && getDomainType() == DOMAIN_AIR)
   {
       iExtra = GetInterceptionDefenseDamageModifier();
       iValue += iTemp + iExtra + iFlavorAir;
   }

   iTemp = pkPromotionInfo->GetDefenseMod();
   if(iTemp != 0)
   {
       iExtra = getDefenseModifier();
       iValue += iTemp + iExtra + iFlavorDefense;
   }

   for(iI = 0; iI < GC.getNumTerrainInfos(); iI++)
   {
       const TerrainTypes eTerrain = static_cast<TerrainTypes>(iI);
       CvTerrainInfo* pkTerrainInfo = GC.getTerrainInfo(eTerrain);
       if(pkTerrainInfo)
       {
           iTemp = pkPromotionInfo->GetTerrainAttackPercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraTerrainAttackPercent(eTerrain);
               if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorOffense;
           }

           iTemp = pkPromotionInfo->GetTerrainDefensePercent(iI);
           if(iTemp != 0)
           {
               iExtra =  getExtraTerrainDefensePercent(eTerrain);
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iExtra *= 2;
               }

               iValue += iTemp + iExtra + iFlavorDefense;
             
           }

           iTemp = pkPromotionInfo->GetTerrainDoubleHeal(iI);
           if (iTemp != 0)
           {
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iTemp *= 5;
               }
               iValue += iTemp + iFlavorDefense * 5;
           }

         

           if(pkPromotionInfo->GetTerrainDoubleMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue += iFlavorMobile;
               }
           }

#if defined(MOD_PROMOTIONS_HALF_MOVE)
           if(pkPromotionInfo->GetTerrainHalfMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue -= 4 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue -= 2 * (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue -= 2 * iFlavorMobile;
               }
           }

           if (pkPromotionInfo->GetTerrainExtraMove(iI))
           {
               if (AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile) * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
               else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile) * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
               else
               {
                   iValue += iFlavorMobile * pkPromotionInfo->GetTerrainExtraMove(iI);
               }
           }
#endif
       }
   }

   for(iI = 0; iI < GC.getNumFeatureInfos(); iI++)
   {
       const FeatureTypes eFeature = static_cast<FeatureTypes>(iI);
       CvFeatureInfo* pkFeatureInfo = GC.getFeatureInfo(eFeature);
       if(pkFeatureInfo)
       {
           iTemp = pkPromotionInfo->GetFeatureAttackPercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraFeatureAttackPercent(eFeature);
               if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorOffense;
             
           }

           iTemp = pkPromotionInfo->GetFeatureDefensePercent(iI);
           if(iTemp != 0)
           {
               iExtra = getExtraFeatureDefensePercent(eFeature);
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iExtra *= 2;
               }
               iValue += iTemp + iExtra + iFlavorDefense;
             
           }

           iTemp = pkPromotionInfo->GetFeatureDoubleHeal(iI);
           if (iTemp != 0)
           {
               if ((AI_getUnitAIType() == UNITAI_DEFENSE) ||
                   (AI_getUnitAIType() == UNITAI_COUNTER))
               {
                   iTemp *= 5;
               }
               iValue += iTemp + iFlavorDefense;
             
           }

           if(pkPromotionInfo->GetFeatureDoubleMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 2 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue += iFlavorMobile;
               }
           }

#if defined(MOD_PROMOTIONS_HALF_MOVE)
           if(pkPromotionInfo->GetFeatureHalfMove(iI))
           {
               if(AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue -= 5 * (iFlavorRecon + iFlavorMobile);
               }
               else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue -= 3 * (iFlavorOffense + iFlavorMobile);
               }
               else
               {
                   iValue -= 3 * iFlavorMobile;
               }
           }
           if (pkPromotionInfo->GetFeatureExtraMove(iI))
           {
               if (AI_getUnitAIType() == UNITAI_EXPLORE)
               {
                   iValue += 3 * (iFlavorRecon + iFlavorMobile) * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
               else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))
               {
                   iValue += 2 * (iFlavorOffense + iFlavorMobile) * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
               else
               {
                   iValue += iFlavorMobile * pkPromotionInfo->GetFeatureExtraMove(iI);
               }
           }
#endif
       }
   }

   int iOtherCombat = 0;
   int iSameCombat = 0;

   for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)
   {
       const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);
       CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);
       if(pkUnitCombatInfo)
       {
           if(eUnitCombat == getUnitCombatType())
           {
               iSameCombat += unitCombatModifier(eUnitCombat);
           }
           else
           {
               iOtherCombat += unitCombatModifier(eUnitCombat);
           }
       }
   }

   for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)
   {
       const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);
       CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);
       if(pkUnitCombatInfo)
       {
           iTemp = pkPromotionInfo->GetUnitCombatModifierPercent(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatModifierPercent(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatAttackModifier(iI);
           iTemp += pkPromotionInfo->GetCombatModPerAdjacentUnitCombatDefenseModifier(iI);

           if (iTemp <= 0)
               continue;

           int iCombatWeight = 0;
           //Fighting their own kind
           if((UnitCombatTypes)iI == getUnitCombatType())
           {
               if(iSameCombat >= iOtherCombat)
               {
                   iCombatWeight = iFlavorOffense;//"axeman takes formation"
               }
               else
               {
                   iCombatWeight = iFlavorDefense;
               }
           }
           else
           {
               //fighting other kinds
               if(unitCombatModifier(eUnitCombat) >= 10)
               {
                   iCombatWeight = iFlavorDefense;//"spearman takes formation"
               }
               else
               {
                   iCombatWeight = iFlavorOffense;
               }
           }

           if((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_RANGED))
           {
               iValue += (iTemp * iCombatWeight) / 25;
           }
           else if((AI_getUnitAIType() == UNITAI_ATTACK) ||
                   (AI_getUnitAIType() == UNITAI_DEFENSE))
           {
               iValue += (iTemp * iCombatWeight) / 50;
           }
           else
           {
               iValue += (iTemp * iCombatWeight) / 100;
           }
       }
   }

   for(iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
   {
       iTemp = pkPromotionInfo->GetDomainModifierPercent(iI);
       if (iTemp <= 0)
           continue;

       iTemp += getExtraDomainModifier((DomainTypes)iI);

       if (DomainTypes(iI) == DOMAIN_SEA)
           iTemp *= iFlavorDefense;
       else if (DomainTypes(iI) == DOMAIN_AIR)
           iTemp *= iFlavorAir;
       else
           iTemp *= iFlavorOffense;

       iTemp /= 5;

       if ((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_RANGED))
       {
           iValue += (iTemp * 2);
       }
       else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_DEFENSE))
       {
           iValue += iTemp;
       }
       else if ((AI_getUnitAIType() == UNITAI_CITY_BOMBARD))
       {
           iValue += (iTemp / 2);
       }
       else
       {
           iValue += (iTemp / 2);
       }
   }

   return iValue;
}

Thanks @Recursive
City Assault is a recently designed promotion that is key to many players taking cities. The AI being unable to select it is certainly a handicap.
 
Top Bottom