Hooks
static bool BeforeCvUnit_UnitAttack(CvUnit* self, int iX, int iY, int iFlags, int iSteps, bool& result);static void AfterCvUnit_UnitAttack(CvUnit* self, int iX, int iY, int iFlags, int iSteps, bool& result);static bool ReplaceCvUnit_UnitAttack(bool (*original)(CvUnit*, int, int, int, int), CvUnit* self, int iX, int iY, int iFlags, int iSteps);CivRegisterBefore<CivHooks::CvUnit_UnitAttack>(host, &BeforeCvUnit_UnitAttack);CivRegisterAfter<CivHooks::CvUnit_UnitAttack>(host, &AfterCvUnit_UnitAttack);CivRegisterReplace<CivHooks::CvUnit_UnitAttack>(host, &ReplaceCvUnit_UnitAttack);
Code
22773// Returns true if attack was made...22774bool CvUnit::UnitAttack(int iX, int iY, int iFlags, int iSteps)22775{22776 VALIDATE_OBJECT22777 CvMap& kMap = GC.getMap();22778 CvPlot* pDestPlot = kMap.plot(iX, iY);2277922780 CvAssertMsg(pDestPlot != NULL, "DestPlot is not assigned a valid value");22781 if(!pDestPlot)22782 {22783 return false;22784 }2278522786#if defined(MOD_GLOBAL_BREAK_CIVILIAN_RESTRICTIONS)22787 if (MOD_GLOBAL_BREAK_CIVILIAN_RESTRICTIONS && IsCivilianUnit())22788 return false;22789#endif2279022791 // Test if this attack requires war to be declared first22792 if(isHuman() && getOwner() == GC.getGame().getActivePlayer() && pDestPlot->isVisible(getTeam()))22793 {22794 TeamTypes eRivalTeam = GetDeclareWarMove(*pDestPlot);2279522796 if(eRivalTeam != NO_TEAM)22797 {22798 CvPopupInfo kPopup(BUTTONPOPUP_DECLAREWARMOVE);22799 kPopup.iData1 = eRivalTeam;22800 kPopup.iData2 = pDestPlot->getX();22801 kPopup.iData3 = pDestPlot->getY();22802 kPopup.bOption1 = false;22803 kPopup.bOption2 = pDestPlot->getTeam() != eRivalTeam;22804 if(pDestPlot->isCity())22805 {22806 kPopup.iFlags = DOW_MOVE_ONTO_CITY;22807 }22808 // If a unit was present, put up the standard DOW message22809#if defined(MOD_BUGFIX_USE_GETTERS)22810 else if (pDestPlot->isVisibleOtherUnit(getOwner()))22811#else22812 else if (pDestPlot->isVisibleOtherUnit(m_eOwner))22813#endif22814 {22815 kPopup.iFlags = DOW_MOVE_ONTO_UNIT;22816 }22817 // Otherwise put out one about entering enemy territory22818 else22819 {22820 kPopup.iFlags = DOW_MOVE_INTO_TERRITORY;22821 }22822 DLLUI->AddPopup(kPopup);2282322824 return false;22825 }22826 }2282722828 const CvPathNodeArray& kPathNodeArray = GetPathNodeArray();2282922830 if(iFlags & MOVE_UNITS_THROUGH_ENEMY)22831 {22832 if(GeneratePath(pDestPlot, iFlags))22833 {22834 pDestPlot = GetPathFirstPlot();22835 }22836 }22837 else22838 {22839 if(getDomainType() != DOMAIN_AIR)22840 {22841 iSteps += 0;2284222843 UpdatePathCache(pDestPlot, iFlags);22844 }22845 }2284622847 CvAssertMsg(pDestPlot != NULL, "DestPlot is not assigned a valid value");2284822849 if(!pDestPlot)22850 {22851 return false;22852 }2285322854 bool bAttack = false;22855 bool bAdjacent = false;2285622857 // No path or air unit?22858 if(kPathNodeArray.size() == 0 || getDomainType() == DOMAIN_AIR)22859 {22860 // Manually check for adjacency22861 if((getDomainType() == DOMAIN_AIR) || (plotDistance(getX(), getY(), iX, iY) == 1))22862 {22863 if((iFlags & MISSION_MODIFIER_DIRECT_ATTACK) || (getDomainType() == DOMAIN_AIR) || (GeneratePath(pDestPlot, iFlags) && (GetPathFirstPlot() == pDestPlot)))22864 {22865 bAdjacent = true;22866 }22867 }22868 }22869 // Multi-turn move22870 else if(kPathNodeArray.size() != 0)22871 {22872 if(kPathNodeArray.size() > 1)22873 {22874 // Previous node is the same plot as the one before the destination (attack point)?22875 // Prevents unit from stopping while adjacent to the enemy, but on top of another unit so it has to move to another tile before it can attack22876 const CvPathNode& kNode = kPathNodeArray[1];22877 if(kNode.m_iX == getX() && kNode.m_iY == getY())22878 {22879 // The path may not be all the way to the destination, it may be only to the unit's turn limit, so check against the final destination22880 const CvPathNode& kDestNode = kPathNodeArray[0];22881 if (kDestNode.m_iX == iX && kDestNode.m_iY == iY)22882 {22883 bAdjacent = true;22884 }22885 }22886 }22887 }2288822889 if(bAdjacent)22890 {22891 if(!isOutOfAttacks() && (!IsCityAttackOnly() || pDestPlot->isEnemyCity(*this) || !pDestPlot->getBestDefender(NO_PLAYER)))22892 {22893 // don't allow an attack if we already have one22894 if(isFighting() || pDestPlot->isFighting())22895 {22896 return true;22897 }2289822899 // Air mission22900 if(getDomainType() == DOMAIN_AIR && GetBaseCombatStrength() == 0)22901 {22902 if(canRangeStrikeAt(iX, iY))22903 {22904 CvUnitCombat::AttackAir(*this, *pDestPlot, (iFlags & MISSION_MODIFIER_NO_DEFENSIVE_SUPPORT)?CvUnitCombat::ATTACK_OPTION_NO_DEFENSIVE_SUPPORT:CvUnitCombat::ATTACK_OPTION_NONE);22905 bAttack = true;22906 }22907 }2290822909 // City combat22910 else if(pDestPlot->isCity())22911 {22912 if(GET_TEAM(getTeam()).isAtWar(pDestPlot->getPlotCity()->getTeam()))22913 {22914 if(getDomainType() != DOMAIN_AIR)22915 {22916 // Ranged units that are embarked can't do a move-attack22917 if(isRanged() && isEmbarked())22918 {22919 return false;22920 }2292122922 CvUnitCombat::AttackCity(*this, *pDestPlot, (iFlags & MISSION_MODIFIER_NO_DEFENSIVE_SUPPORT)?CvUnitCombat::ATTACK_OPTION_NO_DEFENSIVE_SUPPORT:CvUnitCombat::ATTACK_OPTION_NONE);22923 bAttack = true;22924 }22925 }22926 }2292722928 // Normal unit combat22929 else22930 {22931 // if there are no defenders, do not attack22932 UnitHandle pBestDefender = pDestPlot->getBestDefender(NO_PLAYER, getOwner(), this, true);22933 if(!pBestDefender)22934 {22935 return false;22936 }2293722938 // Ranged units that are embarked can't do a move-attack22939 if(isRanged() && isEmbarked())22940 {22941 return false;22942 }2294322944 bAttack = true;22945 CvUnitCombat::Attack(*this, *pDestPlot, (iFlags & MISSION_MODIFIER_NO_DEFENSIVE_SUPPORT)?CvUnitCombat::ATTACK_OPTION_NO_DEFENSIVE_SUPPORT:CvUnitCombat::ATTACK_OPTION_NONE);22946 }2294722948 // Barb camp here that was attacked?22949 if(pDestPlot->getImprovementType() == GC.getBARBARIAN_CAMP_IMPROVEMENT())22950 {22951 CvBarbarians::DoCampAttacked(pDestPlot);22952 }22953 }22954 }2295522956 return bAttack;22957}