Hooks
static bool BeforeCvTacticalAI_CombatResolved(CvTacticalAI* self, void* pAttacker, bool bVictorious, bool bCityAttack);static void AfterCvTacticalAI_CombatResolved(CvTacticalAI* self, void* pAttacker, bool bVictorious, bool bCityAttack);static void ReplaceCvTacticalAI_CombatResolved(void (*original)(CvTacticalAI*, void*, bool, bool), CvTacticalAI* self, void* pAttacker, bool bVictorious, bool bCityAttack);CivRegisterBefore<CivHooks::CvTacticalAI_CombatResolved>(host, &BeforeCvTacticalAI_CombatResolved);CivRegisterAfter<CivHooks::CvTacticalAI_CombatResolved>(host, &AfterCvTacticalAI_CombatResolved);CivRegisterReplace<CivHooks::CvTacticalAI_CombatResolved>(host, &ReplaceCvTacticalAI_CombatResolved);
Code
685/// Handles notification that an attack has been resolved (so can queue another)686void CvTacticalAI::CombatResolved(void* pAttacker, bool bVictorious, bool bCityAttack)687{688 int iSeriesID = 0;689 bool bFoundIt = false;690691 CvCity* pCity = NULL;692 UnitHandle pUnit;693694 if(bCityAttack)695 {696 pCity = (CvCity*)pAttacker;697 }698 else699 {700 pUnit = UnitHandle((CvUnit*)pAttacker);701 }702703 if(m_QueuedAttacks.size() > 0)704 {705 std::list<CvQueuedAttack>::iterator nextToErase, nextInList;706 nextToErase = m_QueuedAttacks.begin();707708 // Find first attack with this unit/city709 while(nextToErase != m_QueuedAttacks.end())710 {711 if(nextToErase->GetAttacker() == pAttacker)712 {713 iSeriesID = nextToErase->GetSeriesID();714 bFoundIt = true;715 break;716 }717 nextToErase++;718 }719720 // Couldn't find it ... could have been an accidental attack moving to deploy near a target721 // So safe to ignore these722 if(!bFoundIt)723 {724 return;725 }726727 // If this attacker gets multiple attacks, release him to be processed again728 if(!bCityAttack && (pUnit->canMoveAfterAttacking() || !pUnit->isOutOfAttacks()) && pUnit->getMoves() > 0)729 {730 pUnit->SetTurnProcessed(false);731 }732733 // If victorious, dump follow-up attacks734 if(bVictorious)735 {736 bool bFirst = true;737 while(nextToErase != m_QueuedAttacks.end() && nextToErase->GetSeriesID() == iSeriesID)738 {739 // Only the first unit being erased is done for the turn740 if(!bFirst && !nextToErase->IsCityAttack())741 {742 UnitHandle pAbortUnit((CvUnit*)nextToErase->GetAttacker());743 pAbortUnit->SetTurnProcessed(false);744 }745 nextToErase = m_QueuedAttacks.erase(nextToErase);746 bFirst = false;747 }748 }749750 // Otherwise look for a follow-up attack751 else752 {753 nextInList = nextToErase;754 nextInList++;755756 // Matching IDs, we have a follow-up attack757 if(nextInList != m_QueuedAttacks.end() && nextInList->GetSeriesID() == nextToErase->GetSeriesID())758 {759 // Calling LaunchAttack can be recursive if the launched combat is resolved immediately.760 // We'll make a copy of the iterator's contents before erasing. This is not technically needed because761 // the current queue is a std::list and iterators don't invalidate on erase, but we'll be safe, in case762 // the container type changes.763 CvQueuedAttack kAttack(*nextInList);764 m_QueuedAttacks.erase(nextToErase);765 LaunchAttack(kAttack.GetAttacker(), kAttack.GetTarget(), false /*bFirst*/, kAttack.IsRanged(), kAttack.IsCityAttack());766 }767 else768 {769 m_QueuedAttacks.erase(nextToErase);770 }771 }772 }773774 return;775}