Hooks
static bool BeforeCvUnitCombat_GenerateMeleeCombatInfo(CvUnit& kAttacker, CvUnit* pkDefender, CvPlot& plot, CvCombatInfo* pkCombatInfo);static void AfterCvUnitCombat_GenerateMeleeCombatInfo(CvUnit& kAttacker, CvUnit* pkDefender, CvPlot& plot, CvCombatInfo* pkCombatInfo);static void ReplaceCvUnitCombat_GenerateMeleeCombatInfo(void (*original)(CvUnit&, CvUnit*, CvPlot&, CvCombatInfo*), CvUnit& kAttacker, CvUnit* pkDefender, CvPlot& plot, CvCombatInfo* pkCombatInfo);CivRegisterBefore<CivHooks::CvUnitCombat_GenerateMeleeCombatInfo>(host, &BeforeCvUnitCombat_GenerateMeleeCombatInfo);CivRegisterAfter<CivHooks::CvUnitCombat_GenerateMeleeCombatInfo>(host, &AfterCvUnitCombat_GenerateMeleeCombatInfo);CivRegisterReplace<CivHooks::CvUnitCombat_GenerateMeleeCombatInfo>(host, &ReplaceCvUnitCombat_GenerateMeleeCombatInfo);
Code
101void CvUnitCombat::GenerateMeleeCombatInfo(CvUnit& kAttacker, CvUnit* pkDefender, CvPlot& plot, CvCombatInfo* pkCombatInfo)102{103 BATTLE_STARTED(BATTLE_TYPE_MELEE, plot);104#if defined(MOD_UNITS_MAX_HP)105 int iAttackerMaxHP = kAttacker.GetMaxHitPoints();106#else107 int iMaxHP = GC.getMAX_HIT_POINTS();108#endif109110 pkCombatInfo->setUnit(BATTLE_UNIT_ATTACKER, &kAttacker);111 pkCombatInfo->setUnit(BATTLE_UNIT_DEFENDER, pkDefender);112 pkCombatInfo->setPlot(&plot);113114 // Attacking a City115 if(plot.isCity())116 {117 // Unit vs. City (non-ranged so the city will retaliate118 CvCity* pkCity = plot.getPlotCity();119 BATTLE_JOINED(pkCity, BATTLE_UNIT_DEFENDER, true);120 int iMaxCityHP = pkCity->GetMaxHitPoints();121122 int iAttackerStrength = kAttacker.GetMaxAttackStrength(kAttacker.plot(), &plot, NULL);123 int iDefenderStrength = pkCity->getStrengthValue();124125 int iAttackerDamageInflicted = kAttacker.getCombatDamage(iAttackerStrength, iDefenderStrength, kAttacker.getDamage(), /*bIncludeRand*/ true, /*bAttackerIsCity*/ false, /*bDefenderIsCity*/ true);126 int iDefenderDamageInflicted = kAttacker.getCombatDamage(iDefenderStrength, iAttackerStrength, pkCity->getDamage(), /*bIncludeRand*/ true, /*bAttackerIsCity*/ true, /*bDefenderIsCity*/ false);127128 int iAttackerTotalDamageInflicted = iAttackerDamageInflicted + pkCity->getDamage();129 int iDefenderTotalDamageInflicted = iDefenderDamageInflicted + kAttacker.getDamage();130131 // Will both the attacker die, and the city fall? If so, the unit wins132#if defined(MOD_UNITS_MAX_HP)133 if (iAttackerTotalDamageInflicted >= iMaxCityHP && iDefenderTotalDamageInflicted >= iAttackerMaxHP)134 {135 iDefenderDamageInflicted = iAttackerMaxHP - kAttacker.getDamage() - 1;136 iDefenderTotalDamageInflicted = iAttackerMaxHP - 1;137 }138#else139 if (iAttackerTotalDamageInflicted >= iMaxCityHP && iDefenderTotalDamageInflicted >= iMaxHP)140 {141 iDefenderDamageInflicted = iMaxHP - kAttacker.getDamage() - 1;142 iDefenderTotalDamageInflicted = iMaxHP - 1;143 }144#endif145146 pkCombatInfo->setFinalDamage(BATTLE_UNIT_ATTACKER, iDefenderTotalDamageInflicted);147 pkCombatInfo->setDamageInflicted(BATTLE_UNIT_ATTACKER, iAttackerDamageInflicted);148 pkCombatInfo->setFinalDamage(BATTLE_UNIT_DEFENDER, iAttackerTotalDamageInflicted);149 pkCombatInfo->setDamageInflicted(BATTLE_UNIT_DEFENDER, iDefenderDamageInflicted);150151 int iExperience = /*5*/ GC.getEXPERIENCE_ATTACKING_CITY_MELEE();152 pkCombatInfo->setExperience(BATTLE_UNIT_ATTACKER, iExperience);153 pkCombatInfo->setMaxExperienceAllowed(BATTLE_UNIT_ATTACKER, MAX_INT);154 pkCombatInfo->setInBorders(BATTLE_UNIT_ATTACKER, plot.getOwner() == pkCity->getOwner());155#if defined(MOD_TRAITS_GG_FROM_BARBARIANS) || defined(MOD_PROMOTIONS_GG_FROM_BARBARIANS)156 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_ATTACKER, kAttacker.isGGFromBarbarians() || !kAttacker.isBarbarian());157#else158 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_ATTACKER, !kAttacker.isBarbarian());159#endif160161 pkCombatInfo->setExperience(BATTLE_UNIT_DEFENDER, 0);162 pkCombatInfo->setMaxExperienceAllowed(BATTLE_UNIT_DEFENDER, kAttacker.maxXPValue());163 pkCombatInfo->setInBorders(BATTLE_UNIT_DEFENDER, plot.getOwner() == kAttacker.getOwner());164#if defined(MOD_TRAITS_GG_FROM_BARBARIANS) || defined(MOD_PROMOTIONS_GG_FROM_BARBARIANS)165 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_DEFENDER, !pkCity->isBarbarian()); // Kind of irrelevant, as cities don't get XP!166#else167 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_DEFENDER, !pkCity->isBarbarian());168#endif169170 pkCombatInfo->setAttackIsRanged(false);171 pkCombatInfo->setDefenderRetaliates(true);172 }173 // Attacking a Unit174 else175 {176 // Unit vs. Unit177 CvAssert(pkDefender != NULL);178179#if defined(MOD_UNITS_MAX_HP)180 int iDefenderMaxHP = pkDefender->GetMaxHitPoints();181#endif182183 int iDefenderStrength = pkDefender->GetMaxDefenseStrength(&plot, &kAttacker);184 int iAttackerStrength = 0;185 if(kAttacker.GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true) > 0 && kAttacker.getDomainType() == DOMAIN_AIR)186 {187 iAttackerStrength = kAttacker.GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true);188 if(pkDefender->getDomainType() != DOMAIN_AIR)189 {190 iDefenderStrength /= 2;191 }192 }193 else194 {195 iAttackerStrength = kAttacker.GetMaxAttackStrength(kAttacker.plot(), &plot, pkDefender);196 }197198 if (kAttacker.IsCanHeavyCharge() && !pkDefender->CanFallBackFromMelee(kAttacker))199 {200 iAttackerStrength = (iAttackerStrength * 150) / 100;201 }202203 int iAttackerDamageInflicted = kAttacker.getCombatDamage(iAttackerStrength, iDefenderStrength, kAttacker.getDamage(), /*bIncludeRand*/ true, /*bAttackerIsCity*/ false, /*bDefenderIsCity*/ false);204 int iDefenderDamageInflicted = pkDefender->getCombatDamage(iDefenderStrength, iAttackerStrength, pkDefender->getDamage(), /*bIncludeRand*/ true, /*bAttackerIsCity*/ false, /*bDefenderIsCity*/ false);205206 if(kAttacker.getDomainType() == DOMAIN_AIR && pkDefender->getDomainType() != DOMAIN_AIR)207 {208 iAttackerDamageInflicted /= 2;209 iDefenderDamageInflicted /= 3;210 }211212 int iAttackerTotalDamageInflicted = iAttackerDamageInflicted + pkDefender->getDamage();213 int iDefenderTotalDamageInflicted = iDefenderDamageInflicted + kAttacker.getDamage();214215 // Will both units be killed by this? :o If so, take drastic corrective measures216#if defined(MOD_UNITS_MAX_HP)217 if (iAttackerTotalDamageInflicted >= iDefenderMaxHP && iDefenderTotalDamageInflicted >= iAttackerMaxHP)218#else219 if (iAttackerTotalDamageInflicted >= iMaxHP && iDefenderTotalDamageInflicted >= iMaxHP)220#endif221 {222 // He who hath the least amount of damage survives with 1 HP left223 if(iAttackerTotalDamageInflicted > iDefenderTotalDamageInflicted)224 {225#if defined(MOD_UNITS_MAX_HP)226 iDefenderDamageInflicted = iAttackerMaxHP - kAttacker.getDamage() - 1;227 iDefenderTotalDamageInflicted = iAttackerMaxHP - 1;228 iAttackerTotalDamageInflicted = iDefenderMaxHP;229#else230 iDefenderDamageInflicted = iMaxHP - kAttacker.getDamage() - 1;231 iDefenderTotalDamageInflicted = iMaxHP - 1;232 iAttackerTotalDamageInflicted = iMaxHP;233#endif234 }235 else236 {237#if defined(MOD_UNITS_MAX_HP)238 iAttackerDamageInflicted = iDefenderMaxHP - pkDefender->getDamage() - 1;239 iAttackerTotalDamageInflicted = iDefenderMaxHP - 1;240 iDefenderTotalDamageInflicted = iAttackerMaxHP;241#else242 iAttackerDamageInflicted = iMaxHP - pkDefender->getDamage() - 1;243 iAttackerTotalDamageInflicted = iMaxHP - 1;244 iDefenderTotalDamageInflicted = iMaxHP;245#endif246 }247 }248249 pkCombatInfo->setFinalDamage(BATTLE_UNIT_ATTACKER, iDefenderTotalDamageInflicted);250 pkCombatInfo->setDamageInflicted(BATTLE_UNIT_ATTACKER, iAttackerDamageInflicted);251 pkCombatInfo->setFinalDamage(BATTLE_UNIT_DEFENDER, iAttackerTotalDamageInflicted);252 pkCombatInfo->setDamageInflicted(BATTLE_UNIT_DEFENDER, iDefenderDamageInflicted);253254 // Fear Damage255 pkCombatInfo->setFearDamageInflicted(BATTLE_UNIT_ATTACKER, kAttacker.getCombatDamage(iAttackerStrength, iDefenderStrength, kAttacker.getDamage(), true, false, true));256 // pkCombatInfo->setFearDamageInflicted( BATTLE_UNIT_DEFENDER, getCombatDamage(iDefenderStrength, iAttackerStrength, pDefender->getDamage(), true, false, true) );257258#if defined(MOD_UNITS_MAX_HP)259 int iAttackerEffectiveStrength = iAttackerStrength * (iAttackerMaxHP - range(kAttacker.getDamage(), 0, iAttackerMaxHP - 1)) / iAttackerMaxHP;260#else261 int iAttackerEffectiveStrength = iAttackerStrength * (iMaxHP - range(kAttacker.getDamage(), 0, iMaxHP - 1)) / iMaxHP;262#endif263 iAttackerEffectiveStrength = iAttackerEffectiveStrength > 0 ? iAttackerEffectiveStrength : 1;264#if defined(MOD_UNITS_MAX_HP)265 int iDefenderEffectiveStrength = iDefenderStrength * (iDefenderMaxHP - range(pkDefender->getDamage(), 0, iDefenderMaxHP - 1)) / iDefenderMaxHP;266#else267 int iDefenderEffectiveStrength = iDefenderStrength * (iMaxHP - range(pkDefender->getDamage(), 0, iMaxHP - 1)) / iMaxHP;268#endif269 iDefenderEffectiveStrength = iDefenderEffectiveStrength > 0 ? iDefenderEffectiveStrength : 1;270271 //int iExperience = kAttacker.defenseXPValue();272 //iExperience = ((iExperience * iAttackerEffectiveStrength) / iDefenderEffectiveStrength); // is this right? looks like more for less [Jon: Yes, it's XP for the defender]273 //iExperience = range(iExperience, GC.getMIN_EXPERIENCE_PER_COMBAT(), GC.getMAX_EXPERIENCE_PER_COMBAT());274 int iExperience = /*4*/ GC.getEXPERIENCE_DEFENDING_UNIT_MELEE();275 pkCombatInfo->setExperience(BATTLE_UNIT_DEFENDER, iExperience);276 pkCombatInfo->setMaxExperienceAllowed(BATTLE_UNIT_DEFENDER, kAttacker.maxXPValue());277 pkCombatInfo->setInBorders(BATTLE_UNIT_DEFENDER, plot.getOwner() == pkDefender->getOwner());278#if defined(MOD_TRAITS_GG_FROM_BARBARIANS) || defined(MOD_PROMOTIONS_GG_FROM_BARBARIANS)279 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_DEFENDER, pkDefender->isGGFromBarbarians() || !kAttacker.isBarbarian());280#else281 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_DEFENDER, !kAttacker.isBarbarian());282#endif283284 //iExperience = ((iExperience * iDefenderEffectiveStrength) / iAttackerEffectiveStrength);285 //iExperience = range(iExperience, GC.getMIN_EXPERIENCE_PER_COMBAT(), GC.getMAX_EXPERIENCE_PER_COMBAT());286 iExperience = /*6*/ GC.getEXPERIENCE_ATTACKING_UNIT_MELEE();287 pkCombatInfo->setExperience(BATTLE_UNIT_ATTACKER, iExperience);288 pkCombatInfo->setMaxExperienceAllowed(BATTLE_UNIT_ATTACKER, pkDefender->maxXPValue());289 pkCombatInfo->setInBorders(BATTLE_UNIT_ATTACKER, plot.getOwner() == kAttacker.getOwner());290#if defined(MOD_TRAITS_GG_FROM_BARBARIANS) || defined(MOD_PROMOTIONS_GG_FROM_BARBARIANS)291 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_ATTACKER, kAttacker.isGGFromBarbarians() || !pkDefender->isBarbarian());292#else293 pkCombatInfo->setUpdateGlobal(BATTLE_UNIT_ATTACKER, !pkDefender->isBarbarian());294#endif295296 pkCombatInfo->setAttackIsRanged(false);297298 bool bAdvance = true;299 if(plot.getNumDefenders(pkDefender->getOwner()) > 1)300 {301 bAdvance = false;302 }303#if defined(MOD_UNITS_MAX_HP)304 else if (iAttackerTotalDamageInflicted >= iDefenderMaxHP && kAttacker.IsCaptureDefeatedEnemy() && kAttacker.AreUnitsOfSameType(*pkDefender))305#else306 else if (iAttackerTotalDamageInflicted >= iMaxHP && kAttacker.IsCaptureDefeatedEnemy() && kAttacker.AreUnitsOfSameType(*pkDefender))307#endif308 {309 int iCaptureRoll = GC.getGame().getJonRandNum(100, "Capture Enemy Roll");310311 if (iCaptureRoll < kAttacker.GetCaptureChance(pkDefender))312 {313 bAdvance = false;314 pkCombatInfo->setDefenderCaptured(true);315 }316 }317 else if (kAttacker.IsCanHeavyCharge() && !pkDefender->isDelayedDeath() && (iAttackerDamageInflicted > iDefenderDamageInflicted) )318 {319 bAdvance = true;320 }321322#if defined(MOD_GLOBAL_NO_FOLLOWUP_FROM_CITIES)323 // If the attacker is in a city, don't advance324 if (MOD_GLOBAL_NO_FOLLOWUP_FROM_CITIES && kAttacker.plot()->isCity()) {325 CUSTOMLOG("Attacker %s is in a city/fort/citadel at (%i, %i) - they will not follow up", kAttacker.getName().GetCString(), kAttacker.getX(), kAttacker.getY());326 bAdvance = false;327 }328#endif329330#if defined(MOD_GLOBAL_NO_FOLLOWUP) || defined(MOD_EVENTS_UNIT_ACTIONS)331 ImprovementTypes eImprovement = kAttacker.plot()->getImprovementType();332 333 if (eImprovement != NO_IMPROVEMENT) {334#if defined(MOD_GLOBAL_NO_FOLLOWUP)335 if (MOD_GLOBAL_NO_FOLLOWUP && GC.getImprovementInfo(eImprovement)->IsNoFollowup()) {336 // The attacker is in a designated improvement (fort, citadel, etc), so don't advance337 CUSTOMLOG("Attacker %s is in a designated improvement (%i) at (%i, %i) - they will not follow up", kAttacker.getName().GetCString(), eImprovement, kAttacker.getX(), kAttacker.getY());338 bAdvance = false;339 }340#endif341342#if defined(MOD_EVENTS_UNIT_ACTIONS)343 if (MOD_EVENTS_UNIT_ACTIONS && bAdvance) {344 if (GAMEEVENTINVOKE_TESTALL(GAMEEVENT_UnitCanFollowupFrom, kAttacker.getOwner(), kAttacker.GetID(), eImprovement, kAttacker.getX(), kAttacker.getY(), pkDefender->getX(), pkDefender->getY()) == GAMEEVENTRETURN_FALSE) {345 bAdvance = false;346 }347 }348#endif349 }350#endif351352 pkCombatInfo->setAttackerAdvances(bAdvance);353 pkCombatInfo->setDefenderRetaliates(true);354 }355356 GC.GetEngineUserInterface()->setDirty(UnitInfo_DIRTY_BIT, true);357}