Hooks
static bool BeforeCvUnit_canMoveInto(const CvUnit* self, const CvPlot& plot, byte bMoveFlags, bool& result);static void AfterCvUnit_canMoveInto(const CvUnit* self, const CvPlot& plot, byte bMoveFlags, bool& result);static bool ReplaceCvUnit_canMoveInto(bool (*original)(const CvUnit*, const CvPlot&, byte), const CvUnit* self, const CvPlot& plot, byte bMoveFlags);CivRegisterBefore<CivHooks::CvUnit_canMoveInto>(host, &BeforeCvUnit_canMoveInto);CivRegisterAfter<CivHooks::CvUnit_canMoveInto>(host, &AfterCvUnit_canMoveInto);CivRegisterReplace<CivHooks::CvUnit_canMoveInto>(host, &ReplaceCvUnit_canMoveInto);
Code
3068bool CvUnit::canMoveInto(const CvPlot& plot, byte bMoveFlags) const3069{3070 VALIDATE_OBJECT3071 TeamTypes ePlotTeam;30723073 if(atPlot(plot))3074 {3075 return false;3076 }30773078 // Cannot move around in unrevealed land freely3079 if(!(bMoveFlags & MOVEFLAG_PRETEND_UNEMBARKED) && isNoRevealMap() && willRevealByMove(plot))3080 {3081 return false;3082 }30833084 // Barbarians have special restrictions early in the game3085 if(isBarbarian() && (GC.getGame().getGameTurn() < GC.getGame().GetBarbarianReleaseTurn()) && (plot.isOwned()))3086 {3087 return false;3088 }30893090 // Added in Civ 5: Destination plots can't allow stacked Units of the same type3091#if defined(MOD_GLOBAL_BREAK_CIVILIAN_RESTRICTIONS)3092 if((bMoveFlags & MOVEFLAG_DESTINATION) && (!MOD_GLOBAL_BREAK_CIVILIAN_RESTRICTIONS || !IsCivilianUnit()))3093#else3094 if(bMoveFlags & MOVEFLAG_DESTINATION)3095#endif3096 {3097 // Don't let another player's unit inside someone's city3098 if(!(bMoveFlags & MOVEFLAG_ATTACK) && !(bMoveFlags & MOVEFLAG_DECLARE_WAR))3099 {3100 if(plot.isCity() && plot.getPlotCity()->getOwner() != getOwner())3101 return false;3102 }31033104 // Check to see if any units are present at this full-turn move plot (borrowed from CvGameCoreUtils::pathDestValid())3105#if defined(MOD_GLOBAL_STACKING_RULES)3106 if(!(bMoveFlags & MOVEFLAG_IGNORE_STACKING) && plot.getUnitLimit() > 0)3107#else3108 if(!(bMoveFlags & MOVEFLAG_IGNORE_STACKING) && GC.getPLOT_UNIT_LIMIT() > 0)3109#endif3110 {3111 // pSelectionGroup has no Team but the HeadUnit does... ???3112#if defined(MOD_GLOBAL_STACKING_RULES)3113 if(plot.isVisible(getTeam()) && plot.getNumFriendlyUnitsOfType(this) >= plot.getUnitLimit())3114#else3115 if(plot.isVisible(getTeam()) && plot.getNumFriendlyUnitsOfType(this) >= GC.getPLOT_UNIT_LIMIT())3116#endif3117 {3118 return FALSE;3119 }3120 }3121 }31223123 if(isNoCapture())3124 {3125 if(!(bMoveFlags & MOVEFLAG_ATTACK))3126 {3127 if(plot.isEnemyCity(*this))3128 {3129 return false;3130 }3131 }3132 }31333134 if(bMoveFlags & MOVEFLAG_ATTACK)3135 {3136 if(isOutOfAttacks())3137 {3138#if defined(MOD_GLOBAL_CAPTURE_AFTER_ATTACKING)3139 // If there are only enemy civilians in the plot, then we don't need remaining attacks to capture them3140 // eg a worker in a barbarian camp where we just killed the defender3141 if (plot.getBestDefender(NO_PLAYER) != ((UnitHandle) NULL))3142 {3143 return false;3144 }3145#else3146 return false;3147#endif3148 }31493150 // Does unit only attack cities?3151 if(IsCityAttackOnly() && !plot.isEnemyCity(*this) && plot.getBestDefender(NO_PLAYER))3152 {3153 return false;3154 }3155 }31563157 // Can't enter an enemy city until it's "defeated"3158 if(plot.isEnemyCity(*this))3159 {3160 if(plot.getPlotCity()->getDamage() < plot.getPlotCity()->GetMaxHitPoints() && !(bMoveFlags & MOVEFLAG_ATTACK))3161 {3162 return false;3163 }3164 if(bMoveFlags & MOVEFLAG_ATTACK)3165 {3166 if(getDomainType() == DOMAIN_AIR)3167 return false;3168 if(isHasPromotion((PromotionTypes)GC.getPROMOTION_ONLY_DEFENSIVE()))3169 return false; // Can't advance into an enemy city3170 }3171 }31723173 if(getDomainType() == DOMAIN_AIR)3174 {3175 if(bMoveFlags & MOVEFLAG_ATTACK)3176 {3177 if(!canRangeStrikeAt(plot.getX(), plot.getY()))3178 {3179 return false;3180 }3181 }3182 }3183 else3184 {3185 if(bMoveFlags & MOVEFLAG_ATTACK)3186 {3187 if(!IsCanAttack()) // trying to give an attack order to a unit that can't fight. That doesn't work!3188 {3189 return false;3190 }31913192 if(getDomainType() == DOMAIN_LAND && plot.isWater() && !canMoveAllTerrain() && !plot.IsAllowsWalkWater())3193 {3194 return false;3195 }31963197 if(!isHuman() || (plot.isVisible(getTeam())))3198 {3199 // This stuff to the next if statement is to get units to advance into a tile with an enemy if that enemy is dying...3200 bool bCanAdvanceOnDeadUnit = false;32013202 const IDInfo* pUnitNode = plot.headUnitNode();3203 const CvUnit* pLoopUnit;32043205 bool bPlotContainsCombat = false;3206 while(pUnitNode != NULL)3207 {3208 pLoopUnit = ::getUnit(*pUnitNode);3209 CvAssertMsg(pLoopUnit, "pUnitNode data should lead to a unit");32103211 pUnitNode = plot.nextUnitNode(pUnitNode);32123213 // NULL check is always a good thing to do.3214 if(pLoopUnit)3215 {3216 if(GET_TEAM(getTeam()).isAtWar(GET_PLAYER(pLoopUnit->getOwner()).getTeam()))3217 {3218 if(!pLoopUnit->IsDead() && pLoopUnit->isInCombat())3219 {3220 if(pLoopUnit->getCombatUnit() != this)3221 bPlotContainsCombat = true;3222 }32233224 if(pLoopUnit->IsDead() || !pLoopUnit->IsCombatUnit())3225 {3226 bCanAdvanceOnDeadUnit = true;3227 }3228 else3229 {3230 bCanAdvanceOnDeadUnit = false;3231 break;3232 }3233 }3234 }3235 }32363237 if(bPlotContainsCombat)3238 {3239 return false; // Can't enter a plot that contains combat that doesn't involve us.3240 }32413242 if(!bCanAdvanceOnDeadUnit)3243 {3244 if(plot.isVisibleEnemyUnit(this) != (bMoveFlags & MOVEFLAG_ATTACK))3245 {3246 // Prevent an attack from failing if a city is empty but still an "enemy" capable of being attacked (this wouldn't happen before in Civ 4)3247 if(!(bMoveFlags & MOVEFLAG_ATTACK) || !plot.isEnemyCity(*this))3248 {3249 if(!(bMoveFlags & MOVEFLAG_DECLARE_WAR) || (plot.isVisibleOtherUnit(getOwner()) != (bMoveFlags & MOVEFLAG_ATTACK) && !((bMoveFlags & MOVEFLAG_ATTACK) && plot.getPlotCity() && !isNoCapture())))3250 {3251 return false;3252 }3253 }3254 }3255 }3256 }32573258 if(plot.isVisible(getTeam()))3259 {3260 const UnitHandle pDefender = plot.getBestDefender(NO_PLAYER, getOwner(), this, true);3261 if(pDefender)3262 {3263 if(pDefender->getDamage() >= GetCombatLimit())3264 {3265 return false;3266 }32673268 // EFB: Check below is not made when capturing civilians3269 else if(pDefender->GetBaseCombatStrength() > 0) // Note: this value will be 0 for embarked Units3270 {3271 // EFB: Added so units can't come out of cities to attack (but so that units in city's pathing doesn't fail all the time)3272 if(!(bMoveFlags & MOVEFLAG_NOT_ATTACKING_THIS_TURN) && !IsCanAttackWithMoveNow())3273 {3274 return false;3275 }3276 }3277 }3278 }3279 }3280 else //if !(bMoveFlags & MOVEFLAG_ATTACK)3281 {3282 bool bEmbarkedAndAdjacent = false;3283 bool bEnemyUnitPresent = false;32843285 // Without this code, Embarked Units can move on top of enemies because they have no visibility3286 if(isEmbarked() || (bMoveFlags & MOVEFLAG_PRETEND_EMBARKED))3287 {3288 if(plotDistance(getX(), getY(), plot.getX(), plot.getY()) == 1)3289 {3290 bEmbarkedAndAdjacent = true;3291 }3292 }32933294 bool bPlotContainsCombat = false;3295 if(plot.getNumUnits())3296 {3297 for(int iUnitLoop = 0; iUnitLoop < plot.getNumUnits(); iUnitLoop++)3298 {3299 CvUnit* loopUnit = plot.getUnitByIndex(iUnitLoop);33003301 if(loopUnit && GET_TEAM(getTeam()).isAtWar(plot.getUnitByIndex(iUnitLoop)->getTeam()))3302 {3303 bEnemyUnitPresent = true;3304 if(!loopUnit->IsDead() && loopUnit->isInCombat())3305 {3306 if(loopUnit->getCombatUnit() != this)3307 bPlotContainsCombat = true;3308 }3309 break;3310 }3311 }3312 }33133314 if(bPlotContainsCombat)3315 {3316 return false; // Can't enter a plot that contains combat that doesn't involve us.3317 }33183319 if(!isHuman() || plot.isVisible(getTeam()) || bEmbarkedAndAdjacent)3320 {3321 if(plot.isEnemyCity(*this))3322 {3323 return false;3324 }33253326 if(plot.isVisibleEnemyUnit(this) || (bEmbarkedAndAdjacent && bEnemyUnitPresent))3327 {3328 return false;3329 }3330 }3331 }33323333 ePlotTeam = ((isHuman()) ? plot.getRevealedTeam(getTeam()) : plot.getTeam());33343335 if(!canEnterTerritory(ePlotTeam, false /*bIgnoreRightOfPassage*/, plot.isCity(), bMoveFlags & MOVEFLAG_DECLARE_WAR))3336 {3337 CvAssert(ePlotTeam != NO_TEAM);33383339#if defined(MOD_EVENTS_WAR_AND_PEACE)3340 if(!(GET_TEAM(getTeam()).canDeclareWar(ePlotTeam, getOwner())))3341#else3342 if(!(GET_TEAM(getTeam()).canDeclareWar(ePlotTeam)))3343#endif3344 {3345 return false;3346 }33473348 if(isHuman())3349 {3350 if(!(bMoveFlags & MOVEFLAG_DECLARE_WAR))3351 {3352 return false;3353 }3354 }3355 else3356 {3357 return false;3358 }3359 }3360 }33613362#if defined(MOD_EVENTS_CAN_MOVE_INTO)3363 if (MOD_EVENTS_CAN_MOVE_INTO && m_pUnitInfo->IsSendCanMoveIntoEvent()) {3364 if (GAMEEVENTINVOKE_TESTALL(GAMEEVENT_CanMoveInto, getOwner(), GetID(), plot.getX(), plot.getY(), ((bMoveFlags & MOVEFLAG_ATTACK) != 0), ((bMoveFlags & MOVEFLAG_DECLARE_WAR) != 0)) == GAMEEVENTRETURN_FALSE) {3365 return false;3366 }3367 }3368#endif33693370 // Make sure we can enter the terrain. Somewhat expensive call, so we do this last.3371 if(!canEnterTerrain(plot, bMoveFlags))3372 {3373 return false;3374 }33753376 return true;3377}