void CvUnit::doBattleFieldPromotions(CvUnit* pDefender, CombatDetails cdDefenderDetails, const CvPlot* pPlot, bool bAttackerHasLostNoHP, bool bAttackerWithdrawn, int iAttackerInitialDamage, int iWinningOdds, int iInitialAttXP, int iInitialAttGGXP, int iDefenderInitialDamage, int iInitialDefXP, int iInitialDefGGXP, bool &bAttackerPromoted, bool &bDefenderPromoted)
{
if (GC.getGameINLINE().getModderGameOption(MODDERGAMEOPTION_BATTLEFIELD_PROMOTIONS))
{
if (getUnitCombatType() != NO_UNITCOMBAT && pDefender->getUnitCombatType() != NO_UNITCOMBAT)
{
std::vector<PromotionTypes> aAttackerAvailablePromotions;
std::vector<PromotionTypes> aDefenderAvailablePromotions;
int iI;
for (iI = 0; iI < GC.getNumPromotionInfos(); iI++) //loop through promotions
{
CvPromotionInfo &kPromotion = GC.getPromotionInfo((PromotionTypes)iI);
/* Block These Promotions */
if (kPromotion.getKamikazePercent() > 0)
continue;
if (kPromotion.getStateReligionPrereq() != NO_RELIGION)
{
if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != kPromotion.getStateReligionPrereq())
continue;
}
if (kPromotion.isLeader())
continue;
/* Block These Promotions */
if (pDefender->isDead() || m_combatResult.bDefenderWithdrawn)
{
//* defender withdrawn, give him withdrawal promo
if (m_combatResult.bDefenderWithdrawn && kPromotion.getWithdrawalChange() > 0 &&
pDefender->canAcquirePromotion((PromotionTypes)iI))
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
if (!canAcquirePromotion((PromotionTypes)iI)) //attacker can not acquire this promotion
{
continue;
}
//* attacker was crossing river
if (kPromotion.isRiver() && cdDefenderDetails.iRiverAttackModifier != 0) //this bonus is being applied to defender
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* attack from water
else if (kPromotion.isAmphib() && cdDefenderDetails.iAmphibAttackModifier != 0)
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* attack terrain
else if (kPromotion.getTerrainAttackPercent((int)pPlot->getTerrainType()) > 0)
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* attack feature
else if (pPlot->getFeatureType() != NO_FEATURE &&
kPromotion.getFeatureAttackPercent((int)pPlot->getFeatureType()) > 0)
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* attack hills
else if (kPromotion.getHillsAttackPercent() > 0 && pPlot->isHills())
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* attack city
else if (kPromotion.getCityAttackPercent() > 0 && pPlot->isCity(true)) //count forts too
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* first strikes/chanses promotions
else if ((kPromotion.getFirstStrikesChange() > 0 ||
kPromotion.getChanceFirstStrikesChange() > 0) && (firstStrikes() > 0 || chanceFirstStrikes() > 0) )
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* unit combat mod
else if (kPromotion.getUnitCombatModifierPercent((int)pDefender->getUnitCombatType()) > 0)
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* combat strength promotions
else if (kPromotion.getCombatPercent() > 0 && !kPromotion.isAmphib())
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* domain mod
else if (kPromotion.getDomainModifierPercent((int)pDefender->getDomainType()))
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
//* blitz
else if (kPromotion.isBlitz() && bAttackerHasLostNoHP)
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
} //if defender is dead or withdrawn
else //attacker is dead or withdrawn
{
//* attacker withdrawn
if (bAttackerWithdrawn && kPromotion.getWithdrawalChange() > 0 && canAcquirePromotion((PromotionTypes)iI))
{
aAttackerAvailablePromotions.push_back((PromotionTypes)iI);
}
if (!pDefender->canAcquirePromotion((PromotionTypes)iI))
{
continue;
}
//* defend terrain
if (kPromotion.getTerrainDefensePercent((int)pPlot->getTerrainType()) > 0)
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* defend feature
else if (pPlot->getFeatureType() != NO_FEATURE &&
kPromotion.getFeatureDefensePercent((int)pPlot->getFeatureType()) > 0)
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* defend hills
else if (kPromotion.getHillsDefensePercent() > 0 && pPlot->isHills())
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* defend city
else if (kPromotion.getCityDefensePercent() > 0 && pPlot->isCity(true)) //count forts too
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* first strikes/chanses promotions
else if ((kPromotion.getFirstStrikesChange() > 0 ||
kPromotion.getChanceFirstStrikesChange() > 0) &&
(pDefender->firstStrikes() > 0 || pDefender->chanceFirstStrikes() > 0))
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* unit combat mod vs attacker unit type
else if (kPromotion.getUnitCombatModifierPercent((int)getUnitCombatType()) > 0)
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* combat strength promotions
else if (kPromotion.getCombatPercent() > 0)
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
//* domain mod
else if (kPromotion.getDomainModifierPercent((int)getDomainType()))
{
aDefenderAvailablePromotions.push_back((PromotionTypes)iI);
}
} //if attacker withdrawn
} //end promotion types cycle
//promote attacker:
if (!isDead() && aAttackerAvailablePromotions.size() > 0)
{
FAssertMsg(maxHitPoints() - iAttackerInitialDamage > 0, "Attacker is Dead!");
int iHealthPercent = (maxHitPoints() - getDamage()) * 100 / std::max(1,(maxHitPoints() - iAttackerInitialDamage));
int iPromotionChanceModifier = iHealthPercent * iHealthPercent / maxHitPoints();
int iPromotionChance = (GC.getCOMBAT_DIE_SIDES() - iWinningOdds) * (100 + iPromotionChanceModifier) / 100;
if (GC.getGameINLINE().getSorenRandNum(GC.getCOMBAT_DIE_SIDES(), "Occasional Promotion") < iPromotionChance)
{
//select random promotion from available
PromotionTypes ptPromotion = aAttackerAvailablePromotions[
GC.getGameINLINE().getSorenRandNum(aAttackerAvailablePromotions.size(), "Select Promotion Type")];
//promote
setHasPromotion(ptPromotion, true);
bAttackerPromoted = true;
//Reset XP
setExperience100(iInitialAttXP);
GET_PLAYER(getOwnerINLINE()).setCombatExperience(iInitialAttGGXP);
// Great Commander XP
if (getUsedCommander() != NULL)
{
getUsedCommander()->setExperience100(getUsedCommander()->getExperience100() + 100);
}
//show message
CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_PROMOTED_IN_BATTLE", getNameKey(), GC.getPromotionInfo(ptPromotion).getText());
gDLL->getInterfaceIFace()->addMessage(
getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer,
GC.getPromotionInfo((PromotionTypes)0).getSound(), MESSAGE_TYPE_INFO, NULL,
(ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), this->plot()->getX_INLINE(), this->plot()->getY_INLINE());
}
}
//promote defender:
if (!pDefender->isDead() && aDefenderAvailablePromotions.size() > 0)
{
FAssertMsg(pDefender->maxHitPoints() - iDefenderInitialDamage > 0, "Defender is Dead!");
int iHealthPercent = (pDefender->maxHitPoints() - pDefender->getDamage()) * 100 / std::max(1,(pDefender->maxHitPoints() - iDefenderInitialDamage));
int iPromotionChanceModifier = iHealthPercent * iHealthPercent / pDefender->maxHitPoints();
int iPromotionChance = iWinningOdds * (100 + iPromotionChanceModifier) / 100;
if (GC.getGameINLINE().getSorenRandNum(GC.getCOMBAT_DIE_SIDES(), "Occasional Promotion") < iPromotionChance)
{
//select random promotion from available
PromotionTypes ptPromotion = aDefenderAvailablePromotions[
GC.getGameINLINE().getSorenRandNum(aDefenderAvailablePromotions.size(), "Select Promotion Type")];
//promote
pDefender->setHasPromotion(ptPromotion, true);
//Reset XP
pDefender->setExperience100(iInitialDefXP);
GET_PLAYER(pDefender->getOwnerINLINE()).setCombatExperience(iInitialDefGGXP);
bDefenderPromoted = true;
// Great Commander XP
if (pDefender->getUsedCommander() != NULL)
{
pDefender->getUsedCommander()->setExperience100(pDefender->getUsedCommander()->getExperience100() + 100);
}
//show message
CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_PROMOTED_IN_BATTLE", pDefender->getNameKey(),
GC.getPromotionInfo(ptPromotion).getText());
gDLL->getInterfaceIFace()->addMessage(
pDefender->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer,
GC.getPromotionInfo((PromotionTypes)0).getSound(), MESSAGE_TYPE_INFO, NULL,
(ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
}
}
}
}
}