Hooks
static bool BeforeCvUnit_AI_promotionValue(CvUnit* self, PromotionTypes ePromotion, int& result);static void AfterCvUnit_AI_promotionValue(CvUnit* self, PromotionTypes ePromotion, int& result);static int ReplaceCvUnit_AI_promotionValue(int (*original)(CvUnit*, PromotionTypes), CvUnit* self, PromotionTypes ePromotion);CivRegisterBefore<CivHooks::CvUnit_AI_promotionValue>(host, &BeforeCvUnit_AI_promotionValue);CivRegisterAfter<CivHooks::CvUnit_AI_promotionValue>(host, &AfterCvUnit_AI_promotionValue);CivRegisterReplace<CivHooks::CvUnit_AI_promotionValue>(host, &ReplaceCvUnit_AI_promotionValue);
Code
24428// XXX make sure we include any new UnitAITypes...24429int CvUnit::AI_promotionValue(PromotionTypes ePromotion)24430{24431 VALIDATE_OBJECT2443224433 CvPromotionEntry* pkPromotionInfo = GC.getPromotionInfo(ePromotion);24434 if(pkPromotionInfo == NULL)24435 {24436 //This function really really really should not be called with an invalid promotion type.24437 CvAssert(pkPromotionInfo);24438 return 0;24439 }2444024441 int iValue = 0;2444224443 int iTemp;24444#if defined(MOD_AI_SMART_V3)24445 int lowPriority = 100;24446 int mediumPriority = 110;24447 int highPriority = 120;24448 int absolutePriority = 200;24449 int plotPercents;24450 int doubleMove;24451#endif24452 int iExtra;24453 int iI;2445424455 // Get flavor info we can use24456#if defined(MOD_BUGFIX_USE_GETTERS)24457 CvFlavorManager* pFlavorMgr = GET_MY_PLAYER().GetFlavorManager();24458#else24459 CvFlavorManager* pFlavorMgr = GET_PLAYER(m_eOwner).GetFlavorManager();24460#endif24461 int iFlavorOffense = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_OFFENSE"));24462 int iFlavorDefense = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_DEFENSE"));24463 int iFlavorRanged = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RANGED"));24464 int iFlavorRecon = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_RECON"));24465 int iFlavorMobile = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_MOBILE"));24466 int iFlavorNaval = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_NAVAL"));24467 int iFlavorAir = pFlavorMgr->GetPersonalityIndividualFlavor((FlavorTypes)GC.getInfoTypeForString("FLAVOR_AIR"));2446824469#if defined(MOD_AI_SMART_V3)24470 if (MOD_AI_SMART_V3)24471 {24472 int iFlavorOffDef = (iFlavorOffense + iFlavorDefense) / 2;2447324474 // If we are damaged, insta heal is the way to go24475 if(pkPromotionInfo->IsInstaHeal())24476 {24477 // Half health or less?24478 if(getDamage() >= (GetMaxHitPoints() / 2))24479 {24480 iValue = absolutePriority; // Enough to lock this one up24481 }24482 else24483 {24484 // Give insta-heal a very low priority otherwise.24485 iValue = GetPromotionValue(pkPromotionInfo->IsInstaHeal() ? 1 : 0, -20, 0, lowPriority);24486 }24487 }2448824489 // High priority promotions24490 if (iValue == 0)24491 {24492 iValue = GetPromotionValue(pkPromotionInfo->GetExtraAttacks(), 0, iFlavorOffense, highPriority);24493 }2449424495 if (iValue == 0)24496 {24497 iValue = GetPromotionValue(pkPromotionInfo->IsAlwaysHeal() ? 1 : 0, 0, iFlavorDefense, highPriority);24498 }2449924500 if (iValue == 0)24501 {24502 iValue = GetPromotionValue(pkPromotionInfo->IsBlitz() ? 1 : 0, 0, iFlavorMobile, highPriority);24503 }2450424505 if (iValue == 0)24506 {24507 iValue = GetPromotionValue(pkPromotionInfo->GetRangeChange(), 0, iFlavorRanged, getDomainType() == DOMAIN_AIR ? mediumPriority : highPriority);24508 }2450924510 if (iValue == 0)24511 {24512 plotPercents = 0;24513 doubleMove = 0;2451424515 for(iI = 0; iI < GC.getNumTerrainInfos(); iI++)24516 {24517 const TerrainTypes eTerrain = static_cast<TerrainTypes>(iI);24518 CvTerrainInfo* pkTerrainInfo = GC.getTerrainInfo(eTerrain);2451924520 if(pkTerrainInfo)24521 {24522 plotPercents += pkPromotionInfo->GetTerrainAttackPercent(iI) + pkPromotionInfo->GetTerrainDefensePercent(iI);24523 doubleMove += pkPromotionInfo->GetTerrainDoubleMove(iI) ? 1 : 0;24524 }24525 }2452624527 iValue = GetPromotionValue(doubleMove, 0, iFlavorMobile, highPriority);2452824529 if (iValue == 0)24530 {24531 iValue = GetPromotionValue(plotPercents, 0, iFlavorOffDef, mediumPriority);24532 }24533 }2453424535 if (iValue == 0)24536 {24537 plotPercents = 0;24538 doubleMove = 0;2453924540 for(iI = 0; iI < GC.getNumFeatureInfos(); iI++)24541 {24542 const FeatureTypes eFeature = static_cast<FeatureTypes>(iI);24543 CvFeatureInfo* pkFeatureInfo = GC.getFeatureInfo(eFeature);2454424545 if(pkFeatureInfo)24546 {24547 plotPercents += pkPromotionInfo->GetFeatureAttackPercent(iI) + pkPromotionInfo->GetFeatureDefensePercent(iI);24548 doubleMove += pkPromotionInfo->GetFeatureDoubleMove(iI) ? 1 : 0;24549 }24550 }2455124552 iValue = GetPromotionValue(doubleMove, 0, iFlavorMobile, highPriority);2455324554 if (iValue == 0)24555 {24556 iValue = GetPromotionValue(plotPercents, 0, iFlavorOffDef, mediumPriority);24557 }24558 }2455924560 // Medium priority promotions24561 if (iValue == 0)24562 {24563 iTemp = pkPromotionInfo->GetEnemyHealChange() + pkPromotionInfo->GetNeutralHealChange() + pkPromotionInfo->GetFriendlyHealChange() + pkPromotionInfo->GetAdjacentTileHealChange();24564 iValue = GetPromotionValue(iTemp, getDefenseModifier(), iFlavorDefense, mediumPriority);24565 }2456624567 if (iValue == 0)24568 {24569 iValue = GetPromotionValue(pkPromotionInfo->IsRangeAttackIgnoreLOS() ? 1 : 0, 0, iFlavorRanged, mediumPriority);24570 }2457124572 if (iValue == 0)24573 {24574 iValue = GetPromotionValue(pkPromotionInfo->GetAttackWoundedMod(), getExtraAttackWoundedMod(), iFlavorOffense, mediumPriority);24575 }2457624577 if (iValue == 0)24578 {24579 iValue = GetPromotionValue(pkPromotionInfo->GetMovesChange(), 0, iFlavorMobile, mediumPriority);24580 }2458124582 if (iValue == 0)24583 {24584 iValue = GetPromotionValue(pkPromotionInfo->GetAttackFortifiedMod(), getExtraAttackFortifiedMod(), iFlavorOffense, mediumPriority);24585 }2458624587 if (iValue == 0)24588 {24589 iValue = GetPromotionValue(pkPromotionInfo->IsCanMoveAfterAttacking() ? 1 : 0, 0, iFlavorMobile, mediumPriority);24590 }2459124592 if (iValue == 0)24593 {24594 iValue = GetPromotionValue(pkPromotionInfo->GetNumInterceptionChange(), 0, iFlavorDefense, mediumPriority);24595 }2459624597 if (iValue == 0)24598 {24599 iValue = GetPromotionValue(getDomainType() == DOMAIN_AIR ? pkPromotionInfo->GetInterceptionDefenseDamageModifier() : 0, GetInterceptionDefenseDamageModifier(), iFlavorAir, mediumPriority);24600 }2460124602 if (iValue == 0)24603 {24604 iValue = GetPromotionValue(pkPromotionInfo->GetCargoChange(), 0, iFlavorNaval, mediumPriority);24605 }2460624607 if (iValue == 0)24608 {24609 iValue = GetPromotionValue(pkPromotionInfo->GetAttackMod(), getDomainType() == DOMAIN_SEA ? 1 : 0, iFlavorMobile, mediumPriority);24610 }2461124612 if (iValue == 0)24613 {24614 iValue = GetPromotionValue(pkPromotionInfo->GetRangedDefenseMod(), getExtraRangedDefenseModifier(), iFlavorDefense, mediumPriority);24615 }2461624617 // Low priority promotions2461824619 if (iValue == 0)24620 {24621 iValue = GetPromotionValue(pkPromotionInfo->GetCityAttackPercent(), getDomainType() == DOMAIN_SEA ? 1 : getExtraCityAttackPercent(), iFlavorOffense, lowPriority);24622 }2462324624 if (iValue == 0)24625 {24626 iValue = GetPromotionValue(pkPromotionInfo->GetCityDefensePercent(), getExtraCityDefensePercent(), iFlavorDefense, lowPriority);24627 }2462824629 if (iValue == 0)24630 {24631 iTemp = pkPromotionInfo->GetOpenAttackPercent() + pkPromotionInfo->GetOpenDefensePercent();24632 iValue = GetPromotionValue(iTemp, getExtraOpenAttackPercent() + getExtraOpenDefensePercent() + (canMoveAfterAttacking() ? 1 : 0), iFlavorOffDef, lowPriority);24633 }2463424635 if (iValue == 0)24636 {24637 iTemp = pkPromotionInfo->GetRoughAttackPercent() + pkPromotionInfo->GetRoughDefensePercent();24638 iValue = GetPromotionValue(iTemp, getExtraRoughAttackPercent() + getExtraRoughDefensePercent(), iFlavorOffDef, lowPriority);24639 }2464024641 if (iValue == 0)24642 {24643 iValue = GetPromotionValue(pkPromotionInfo->GetOpenRangedAttackMod(), getExtraOpenRangedAttackMod(), iFlavorRanged, lowPriority);24644 }2464524646 if (iValue == 0)24647 {24648 iValue = GetPromotionValue(pkPromotionInfo->GetRoughRangedAttackMod(), getExtraRoughRangedAttackMod(), iFlavorRanged, lowPriority);24649 }2465024651 if (iValue == 0)24652 {24653 iValue = GetPromotionValue(pkPromotionInfo->GetVisibilityChange(), 0, iFlavorRecon, lowPriority);24654 }2465524656 if (iValue == 0)24657 {24658 iValue = GetPromotionValue((pkPromotionInfo->IsAmphib() || pkPromotionInfo->IsRiver()) ? 1 : 0, 0, iFlavorOffense, lowPriority);24659 }2466024661 if (iValue == 0)24662 {24663 iValue = GetPromotionValue(pkPromotionInfo->GetDefenseMod(), getDefenseModifier(), iFlavorDefense, lowPriority);24664 }2466524666 if (iValue == 0)24667 {24668 iValue = GetPromotionValue(pkPromotionInfo->GetFlankAttackModifier(), maxMoves() > 2 ? 1 : 0, iFlavorMobile, lowPriority);24669 }2467024671 if (iValue == 0)24672 {24673 iTemp = (GC.getPromotionInfo(ePromotion)->IsHealOutsideFriendly() && getDomainType() == DOMAIN_SEA) ? 1 : 0;24674 iValue = GetPromotionValue(iTemp, 0, iFlavorNaval, mediumPriority);24675 }2467624677 if (iValue == 0)24678 {24679 iValue = GetPromotionValue(canAirPatrol(NULL) ? pkPromotionInfo->GetInterceptionCombatModifier() : 0, GetInterceptionCombatModifier(), iFlavorAir, lowPriority);24680 }2468124682 if (iValue == 0)24683 {24684 iValue = GetPromotionValue(canAirSweep() ? pkPromotionInfo->GetAirSweepCombatModifier() : 0, GetAirSweepCombatModifier(), iFlavorAir, lowPriority);24685 }2468624687 if (iValue == 0)24688 {24689 iTemp = 0;2469024691 for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)24692 {24693 const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);24694 CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);2469524696 if(pkUnitCombatInfo)24697 {24698 iTemp += pkPromotionInfo->GetUnitCombatModifierPercent(iI);24699 }24700 }2470124702 iValue = GetPromotionValue(iTemp, 0, iFlavorOffDef, lowPriority);24703 }2470424705 if (iValue == 0)24706 {24707 iTemp = 0;2470824709 for(iI = 0; iI < NUM_DOMAIN_TYPES; iI++)24710 {24711 iTemp += pkPromotionInfo->GetDomainModifierPercent(iI);24712 }2471324714 iValue = GetPromotionValue(iTemp, getDomainType() == DOMAIN_SEA ? 1 : 0, iFlavorOffDef, lowPriority);24715 }2471624717 // Unknown promotion? Always give at least a random priority with some flavor24718 if (iValue == 0)24719 {24720 iTemp = lowPriority + GC.getGame().getJonRandNum(20, "AI Promote Unknown");24721 iValue = GetPromotionValue(1, 0, iFlavorOffDef, iTemp);2472224723 // Logging to keep track on promotions not handled on the script.24724 if(GC.getLogging() && GC.getAILogging())24725 {24726 CvString szMsg;24727 szMsg.Format("UNKNOWN PROMOTION %s.", getName().GetCString());24728 GET_PLAYER(m_eOwner).GetTacticalAI()->LogTacticalMessage(szMsg, true /*bSkipLogDominanceZone*/);24729 }24730 }2473124732 //AMS: Higher random from original 15 to 2524733 iValue += GC.getGame().getJonRandNum(25, "AI Promote");24734 }24735 else24736 {24737#endif24738 // If we are damaged, insta heal is the way to go24739 if(pkPromotionInfo->IsInstaHeal())24740 {24741 // Half health or less?24742 if(getDamage() >= (GetMaxHitPoints() / 2))24743 {24744 iValue += 1000; // Enough to lock this one up24745 }24746 }2474724748 iTemp = pkPromotionInfo->GetOpenAttackPercent();24749 if(iTemp != 0)24750 {24751 iExtra = getExtraOpenAttackPercent();24752 iTemp *= (100 + iExtra * 2);24753 iTemp /= 100;24754 if(noDefensiveBonus())24755 {24756 iTemp *= 2;24757 }24758 iValue += iTemp + iFlavorOffense * 2;24759 }2476024761 iTemp = pkPromotionInfo->GetOpenDefensePercent();24762 if(iTemp != 0)24763 {24764 iExtra = getExtraOpenDefensePercent() * 2;24765 iTemp *= (100 + iExtra);24766 iTemp /= 100;24767 if(noDefensiveBonus())24768 {24769 iTemp *= 2;24770 }24771 iValue += iTemp + iFlavorDefense * 2;24772 }2477324774 iTemp = pkPromotionInfo->GetRoughAttackPercent();24775 if(iTemp != 0)24776 {24777 iExtra = getExtraRoughAttackPercent();24778 iTemp *= (100 + iExtra * 2);24779 iTemp /= 100;24780 if(!noDefensiveBonus())24781 {24782 iTemp *= 2;24783 }24784 iValue += iTemp + iFlavorOffense * 2;24785 }2478624787 iTemp = pkPromotionInfo->GetRoughDefensePercent();24788 if(iTemp != 0)24789 {24790 iExtra = getExtraRoughDefensePercent() * 2;24791 iTemp *= (100 + iExtra);24792 iTemp /= 100;24793 if(!noDefensiveBonus())24794 {24795 iTemp *= 2;24796 }24797 iValue += iTemp + iFlavorDefense * 2;24798 }2479924800 iTemp = pkPromotionInfo->GetOpenRangedAttackMod();24801 if(iTemp != 0 && isRanged())24802 {24803 iExtra = getExtraOpenRangedAttackMod();24804 iTemp *= (100 + iExtra * 2);24805 iTemp /= 100;24806 if(noDefensiveBonus())24807 {24808 iTemp *= 2;24809 }24810 iValue += iTemp + iFlavorRanged * 2;24811 }2481224813 iTemp = pkPromotionInfo->GetRoughRangedAttackMod();24814 if(iTemp != 0 && isRanged())24815 {24816 iExtra = getExtraRoughRangedAttackMod() * 2;24817 iTemp *= (100 + iExtra);24818 iTemp /= 100;24819 if(!noDefensiveBonus())24820 {24821 iTemp *= 2;24822 }24823 iValue += iTemp + iFlavorRanged * 2;24824 }2482524826 iTemp = pkPromotionInfo->GetVisibilityChange();24827 if((AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||24828 (AI_getUnitAIType() == UNITAI_EXPLORE))24829 {24830 iValue += iTemp * (50 + iFlavorRecon * 2);24831 }24832 else24833 {24834 iValue += iTemp * (10 + iFlavorRecon * 2);24835 }2483624837 iTemp = pkPromotionInfo->GetCityAttackPercent();24838 if(iTemp != 0)24839 {24840 iExtra = getExtraCityAttackPercent();24841 iTemp *= (100 + iExtra * 2);24842 iTemp /= 100;24843 iValue += iTemp + iFlavorOffense * 2;24844 if(isRanged())24845 {24846 iValue += iFlavorRanged * 2;24847 }24848 }2484924850 iTemp = pkPromotionInfo->GetCityDefensePercent();24851 if(iTemp != 0)24852 {24853 iExtra = getExtraCityDefensePercent();24854 iTemp *= (100 + iExtra * 2);24855 iTemp /= 100;24856 iValue += iTemp + iFlavorDefense * 2;24857 if((AI_getUnitAIType() == UNITAI_DEFENSE) ||24858 (AI_getUnitAIType() == UNITAI_COUNTER))24859 {24860 iValue *= 2;24861 }24862 }2486324864 iTemp = pkPromotionInfo->GetAttackFortifiedMod();24865 if(iTemp != 0 && isRanged())24866 {24867 iExtra = getExtraAttackFortifiedMod() * 2;24868 iTemp *= (100 + iExtra);24869 iTemp /= 100;24870 iValue += iTemp + (iFlavorOffense * iFlavorRanged) * 2;24871 }2487224873 iTemp = pkPromotionInfo->GetEnemyHealChange();24874 if((AI_getUnitAIType() == UNITAI_PARADROP) ||24875 (AI_getUnitAIType() == UNITAI_PIRATE_SEA))24876 {24877 iValue += iTemp * (50 + iFlavorOffense * 2);24878 }24879 else24880 {24881 iValue += iTemp * (10 + iFlavorOffense * 2);24882 }2488324884 iTemp = pkPromotionInfo->GetNeutralHealChange();24885 if((AI_getUnitAIType() == UNITAI_EXPLORE) ||24886 (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))24887 {24888 iValue += iTemp * (40 + iFlavorRecon * 2);24889 }24890 else24891 {24892 iValue += iTemp * (10 + iFlavorRecon * 2);24893 }2489424895 iTemp = pkPromotionInfo->GetFriendlyHealChange();24896 if((AI_getUnitAIType() == UNITAI_DEFENSE) ||24897 (AI_getUnitAIType() == UNITAI_COUNTER))24898 {24899 iValue += iTemp * (20 + iFlavorDefense * 2);24900 }24901 else24902 {24903 iValue += iTemp * (10 + iFlavorDefense * 2);24904 }2490524906 iTemp = pkPromotionInfo->GetAdjacentTileHealChange();24907 if((AI_getUnitAIType() == UNITAI_DEFENSE) ||24908 (AI_getUnitAIType() == UNITAI_COUNTER))24909 {24910 iValue += iTemp * (40 + iFlavorDefense * 2);24911 }24912 else24913 {24914 iValue += iTemp * (10 + iFlavorDefense * 2);24915 }2491624917 if(pkPromotionInfo->IsAmphib())24918 {24919 if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||24920 (AI_getUnitAIType() == UNITAI_ATTACK))24921 {24922 iValue += 40 + iFlavorOffense * 2;24923 }24924 else24925 {24926 iValue += 10 + iFlavorOffense * 2;24927 }24928 }2492924930 if(pkPromotionInfo->IsRiver())24931 {24932 if((AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||24933 (AI_getUnitAIType() == UNITAI_ATTACK))24934 {24935 iValue += 40 + iFlavorOffense * 2;24936 }24937 else24938 {24939 iValue += 10 + iFlavorOffense * 2;24940 }24941 }2494224943 iTemp = pkPromotionInfo->GetRangedDefenseMod();24944 if(iTemp != 0)24945 {24946 iExtra = getExtraRangedDefenseModifier() * 2;24947 iTemp *= (100 + iExtra);24948 iTemp /= 100;24949 // likely not a ranged unit24950 if((AI_getUnitAIType() == UNITAI_DEFENSE) || (AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_ATTACK))24951 {24952 iTemp *= 2;24953 }24954 // a slow unit24955 if (maxMoves() / GC.getMOVE_DENOMINATOR() <= 2)24956 {24957 iTemp *= 2;24958 }24959 iValue += iTemp + iFlavorDefense * 2;24960 }2496124962 if(pkPromotionInfo->IsRangeAttackIgnoreLOS() && isRanged())24963 {24964 iValue += 75 + iFlavorRanged * 2;24965 }2496624967 iTemp = pkPromotionInfo->GetAttackWoundedMod();24968 if(iTemp != 0 && isRanged())24969 {24970 iExtra = getExtraAttackWoundedMod() * 2;24971 iTemp *= (100 + iExtra);24972 iTemp /= 100;24973 iValue += iTemp + (iFlavorOffense * iFlavorRanged) * 2;24974 }2497524976 iTemp = pkPromotionInfo->GetFlankAttackModifier();24977 if(iTemp > 0)24978 {24979 iExtra = (2 * iFlavorOffense + iFlavorMobile) * maxMoves() / GC.getMOVE_DENOMINATOR();24980 iExtra *= iTemp;24981 iExtra /= 100;24982 iValue += iExtra;24983 }2498424985 if(GC.getPromotionInfo(ePromotion)->IsHealOutsideFriendly() && getDomainType() == DOMAIN_SEA)24986 {24987 iValue += 50 + iFlavorNaval * 2;24988 }2498924990 iTemp = pkPromotionInfo->GetMovesChange();24991 if((AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||24992 (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||24993 (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||24994 (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||24995 (AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||24996 (AI_getUnitAIType() == UNITAI_ASSAULT_SEA) ||24997 (AI_getUnitAIType() == UNITAI_SETTLER_SEA) ||24998 (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||24999 (AI_getUnitAIType() == UNITAI_ATTACK) ||25000 (AI_getUnitAIType() == UNITAI_PARADROP))25001 {25002 iValue += iTemp * (50 + iFlavorMobile * 2);25003 }25004 else25005 {25006 iValue += iTemp * (30 + iFlavorMobile * 2);25007 }2500825009 if(pkPromotionInfo->IsAlwaysHeal())25010 {25011 if((AI_getUnitAIType() == UNITAI_ATTACK) ||25012 (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||25013 (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||25014 (AI_getUnitAIType() == UNITAI_COUNTER) ||25015 (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||25016 (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||25017 (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||25018 (AI_getUnitAIType() == UNITAI_PARADROP))25019 {25020 iValue += 50 + iFlavorMobile * 2;25021 }25022 else25023 {25024 iValue += 30 + iFlavorMobile * 2;25025 }25026 }2502725028 if(pkPromotionInfo->IsBlitz())25029 {25030 if((AI_getUnitAIType() == UNITAI_ATTACK) ||25031 (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||25032 (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||25033 (AI_getUnitAIType() == UNITAI_COUNTER) ||25034 (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||25035 (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||25036 (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||25037 (AI_getUnitAIType() == UNITAI_PARADROP))25038 {25039 iValue += 50 + (iFlavorMobile + iFlavorOffense) * 2;25040 }25041 else25042 {25043 iValue += 20 + (iFlavorMobile + iFlavorOffense) * 2;25044 }25045 }2504625047 if(pkPromotionInfo->IsCanMoveAfterAttacking())25048 {25049 if((AI_getUnitAIType() == UNITAI_ATTACK) ||25050 (AI_getUnitAIType() == UNITAI_CITY_BOMBARD) ||25051 (AI_getUnitAIType() == UNITAI_FAST_ATTACK) ||25052 (AI_getUnitAIType() == UNITAI_COUNTER) ||25053 (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||25054 (AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||25055 (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||25056 (AI_getUnitAIType() == UNITAI_PARADROP))25057 {25058 iValue += 30 + (iFlavorMobile + iFlavorOffense) * 2;25059 }25060 else25061 {25062 iValue += 10 + (iFlavorMobile + iFlavorOffense) * 2;25063 }25064 }2506525066 iTemp = pkPromotionInfo->GetExtraAttacks();25067 if(iTemp != 0)25068 {25069 iValue += (iTemp * 200);25070 }2507125072 iTemp = pkPromotionInfo->GetRangeChange();25073 if(isRanged())25074 {25075 iValue += (iTemp * 200);25076 }2507725078 iTemp = pkPromotionInfo->GetInterceptionCombatModifier();25079 if(iTemp != 0 && canAirPatrol(NULL))25080 {25081 iExtra = GetInterceptionCombatModifier() * 2;25082 iTemp *= (100 + iExtra);25083 iTemp /= 100;25084 iValue += iTemp + iFlavorAir * 2;25085 }2508625087 iTemp = pkPromotionInfo->GetAirSweepCombatModifier();25088 if(iTemp != 0 && canAirSweep())25089 {25090 iExtra = GetAirSweepCombatModifier() * 2;25091 iTemp *= (100 + iExtra);25092 iTemp /= 100;25093 iValue += iTemp + iFlavorAir * 2;25094 }2509525096 iTemp = pkPromotionInfo->GetNumInterceptionChange();25097 if(iTemp != 0)25098 {25099 iValue += (iTemp * 200);25100 }2510125102 iTemp = pkPromotionInfo->GetInterceptionDefenseDamageModifier();25103 if(iTemp != 0 && getDomainType() == DOMAIN_AIR)25104 {25105 iExtra = GetInterceptionDefenseDamageModifier() * 2;25106 iTemp *= (100 + iExtra);25107 iTemp /= 100;25108 iValue += iTemp + iFlavorAir * 2;25109 }2511025111 iTemp = pkPromotionInfo->GetDefenseMod();25112 if(iTemp != 0)25113 {25114 iExtra = getDefenseModifier() * 2;25115 iTemp *= (100 + iExtra);25116 iTemp /= 100;25117 iValue += iTemp + iFlavorDefense * 2;25118 }2511925120 for(iI = 0; iI < GC.getNumTerrainInfos(); iI++)25121 {25122 const TerrainTypes eTerrain = static_cast<TerrainTypes>(iI);25123 CvTerrainInfo* pkTerrainInfo = GC.getTerrainInfo(eTerrain);25124 if(pkTerrainInfo)25125 {25126 iTemp = pkPromotionInfo->GetTerrainAttackPercent(iI);25127 if(iTemp != 0)25128 {25129 iExtra = getExtraTerrainAttackPercent(eTerrain);25130 iTemp *= (100 + iExtra * 2);25131 iTemp /= 100;25132 iValue += iTemp + iFlavorOffense * 2;25133 if((AI_getUnitAIType() == UNITAI_ATTACK) ||25134 (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25135 {25136 iValue *= 2;25137 }25138 }2513925140 iTemp = pkPromotionInfo->GetTerrainDefensePercent(iI);25141 if(iTemp != 0)25142 {25143 iExtra = getExtraTerrainDefensePercent(eTerrain);25144 iTemp *= (100 + iExtra);25145 iTemp /= 100;25146 iValue += iTemp + iFlavorDefense * 2;25147 if((AI_getUnitAIType() == UNITAI_DEFENSE) ||25148 (AI_getUnitAIType() == UNITAI_COUNTER))25149 {25150 iValue *= 2;25151 }25152 }2515325154 if(pkPromotionInfo->GetTerrainDoubleMove(iI))25155 {25156 if(AI_getUnitAIType() == UNITAI_EXPLORE)25157 {25158 iValue += 5 * (iFlavorRecon + iFlavorMobile);25159 }25160 else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25161 {25162 iValue += 3 * (iFlavorOffense + iFlavorMobile);25163 }25164 else25165 {25166 iValue += 3 * iFlavorMobile;25167 }25168 }2516925170#if defined(MOD_PROMOTIONS_HALF_MOVE)25171 if(pkPromotionInfo->GetTerrainHalfMove(iI))25172 {25173 if(AI_getUnitAIType() == UNITAI_EXPLORE)25174 {25175 iValue -= 5 * (iFlavorRecon + iFlavorMobile);25176 }25177 else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25178 {25179 iValue -= 3 * (iFlavorOffense + iFlavorMobile);25180 }25181 else25182 {25183 iValue -= 3 * iFlavorMobile;25184 }25185 }25186#endif25187 }25188 }2518925190 for(iI = 0; iI < GC.getNumFeatureInfos(); iI++)25191 {25192 const FeatureTypes eFeature = static_cast<FeatureTypes>(iI);25193 CvFeatureInfo* pkFeatureInfo = GC.getFeatureInfo(eFeature);25194 if(pkFeatureInfo)25195 {25196 iTemp = pkPromotionInfo->GetFeatureAttackPercent(iI);25197 if(iTemp != 0)25198 {25199 iExtra = getExtraFeatureAttackPercent(eFeature);25200 iTemp *= (100 + iExtra * 2);25201 iTemp /= 100;25202 iValue += iTemp + iFlavorOffense * 2;25203 if((AI_getUnitAIType() == UNITAI_ATTACK) ||25204 (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25205 {25206 iValue *= 2;25207 }25208 }2520925210 iTemp = pkPromotionInfo->GetFeatureDefensePercent(iI);;25211 if(iTemp != 0)25212 {25213 iExtra = getExtraFeatureDefensePercent(eFeature);25214 iTemp *= (100 + iExtra * 2);25215 iTemp /= 100;25216 iValue += iTemp + iFlavorDefense * 2;25217 if((AI_getUnitAIType() == UNITAI_DEFENSE) ||25218 (AI_getUnitAIType() == UNITAI_COUNTER))25219 {25220 iValue *= 2;25221 }25222 }2522325224 if(pkPromotionInfo->GetFeatureDoubleMove(iI))25225 {25226 if(AI_getUnitAIType() == UNITAI_EXPLORE)25227 {25228 iValue += 5 * (iFlavorRecon + iFlavorMobile);25229 }25230 else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25231 {25232 iValue += 3 * (iFlavorOffense + iFlavorMobile);25233 }25234 else25235 {25236 iValue += 3 * iFlavorMobile;25237 }25238 }2523925240#if defined(MOD_PROMOTIONS_HALF_MOVE)25241 if(pkPromotionInfo->GetFeatureHalfMove(iI))25242 {25243 if(AI_getUnitAIType() == UNITAI_EXPLORE)25244 {25245 iValue -= 5 * (iFlavorRecon + iFlavorMobile);25246 }25247 else if((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_FAST_ATTACK))25248 {25249 iValue -= 3 * (iFlavorOffense + iFlavorMobile);25250 }25251 else25252 {25253 iValue -= 3 * iFlavorMobile;25254 }25255 }25256#endif25257 }25258 }2525925260 int iOtherCombat = 0;25261 int iSameCombat = 0;2526225263 for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)25264 {25265 const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);25266 CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);25267 if(pkUnitCombatInfo)25268 {25269 if(eUnitCombat == getUnitCombatType())25270 {25271 iSameCombat += unitCombatModifier(eUnitCombat);25272 }25273 else25274 {25275 iOtherCombat += unitCombatModifier(eUnitCombat);25276 }25277 }25278 }2527925280 for(iI = 0; iI < GC.getNumUnitCombatClassInfos(); iI++)25281 {25282 const UnitCombatTypes eUnitCombat = static_cast<UnitCombatTypes>(iI);25283 CvBaseInfo* pkUnitCombatInfo = GC.getUnitCombatClassInfo(eUnitCombat);25284 if(pkUnitCombatInfo)25285 {25286 iTemp = pkPromotionInfo->GetUnitCombatModifierPercent(iI);25287 int iCombatWeight = 0;25288 //Fighting their own kind25289 if((UnitCombatTypes)iI == getUnitCombatType())25290 {25291 if(iSameCombat >= iOtherCombat)25292 {25293 iCombatWeight = 70;//"axeman takes formation"25294 }25295 else25296 {25297 iCombatWeight = 30;25298 }25299 }25300 else25301 {25302 //fighting other kinds25303 if(unitCombatModifier(eUnitCombat) > 10)25304 {25305 iCombatWeight = 70;//"spearman takes formation"25306 }25307 else25308 {25309 iCombatWeight = 30;25310 }25311 }2531225313 if((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_RANGED))25314 {25315 iValue += (iTemp * iCombatWeight) / 25;25316 }25317 else if((AI_getUnitAIType() == UNITAI_ATTACK) ||25318 (AI_getUnitAIType() == UNITAI_DEFENSE))25319 {25320 iValue += (iTemp * iCombatWeight) / 50;25321 }25322 else25323 {25324 iValue += (iTemp * iCombatWeight) / 100;25325 }25326 }25327 }2532825329 for(iI = 0; iI < NUM_DOMAIN_TYPES; iI++)25330 {25331 iTemp = pkPromotionInfo->GetDomainModifierPercent(iI);25332 if(AI_getUnitAIType() == UNITAI_COUNTER)25333 {25334 iValue += (iTemp * 2);25335 }25336 else if((AI_getUnitAIType() == UNITAI_ATTACK) ||25337 (AI_getUnitAIType() == UNITAI_DEFENSE))25338 {25339 iValue += iTemp;25340 }25341 else25342 {25343 iValue += (iTemp / 2);25344 }25345 }2534625347 if(iValue > 0)25348 {25349 iValue += GC.getGame().getJonRandNum(15, "AI Promote");25350 }25351#if defined(MOD_AI_SMART_V3)25352 }25353#endif2535425355 return iValue;25356}