Bazaar developer reference

CvUnitCombat::Attack(CvUnit &, CvPlot &, ATTACK_OPTION)

Defined in
CvUnitCombat.cpp, line 3000
Class
CvUnitCombat
Hook name
CivHooks::CvUnitCombat_Attack

Hooks

static bool BeforeCvUnitCombat_Attack(CvUnit& kAttacker, CvPlot& targetPlot, ATTACK_OPTION eOption, CvUnitCombat::ATTACK_RESULT& result);static void AfterCvUnitCombat_Attack(CvUnit& kAttacker, CvPlot& targetPlot, ATTACK_OPTION eOption, CvUnitCombat::ATTACK_RESULT& result);static CvUnitCombat::ATTACK_RESULT ReplaceCvUnitCombat_Attack(CvUnitCombat::ATTACK_RESULT (*original)(CvUnit&, CvPlot&, ATTACK_OPTION), CvUnit& kAttacker, CvPlot& targetPlot, ATTACK_OPTION eOption);// CivHooks.h gives this hook point no types, so nothing checks these hooks' parameters.host->RegisterHook(host->pluginIndex, CivHooks::CvUnitCombat_Attack::ID, CIV_HOOK_BEFORE, (void*)&BeforeCvUnitCombat_Attack);host->RegisterHook(host->pluginIndex, CivHooks::CvUnitCombat_Attack::ID, CIV_HOOK_AFTER, (void*)&AfterCvUnitCombat_Attack);host->RegisterHook(host->pluginIndex, CivHooks::CvUnitCombat_Attack::ID, CIV_HOOK_REPLACE, (void*)&ReplaceCvUnitCombat_Attack);

Code

3000CvUnitCombat::ATTACK_RESULT CvUnitCombat::Attack(CvUnit& kAttacker, CvPlot& targetPlot, ATTACK_OPTION eOption)3001{3002	CvString strBuffer;30033004	//VALIDATE_OBJECT3005	CvAssert(kAttacker.canMoveInto(targetPlot, CvUnit::MOVEFLAG_ATTACK | CvUnit::MOVEFLAG_PRETEND_CORRECT_EMBARK_STATE));3006	CvAssert(kAttacker.getCombatTimer() == 0);30073008	CvUnitCombat::ATTACK_RESULT eResult = CvUnitCombat::ATTACK_ABORTED;30093010	CvAssert(kAttacker.getCombatTimer() == 0);3011	//	CvAssert(pDefender != NULL);3012	CvAssert(!kAttacker.isFighting());30133014	// Unit that attacks loses his Fort bonus3015	kAttacker.setFortifyTurns(0);30163017	UnitHandle pDefender;3018	pDefender = targetPlot.getBestDefender(NO_PLAYER, kAttacker.getOwner(), &kAttacker, true);30193020	// JAR - without pDefender, nothing in here is going to work, just crash3021	if(!pDefender)3022	{3023		return eResult;3024	}30253026	kAttacker.SetAutomateType(NO_AUTOMATE);3027	pDefender->SetAutomateType(NO_AUTOMATE);3028#if defined(MOD_BUGFIX_UNITS_AWAKE_IN_DANGER)3029	// We want to "wake up" a unit that is being attacked by a hidden enemy (probably being bombed, indirect naval fire,3030	// or sneaky long-range archers) so the player can consider what to do with them, but without removing any fortification bonus!3031	if (MOD_BUGFIX_UNITS_AWAKE_IN_DANGER) {3032		pDefender->SetActivityType(ACTIVITY_AWAKE, false); 3033	}3034#endif30353036#if !defined(NO_TUTORIALS)3037	// slewis - tutorial'd3038	if(kAttacker.getOwner() == GC.getGame().getActivePlayer())3039	{3040		GC.getGame().SetEverAttackedTutorial(true);3041	}3042	// end tutorial'd3043#endif30443045	// handle the Zulu special thrown spear first attack3046	ATTACK_RESULT eFireSupportResult = ATTACK_ABORTED;3047	if (kAttacker.isRangedSupportFire() && pDefender->IsCanDefend())3048	{3049		eFireSupportResult = AttackRanged(kAttacker, pDefender->getX(), pDefender->getY(), CvUnitCombat::ATTACK_OPTION_NO_DEFENSIVE_SUPPORT);3050		if (pDefender->isDelayedDeath())3051		{3052			// Killed him, move to the plot if we can.3053			if(targetPlot.getNumVisibleEnemyDefenders(&kAttacker) == 0)3054			{3055				if (kAttacker.UnitMove(&targetPlot, true, &kAttacker, true))3056					kAttacker.finishMoves();	// Burn all the moves we have3057			}3058			return eFireSupportResult;3059		}3060	}30613062	CvCombatInfo kCombatInfo;3063	GenerateMeleeCombatInfo(kAttacker, pDefender.pointer(), targetPlot, &kCombatInfo);30643065	CvAssertMsg(!kAttacker.isDelayedDeath() && !pDefender->isDelayedDeath(), "Trying to battle and one of the units is already dead!");30663067	if(pDefender->getExtraWithdrawal() > 0 && pDefender->CanWithdrawFromMelee(kAttacker))3068	{3069		pDefender->DoWithdrawFromMelee(kAttacker);30703071		if(kAttacker.getOwner() == GC.getGame().getActivePlayer())3072		{3073			strBuffer = GetLocalizedText("TXT_KEY_MISC_ENEMY_UNIT_WITHDREW", pDefender->getNameKey());3074			GC.GetEngineUserInterface()->AddMessage(0, kAttacker.getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer);3075			MILITARYLOG(kAttacker.getOwner(), strBuffer.c_str(), kAttacker.plot(), pDefender->getOwner());3076		}3077		else if(pDefender->getOwner() == GC.getGame().getActivePlayer())3078		{3079			strBuffer = GetLocalizedText("TXT_KEY_MISC_FRIENDLY_UNIT_WITHDREW", pDefender->getNameKey());3080			GC.GetEngineUserInterface()->AddMessage(0, pDefender->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), strBuffer);3081			MILITARYLOG(pDefender->getOwner(), strBuffer.c_str(), pDefender->plot(), kAttacker.getOwner());3082		}30833084		// Move forward3085		if(targetPlot.getNumVisibleEnemyDefenders(&kAttacker) == 0)3086		{3087			kAttacker.UnitMove(&targetPlot, true, &kAttacker);3088		}30893090//		kAttacker.setMadeAttack(true);   /* EFB: Doesn't work, causes tactical AI to not dequeue this attack; but we've decided you don't lose your attack anyway */3091		eResult = ATTACK_COMPLETED;3092	}30933094	else if(!pDefender->IsCanDefend())3095	{3096		CvMissionDefinition kMission;3097		kMission.setMissionTime(kAttacker.getCombatTimer() * gDLL->getSecsPerTurn());3098		kMission.setMissionType(CvTypes::getMISSION_SURRENDER());3099		kMission.setUnit(BATTLE_UNIT_ATTACKER, &kAttacker);3100		kMission.setUnit(BATTLE_UNIT_DEFENDER, pDefender.pointer());3101		kMission.setPlot(&targetPlot);31023103		// Surrender mission3104		CvMissionInfo* pkSurrenderMission = GC.getMissionInfo(CvTypes::getMISSION_SURRENDER());3105		if(pkSurrenderMission == NULL)3106		{3107			CvAssert(false);3108		}3109		else3110		{3111			kAttacker.setCombatTimer(pkSurrenderMission->getTime());3112		}31133114		// Kill them!3115#if defined(MOD_UNITS_MAX_HP)3116		pDefender->setDamage(pDefender->GetMaxHitPoints());3117#else3118		pDefender->setDamage(GC.getMAX_HIT_POINTS());3119#endif31203121		Localization::String strMessage;3122		Localization::String strSummary;31233124		// Some units can't capture civilians. Embarked units are also not captured, they're simply killed. And some aren't a type that gets captured.3125		if(!kAttacker.isNoCapture() && (!pDefender->isEmbarked() || pDefender->getUnitInfo().IsCaptureWhileEmbarked()) && pDefender->getCaptureUnitType(GET_PLAYER(pDefender->getOwner()).getCivilizationType()) != NO_UNIT)3126		{3127			pDefender->setCapturingPlayer(kAttacker.getOwner());31283129			if(kAttacker.isBarbarian())3130			{3131				strMessage = Localization::Lookup("TXT_KEY_UNIT_CAPTURED_BARBS_DETAILED");3132				strMessage << pDefender->getUnitInfo().GetTextKey() << GET_PLAYER(kAttacker.getOwner()).getNameKey();3133				strSummary = Localization::Lookup("TXT_KEY_UNIT_CAPTURED_BARBS");3134			}3135			else3136			{3137				strMessage = Localization::Lookup("TXT_KEY_UNIT_CAPTURED_DETAILED");3138				strMessage << pDefender->getUnitInfo().GetTextKey();3139				strSummary = Localization::Lookup("TXT_KEY_UNIT_CAPTURED");3140			}3141		}3142		// Unit was killed instead3143		else3144		{3145			strMessage = Localization::Lookup("TXT_KEY_UNIT_LOST");3146			strSummary = strMessage;3147		}31483149		CvNotifications* pNotification = GET_PLAYER(pDefender->getOwner()).GetNotifications();3150		if(pNotification)3151			pNotification->Add(NOTIFICATION_UNIT_DIED, strMessage.toUTF8(), strSummary.toUTF8(), pDefender->getX(), pDefender->getY(), (int) pDefender->getUnitType(), pDefender->getOwner());31523153		bool bAdvance;3154		bAdvance = kAttacker.canAdvance(targetPlot, ((pDefender->IsCanDefend()) ? 1 : 0));31553156		// Move forward3157		if(targetPlot.getNumVisibleEnemyDefenders(&kAttacker) == 0)3158		{3159			kAttacker.UnitMove(&targetPlot, true, ((bAdvance) ? &kAttacker : NULL));3160		}31613162		// KWG: Should this be called? The defender is killed above and the unit.3163		//      If anything, the above code should be put in the ResolveCombat method.3164		ResolveCombat(kCombatInfo);3165		eResult = ATTACK_COMPLETED;3166	}3167	else3168	{3169		ATTACK_RESULT eSupportResult = ATTACK_ABORTED;3170		if(eOption != ATTACK_OPTION_NO_DEFENSIVE_SUPPORT)3171		{3172			// Ranged fire support from artillery units3173			CvUnit* pFireSupportUnit = GetFireSupportUnit(pDefender->getOwner(), pDefender->getX(), pDefender->getY(), kAttacker.getX(), kAttacker.getY());3174			if(pFireSupportUnit != NULL)3175			{3176				CvAssertMsg(!pFireSupportUnit->isDelayedDeath(), "Supporting battle unit is already dead!");3177				eSupportResult = AttackRanged(*pFireSupportUnit, kAttacker.getX(), kAttacker.getY(), CvUnitCombat::ATTACK_OPTION_NO_DEFENSIVE_SUPPORT);3178				// Turn off Fortify Turns, as this is the trigger for whether or not a ranged Unit can provide support fire (in addition to hasMadeAttack)3179				pFireSupportUnit->setFortifyTurns(0);3180			}31813182			if(eSupportResult == ATTACK_QUEUED)3183			{3184				// The supporting unit has queued their attack (against the attacker), we must have the attacker queue its attack.3185				// Also, flag the current mission that the next time through, the defender doesn't get any defensive support.3186				const_cast<MissionData*>(kAttacker.GetHeadMissionData())->iFlags |= MISSION_MODIFIER_NO_DEFENSIVE_SUPPORT;3187				CvUnitMission::WaitFor(&kAttacker, pFireSupportUnit);3188				eResult = ATTACK_QUEUED;3189			}3190		}31913192		if(eResult != ATTACK_QUEUED)3193		{3194			kAttacker.setMadeAttack(true);31953196			uint uiParentEventID = 0;3197			// Send the combat message if the target plot is visible.3198			bool isTargetVisibleToActivePlayer = targetPlot.isActiveVisible(false);3199			bool quickCombat = CvPreGame::quickCombat();3200			if(!quickCombat)3201			{3202				// Center camera here!3203				if(isTargetVisibleToActivePlayer)3204				{3205					auto_ptr<ICvPlot1> pDefenderPlot = GC.WrapPlotPointer(pDefender->plot());3206					GC.GetEngineUserInterface()->lookAt(pDefenderPlot.get(), CAMERALOOKAT_NORMAL);3207				}3208				kCombatInfo.setVisualizeCombat(isTargetVisibleToActivePlayer);32093210				auto_ptr<ICvCombatInfo1> pDllCombatInfo(new CvDllCombatInfo(&kCombatInfo));3211				uiParentEventID = gDLL->GameplayUnitCombat(pDllCombatInfo.get());32123213				// Set the combat units so that other missions do not continue until combat is over.3214				kAttacker.setCombatUnit(pDefender.pointer(), true);3215				pDefender->setCombatUnit(&kAttacker, false);32163217				eResult = ATTACK_QUEUED;3218			}3219			else3220				eResult = ATTACK_COMPLETED;32213222			// Resolve combat here.3223			ResolveCombat(kCombatInfo, uiParentEventID);32243225		}3226	}32273228	return eResult;3229}

Calls

Called by