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}