Bazaar developer reference

CvUnitCombat::ResolveMeleeCombat(const CvCombatInfo &, uint)

Defined in
CvUnitCombat.cpp, line 360
Class
CvUnitCombat
Hook name
CivHooks::CvUnitCombat_ResolveMeleeCombat

Hooks

static bool BeforeCvUnitCombat_ResolveMeleeCombat(const CvCombatInfo& kCombatInfo, uint uiParentEventID);static void AfterCvUnitCombat_ResolveMeleeCombat(const CvCombatInfo& kCombatInfo, uint uiParentEventID);static void ReplaceCvUnitCombat_ResolveMeleeCombat(void (*original)(const CvCombatInfo&, uint), const CvCombatInfo& kCombatInfo, uint uiParentEventID);CivRegisterBefore<CivHooks::CvUnitCombat_ResolveMeleeCombat>(host, &BeforeCvUnitCombat_ResolveMeleeCombat);CivRegisterAfter<CivHooks::CvUnitCombat_ResolveMeleeCombat>(host, &AfterCvUnitCombat_ResolveMeleeCombat);CivRegisterReplace<CivHooks::CvUnitCombat_ResolveMeleeCombat>(host, &ReplaceCvUnitCombat_ResolveMeleeCombat);

Code

360void CvUnitCombat::ResolveMeleeCombat(const CvCombatInfo& kCombatInfo, uint uiParentEventID)361{362	// After combat stuff363	CvString strBuffer;364	bool bAttackerDead = false;365	bool bDefenderDead = false;366	int iAttackerDamageDelta = 0;367368	CvUnit* pkAttacker = kCombatInfo.getUnit(BATTLE_UNIT_ATTACKER);369	CvUnit* pkDefender = kCombatInfo.getUnit(BATTLE_UNIT_DEFENDER);370	CvPlot* pkTargetPlot = kCombatInfo.getPlot();371	if(!pkTargetPlot && pkDefender)372		pkTargetPlot = pkDefender->plot();373374	CvAssert_Debug(pkAttacker && pkDefender && pkTargetPlot);375376	int iActivePlayerID = GC.getGame().getActivePlayer();377378	bool bAttackerDidMoreDamage = false;379380	if(pkAttacker != NULL && pkDefender != NULL && pkTargetPlot != NULL &&381	        pkDefender->IsCanDefend()) 		// Did the defender actually defend?382	{383		// Internal variables384		int iAttackerDamageInflicted = kCombatInfo.getDamageInflicted(BATTLE_UNIT_ATTACKER);385		int iDefenderDamageInflicted = kCombatInfo.getDamageInflicted(BATTLE_UNIT_DEFENDER);386		int iAttackerFearDamageInflicted = 0;//pInfo->getFearDamageInflicted( BATTLE_UNIT_ATTACKER );387388		bAttackerDidMoreDamage = iAttackerDamageInflicted > iDefenderDamageInflicted;389390#if !defined(NO_ACHIEVEMENTS)391		//One Hit392#if defined(MOD_UNITS_MAX_HP)393		if(pkDefender->GetCurrHitPoints() == pkDefender->GetMaxHitPoints() && iAttackerDamageInflicted >= pkDefender->GetCurrHitPoints()  // Defender at full hit points and will the damage be more than the full hit points?394#else395		if(pkDefender->GetCurrHitPoints() == GC.getMAX_HIT_POINTS() && iAttackerDamageInflicted >= pkDefender->GetCurrHitPoints()  // Defender at full hit points and will the damage be more than the full hit points?396#endif397		        && pkAttacker->isHuman() && !GC.getGame().isGameMultiPlayer())398		{399			gDLL->UnlockAchievement(ACHIEVEMENT_ONEHITKILL);400		}401#endif402403#if defined(MOD_API_UNIT_STATS)404		pkDefender->changeDamage(iAttackerDamageInflicted, pkAttacker->getOwner(), pkAttacker->GetID());405		iAttackerDamageDelta = pkAttacker->changeDamage(iDefenderDamageInflicted, pkDefender->getOwner(), pkDefender->GetID(), -1.f);		// Signal that we don't want the popup text.  It will be added later when the unit is at its final location406#else407		pkDefender->changeDamage(iAttackerDamageInflicted, pkAttacker->getOwner());408		iAttackerDamageDelta = pkAttacker->changeDamage(iDefenderDamageInflicted, pkDefender->getOwner(), -1.f);		// Signal that we don't want the popup text.  It will be added later when the unit is at its final location409#endif410411		// Update experience for both sides.412#if defined(MOD_UNITS_XP_TIMES_100)413		pkDefender->changeExperienceTimes100(100 *414#else415		pkDefender->changeExperience(416#endif417		    kCombatInfo.getExperience(BATTLE_UNIT_DEFENDER),418		    kCombatInfo.getMaxExperienceAllowed(BATTLE_UNIT_DEFENDER),419		    true,420		    kCombatInfo.getInBorders(BATTLE_UNIT_DEFENDER),421		    kCombatInfo.getUpdateGlobal(BATTLE_UNIT_DEFENDER));422423#if defined(MOD_UNITS_XP_TIMES_100)424		pkAttacker->changeExperienceTimes100(100 * 425#else426		pkAttacker->changeExperience(427#endif428		    kCombatInfo.getExperience(BATTLE_UNIT_ATTACKER),429		    kCombatInfo.getMaxExperienceAllowed(BATTLE_UNIT_ATTACKER),430		    true,431		    kCombatInfo.getInBorders(BATTLE_UNIT_ATTACKER),432		    kCombatInfo.getUpdateGlobal(BATTLE_UNIT_ATTACKER));433434		// Anyone eat it?435#if defined(MOD_UNITS_MAX_HP)436		bAttackerDead = (pkAttacker->getDamage() >= pkAttacker->GetMaxHitPoints());437		bDefenderDead = (pkDefender->getDamage() >= pkDefender->GetMaxHitPoints());438#else439		bAttackerDead = (pkAttacker->getDamage() >= GC.getMAX_HIT_POINTS());440		bDefenderDead = (pkDefender->getDamage() >= GC.getMAX_HIT_POINTS());441#endif442443#if !defined(NO_ACHIEVEMENTS)444		CvPlayerAI& kAttackerOwner = GET_PLAYER(pkAttacker->getOwner());445		kAttackerOwner.GetPlayerAchievements().AttackedUnitWithUnit(pkAttacker, pkDefender);446#endif447448		// Attacker died449		if(bAttackerDead)450		{451#if !defined(NO_ACHIEVEMENTS)452			CvPlayerAI& kDefenderOwner = GET_PLAYER(pkDefender->getOwner());453			kDefenderOwner.GetPlayerAchievements().KilledUnitWithUnit(pkDefender, pkAttacker);454#endif455456			auto_ptr<ICvUnit1> pAttacker = GC.WrapUnitPointer(pkAttacker);457			gDLL->GameplayUnitDestroyedInCombat(pAttacker.get());458			459			if(iActivePlayerID == pkAttacker->getOwner())460			{461				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_UNIT_DIED_ATTACKING", pkAttacker->getNameKey(), pkDefender->getNameKey(), iAttackerDamageInflicted, iAttackerFearDamageInflicted);462				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkAttacker->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*, GC.getEraInfo(GC.getGame().getCurrentEra())->getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);463				MILITARYLOG(pkAttacker->getOwner(), strBuffer.c_str(), pkAttacker->plot(), pkDefender->getOwner());464			}465			if(iActivePlayerID == pkDefender->getOwner())466			{467				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_KILLED_ENEMY_UNIT", pkDefender->getNameKey(), iAttackerDamageInflicted, iAttackerFearDamageInflicted, pkAttacker->getNameKey(), pkAttacker->getVisualCivAdjective(pkDefender->getTeam()));468				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkDefender->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*, GC.getEraInfo(GC.getGame().getCurrentEra())->getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);469				MILITARYLOG(pkDefender->getOwner(), strBuffer.c_str(), pkDefender->plot(), pkAttacker->getOwner());470			}471			pkDefender->testPromotionReady();472473			ApplyPostCombatTraitEffects(pkDefender, pkAttacker);474475		}476		// Defender died477		else if(bDefenderDead)478		{479#if !defined(NO_ACHIEVEMENTS)480			kAttackerOwner.GetPlayerAchievements().KilledUnitWithUnit(pkAttacker, pkDefender);481#endif482483			auto_ptr<ICvUnit1> pDefender = GC.WrapUnitPointer(pkDefender);484			gDLL->GameplayUnitDestroyedInCombat(pDefender.get());485486			if(iActivePlayerID == pkAttacker->getOwner())487			{488				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_UNIT_DESTROYED_ENEMY", pkAttacker->getNameKey(), iDefenderDamageInflicted, pkDefender->getNameKey());489				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkAttacker->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*, GC.getEraInfo(GC.getGame().getCurrentEra())->getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);490				MILITARYLOG(pkAttacker->getOwner(), strBuffer.c_str(), pkDefender->plot(), pkDefender->getOwner());491			}492493			if(pkAttacker->getVisualOwner(pkDefender->getTeam()) != pkAttacker->getOwner())494			{495				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED_UNKNOWN", pkDefender->getNameKey(), pkAttacker->getNameKey(), iDefenderDamageInflicted);496			}497			else498			{499				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED", pkDefender->getNameKey(), pkAttacker->getNameKey(), pkAttacker->getVisualCivAdjective(pkDefender->getTeam()), iDefenderDamageInflicted);500			}501			if(iActivePlayerID == pkDefender->getOwner())502			{503				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkDefender->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*,GC.getEraInfo(GC.getGame().getCurrentEra())->getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);504				MILITARYLOG(pkDefender->getOwner(), strBuffer.c_str(), pkDefender->plot(), ((pkAttacker->getVisualOwner(pkDefender->getTeam()) != pkAttacker->getOwner()) ? NO_PLAYER : pkAttacker->getOwner()));505			}506			CvNotifications* pNotification = GET_PLAYER(pkDefender->getOwner()).GetNotifications();507			if(pNotification)508			{509				Localization::String strSummary = Localization::Lookup("TXT_KEY_UNIT_LOST");510				pNotification->Add(NOTIFICATION_UNIT_DIED, strBuffer, strSummary.toUTF8(), pkDefender->getX(), pkDefender->getY(), (int) pkDefender->getUnitType(), pkDefender->getOwner());511			}512513			pkAttacker->testPromotionReady();514515			ApplyPostCombatTraitEffects(pkAttacker, pkDefender);516517			// If defender captured, mark who captured him518			if (kCombatInfo.getDefenderCaptured())519			{520				pkDefender->setCapturingPlayer(pkAttacker->getOwner());521				pkDefender->SetCapturedAsIs(true);522			}523		}524		// Nobody died525		else526		{527			if(iActivePlayerID == pkAttacker->getOwner())528			{529				strBuffer = GetLocalizedText("TXT_KEY_MISC_YOU_UNIT_WITHDRAW", pkAttacker->getNameKey(), iDefenderDamageInflicted, pkDefender->getNameKey(), iAttackerDamageInflicted);530				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkAttacker->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);531				MILITARYLOG(pkAttacker->getOwner(), strBuffer.c_str(), pkAttacker->plot(), pkDefender->getOwner());532			}533			if(iActivePlayerID == pkDefender->getOwner())534			{535				strBuffer = GetLocalizedText("TXT_KEY_MISC_ENEMY_UNIT_WITHDRAW", pkAttacker->getNameKey(), iDefenderDamageInflicted, pkDefender->getNameKey(), iAttackerDamageInflicted);536				GC.GetEngineUserInterface()->AddMessage(uiParentEventID, pkDefender->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer/*, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pkTargetPlot->getX(), pkTargetPlot->getY()*/);537				MILITARYLOG(pkDefender->getOwner(), strBuffer.c_str(), pkDefender->plot(), pkAttacker->getOwner());538			}539540			pkDefender->testPromotionReady();541			pkAttacker->testPromotionReady();542543		}544545		// Minors want Barbs near them dead546		if(bAttackerDead)547		{548			if(pkAttacker->isBarbarian())549				pkAttacker->DoTestBarbarianThreatToMinorsWithThisUnitsDeath(pkDefender->getOwner());550		}551		else if(bDefenderDead)552		{553			if(pkDefender->isBarbarian())554				pkDefender->DoTestBarbarianThreatToMinorsWithThisUnitsDeath(pkAttacker->getOwner());555		}556	}557558	if(pkAttacker)559	{560		pkAttacker->setCombatUnit(NULL);561		pkAttacker->ClearMissionQueue(GetPostCombatDelay());562	}563	if(pkDefender)564	{565		pkDefender->setCombatUnit(NULL);566		pkDefender->ClearMissionQueue();567	}568	else569		bDefenderDead = true;570571	if(pkAttacker)572	{573		if(pkAttacker->isSuicide())574		{575			pkAttacker->setCombatUnit(NULL);	// Must clear this if doing a delayed kill, should this be part of the kill method?576			pkAttacker->kill(true);577		}578		else579		{580			if(pkTargetPlot)581			{582				if (pkAttacker->IsCanHeavyCharge() && !pkDefender->isDelayedDeath() && bAttackerDidMoreDamage)583				{584					pkDefender->DoFallBackFromMelee(*pkAttacker);585				}586587				bool bCanAdvance = kCombatInfo.getAttackerAdvances() && pkTargetPlot->getNumVisibleEnemyDefenders(pkAttacker) == 0;588				if(bCanAdvance)589				{590					if(kCombatInfo.getAttackerAdvancedVisualization())591						// The combat vis has already 'moved' the unit.  Have the game side just do its movement calculations and pop the unit to the new location.592						pkAttacker->move(*pkTargetPlot, false);593					else594						pkAttacker->UnitMove(pkTargetPlot, true, pkAttacker);595596					pkAttacker->PublishQueuedVisualizationMoves();597				}598				else599				{600					pkAttacker->changeMoves(-1 * std::max(GC.getMOVE_DENOMINATOR(), pkTargetPlot->movementCost(pkAttacker, pkAttacker->plot())));601602					if(!pkAttacker->canMove() || !pkAttacker->isBlitz())603					{604						if(pkAttacker->IsSelected())605						{606							if(GC.GetEngineUserInterface()->GetLengthSelectionList() > 1)607							{608								auto_ptr<ICvUnit1> pDllAttacker = GC.WrapUnitPointer(pkAttacker);609								GC.GetEngineUserInterface()->RemoveFromSelectionList(pDllAttacker.get());610							}611						}612					}613				}614			}615616			// If a Unit loses his moves after attacking, do so617			if(!pkAttacker->canMoveAfterAttacking())618			{619				pkAttacker->finishMoves();620				GC.GetEngineUserInterface()->changeCycleSelectionCounter(1);621			}622623			// Now that the attacker is in their final location, show any damage popup624			if (!pkAttacker->IsDead() && iAttackerDamageDelta != 0)625#if defined(SHOW_PLOT_POPUP)626				pkAttacker->ShowDamageDeltaText(iAttackerDamageDelta, pkAttacker->plot());627#else628				CvUnit::ShowDamageDeltaText(iAttackerDamageDelta, pkAttacker->plot());629#endif630		}631632		// Report that combat is over in case we want to queue another attack633		GET_PLAYER(pkAttacker->getOwner()).GetTacticalAI()->CombatResolved(pkAttacker, bDefenderDead);634	}635636	BATTLE_FINISHED();637}

Calls

Called by