Subversion Repositories RAND

Rev

Rev 1025 | Rev 1033 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

// unit.cpp

#include "CvGameCoreDLL.h"
#include "CvUnit.h"
#include "CvArea.h"
#include "CvPlot.h"
#include "CvCity.h"
#include "CvGlobals.h"
#include "CvGameCoreUtils.h"
#include "CvGameAI.h"
#include "CvMap.h"
#include "CvViewport.h"
#include "CvPlayerAI.h"
#include "CvRandom.h"
#include "CvTeamAI.h"
#include "CvGameCoreUtils.h"
#include "CyUnit.h"
#include "CyArgsList.h"
#include "CyPlot.h"
#include "CvDLLEntityIFaceBase.h"
#include "CvDLLInterfaceIFaceBase.h"
#include "CvDLLEngineIFaceBase.h"
#include "CvEventReporter.h"
#include "CvDLLPythonIFaceBase.h"
#include "CvDLLFAStarIFaceBase.h"
#include "CvInfos.h"
#include "FProfiler.h"
#include "CvPopupInfo.h"
#include "CvInitCore.h"
#include "CvArtFileMgr.h"

// BUG - start
#include "CvBugOptions.h"
// BUG - end

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/24/10                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
#include "BetterBTSAI.h"
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

static CvEntity* g_dummyEntity = NULL;
static CvUnit*   g_dummyUnit = NULL;
static int               g_numEntities = 0;
static int               g_dummyUsage = 0;
static bool              g_bUseDummyEntities = false;

bool CvUnit::isDummyEntity(const CvEntity* entity)
{
        return (entity == g_dummyEntity);
}

bool CvUnit::isRealEntity(const CvEntity* entity)
{
        return (entity != NULL && entity != g_dummyEntity);
}

// Public Functions...
#pragma warning( disable : 4355 )
CvUnit::CvUnit(bool bIsDummy) : m_GameObject(this),
m_Properties(this)
{
        m_aiExtraDomainModifier = new int[NUM_DOMAIN_TYPES];
/************************************************************************************************/
/* Afforess                       Start          03/1/10                       Coded By: KillMePlease   */
/*                                                                                              */
/* Great Commanders                                                                             */
/************************************************************************************************/
        m_paiTerrainProtected = NULL;
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        m_pabHasPromotion = NULL;

        m_paiTerrainDoubleMoveCount = NULL;
        m_paiFeatureDoubleMoveCount = NULL;
        m_paiExtraTerrainAttackPercent = NULL;
        m_paiExtraTerrainDefensePercent = NULL;
        m_paiExtraFeatureAttackPercent = NULL;
        m_paiExtraFeatureDefensePercent = NULL;
        m_paiExtraUnitCombatModifier = NULL;

        m_iMaxMoveCacheTurn = -1;

        if ( g_dummyUnit == NULL && !bIsDummy )
        {
                g_dummyUnit = new CvUnitAI(true);

                if ( GC.getDefineINT("ENABLE_DYNAMIC_UNIT_ENTITIES") )
                {
                        g_bUseDummyEntities = true;
                }
        }

        if ( g_bUseDummyEntities )
        {
                if ( g_dummyEntity == NULL )
                {
                        CvDLLEntity::createUnitEntity(this);            // create and attach entity to unit

                        g_dummyEntity = getEntity();
                }
                else
                {
                        setEntity(g_dummyEntity);
                        g_dummyUsage++;
                }
        }
        else
        {
                CvDLLEntity::createUnitEntity(this);            // create and attach entity to unit
        }

        bGraphicsSetup = false;

        reset(0, NO_UNIT, NO_PLAYER, true);
}


CvUnit::~CvUnit()
{
        if ( !isUsingDummyEntities() )
        {
                if (!gDLL->GetDone() && GC.IsGraphicsInitialized())                                             // don't need to remove entity when the app is shutting down, or crash can occur
                {
                        gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
                        CvDLLEntity::removeEntity();            // remove entity from engine
                }

                CvDLLEntity::destroyEntity();                   // delete CvUnitEntity and detach from us
        }

        uninit();

        SAFE_DELETE_ARRAY(m_aiExtraDomainModifier);
}

bool CvUnit::isUsingDummyEntities(void)
{
        CvEntity* entity = getEntity();

        return (entity != NULL && g_dummyEntity == entity);// || (m_eUnitType == 701);
}

void CvUnit::reloadEntity(bool bForceLoad)
{
        bool    bNeedsRealEntity = !g_bUseDummyEntities || bForceLoad || (plot() != NULL && plot()->isActiveVisible(false) && (plot()->getCenterUnit() == this || getOwnerINLINE() == GC.getGameINLINE().getActivePlayer()));

        //OutputDebugString(CvString::format("reloadEntity for %08lx\n", this).c_str());
        if ( !IsSelected() )
        {
                BeginDLLSerialization();

                if ( !isUsingDummyEntities() ) //&& !bNeedsRealEntity )
                {
                        //destroy old entity
                        if (!gDLL->GetDone() && GC.IsGraphicsInitialized())                                             // don't need to remove entity when the app is shutting down, or crash can occur
                        {
                                gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
                                CvDLLEntity::removeEntity();            // remove entity from engine
                        }

                        CvDLLEntity::destroyEntity();                   // delete CvUnitEntity and detach from us
                        g_numEntities--;

                        setEntity(NULL);
                }
                else if ( isUsingDummyEntities() && bNeedsRealEntity )
                {
                        g_dummyUsage--;

                        setEntity(NULL);
                }

                if ( getEntity() == NULL )
                {
                        if ( g_bUseDummyEntities )
                        {
                                if ( bNeedsRealEntity )
                                {
                                        //create new one
                                        CvDLLEntity::createUnitEntity(this);            // create and attach entity to unit
                                        g_numEntities++;

                                        bGraphicsSetup = false;
                                }
                                else
                                {
                                        setEntity(g_dummyEntity);
                                        g_dummyUsage++;
                                }

                                //      Log every now and again in non final release builds
                                if ( g_numEntities%100 == 0 )
                                {
                                        OutputDebugString(CvString::format("Dummy unit entity usage: %d, real %d\n", g_dummyUsage, g_numEntities).c_str());
                                }
                        }
                        else
                        {
                                //create new one
                                if ( plot() != NULL )
                                {
                                        CvDLLEntity::createUnitEntity(this);            // create and attach entity to unit

                                        bGraphicsSetup = false;
                                }
                        }
                }

                if ( !bGraphicsSetup && bNeedsRealEntity && plot() != NULL )
                {
                        setupGraphical();

                        bGraphicsSetup = true;
                }

                EndDLLSerialization();
        }
        else
        {
                OutputDebugString("Reload of selected unit\n");
        }
}

void CvUnit::changeIdentity(UnitTypes eUnit)
{
        reset(getID(), eUnit, getOwnerINLINE(), false, true);
        //      Same id is now a differnt unit - make sure no old cached path info
        //      gets used for it
        CvPlot::NextCachePathEpoch();
}

void CvUnit::init(int iID, UnitTypes eUnit, UnitAITypes eUnitAI, PlayerTypes eOwner, int iX, int iY, DirectionTypes eFacingDirection, int iBirthmark)
{
        CvWString szBuffer;
        int iUnitName;
        int iI, iJ;

        FAssert(NO_UNIT != eUnit);

        //      If the current viewport is not yet initialized center it on the first unit created for the active player
        if ( GC.getGameINLINE().getActivePlayer() == eOwner && GC.getCurrentViewport()->getState() == VIEWPORT_MODE_UNINITIALIZED && UNIT_BIRTHMARK_TEMP_UNIT != iBirthmark )
        {
                GC.getCurrentViewport()->setOffsetToShow(iX, iY);
        }

        //--------------------------------
        // Init saved data
        reset(iID, eUnit, eOwner);

        if ( eOwner != NO_PLAYER && eUnitAI == UNITAI_SUBDUED_ANIMAL)
        {
                GET_PLAYER(eOwner).NoteAnimalSubdued();
        }
        //      Koshling -  moved this earlier to get unitAI set up so that
        //      constraint checking on the unitAI can work more uniformly
        AI_init(eUnitAI, iBirthmark);

        if(eFacingDirection == NO_DIRECTION)
                m_eFacingDirection = DIRECTION_SOUTH;
        else
                m_eFacingDirection = eFacingDirection;

        //--------------------------------
        // Init containers

        //--------------------------------
        // Init pre-setup() data
        setXY(iX, iY, false);

        if ( getGroup() == NULL )
        {
        //TB OOS fix - POSSIBLE that this represents a fix but I consider it a longshot since they should really mean the same thing (-1)
                ::MessageBox(NULL,
                                        getGroupID() == FFreeList::INVALID_INDEX ? "Unit with NULL group ID after set position in init\n" : "Unit with no group after set position in init\n",
                                        "CvGameCoreDLL Diagnostics",
                                        MB_OK);
        }

        if ( !isTempUnit() )
        {
                //--------------------------------
                // Init non-saved data
                setupGraphical();

                //--------------------------------
                // Init other game data
                plot()->updateCenterUnit();

                plot()->setFlagDirty(true);

                iUnitName = GC.getGameINLINE().getUnitCreatedCount(getUnitType());
                int iNumNames = m_pUnitInfo->getNumUnitNames();
                if (iUnitName < iNumNames)
                {
                        int iOffset = GC.getGameINLINE().getSorenRandNum(iNumNames, "Unit name selection");

                        for (iI = 0; iI < iNumNames; iI++)
                        {
                                int iIndex = (iI + iOffset) % iNumNames;
                                CvWString szName = gDLL->getText(m_pUnitInfo->getUnitNames(iIndex));
                                if (!GC.getGameINLINE().isGreatPersonBorn(szName))
                                {
                                        setName(szName);
                                        GC.getGameINLINE().addGreatPersonBornName(szName);
                                        break;
                                }
                        }
                }

                setGameTurnCreated(GC.getGameINLINE().getGameTurn());

                GC.getGameINLINE().incrementUnitCreatedCount(getUnitType());

                GC.getGameINLINE().incrementUnitClassCreatedCount((UnitClassTypes)(m_pUnitInfo->getUnitClassType()));
                GET_TEAM(getTeam()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);
                GET_PLAYER(getOwnerINLINE()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);

                GET_PLAYER(getOwnerINLINE()).changeExtraUnitCost(m_pUnitInfo->getExtraCost());

                if (m_pUnitInfo->getNukeRange() != -1)
                {
                        GET_PLAYER(getOwnerINLINE()).changeNumNukeUnits(1);
                }

                if (m_pUnitInfo->isMilitarySupport())
                {
                        GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(1);
                }

                GET_PLAYER(getOwnerINLINE()).changeAssets(m_pUnitInfo->getAssetValue());

                GET_PLAYER(getOwnerINLINE()).changeUnitPower(m_pUnitInfo->getPowerValue());

                //doSetFreePromotions();

        for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
        {
                if (m_pUnitInfo->getFreePromotions(iI))
                {
                        setHasPromotion(((PromotionTypes)iI), true);
                }
        }
/************************************************************************************************/
/* Afforess                       Start          08/26/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
/*
        FAssertMsg((GC.getNumTraitInfos() > 0), "GC.getNumTraitInfos() is less than or equal to zero but is expected to be larger than zero in CvUnit::init");
        for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
        {
                if (GET_PLAYER(getOwnerINLINE()).hasTrait((TraitTypes)iI))
                {
                        for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
                        {
                                if (GC.getTraitInfo((TraitTypes) iI).isFreePromotion(iJ))
                                {
                                        if ((getUnitCombatType() != NO_UNITCOMBAT) && GC.getTraitInfo((TraitTypes) iI).isFreePromotionUnitCombat(getUnitCombatType()))
                                        {
                                                setHasPromotion(((PromotionTypes)iJ), true);
                                        }
                                }
                        }
                }
        }
*/

        if (getUnitCombatType() != NO_UNITCOMBAT)
        {
                for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
                {
                        if (GET_PLAYER(getOwnerINLINE()).hasTrait((TraitTypes)iI))
                        {
                                for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
                                {
                                        if (GC.getTraitInfo((TraitTypes) iI).isFreePromotionUnitCombats(iJ, getUnitCombatType()))
                                        {
                                                setHasPromotion(((PromotionTypes)iJ), true);
                                        }
                                }
                        }
                }
        }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        if (NO_UNITCOMBAT != getUnitCombatType())
        {
                for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
                {
                        if (GET_PLAYER(getOwnerINLINE()).isFreePromotion(getUnitCombatType(), (PromotionTypes)iJ))
                        {
                                setHasPromotion(((PromotionTypes)iJ), true);
                        }
                }
        }

        if (NO_UNITCLASS != getUnitClassType())
        {
                for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
                {
                        if (GET_PLAYER(getOwnerINLINE()).isFreePromotion(getUnitClassType(), (PromotionTypes)iJ))
                        {
                                setHasPromotion(((PromotionTypes)iJ), true);
                        }
                }
        }

                if (getDomainType() == DOMAIN_LAND)
                {
                        if (baseCombatStr() > 0)
                        {
                                if ((GC.getGameINLINE().getBestLandUnit() == NO_UNIT) || (baseCombatStr() > GC.getGameINLINE().getBestLandUnitCombat()))
                                {
                                        GC.getGameINLINE().setBestLandUnit(getUnitType());
                                }
                        }
                }

                if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
                {
                        gDLL->getInterfaceIFace()->setDirty(GameData_DIRTY_BIT, true);
                }

                if (isWorldUnitClass((UnitClassTypes)(m_pUnitInfo->getUnitClassType())))
                {
                        for (iI = 0; iI < MAX_PLAYERS; iI++)
                        {
                                if (GET_PLAYER((PlayerTypes)iI).isAlive())
                                {
                                        MEMORY_TRACK_EXEMPT();

                                        if (GET_TEAM(getTeam()).isHasMet(GET_PLAYER((PlayerTypes)iI).getTeam()))
                                        {
                                                szBuffer = gDLL->getText("TXT_KEY_MISC_SOMEONE_CREATED_UNIT", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey());
                                                AddDLLMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
                                        }
                                        else
                                        {
                                                szBuffer = gDLL->getText("TXT_KEY_MISC_UNKNOWN_CREATED_UNIT", getNameKey());
                                                AddDLLMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"));
                                        }
                                }
                        }

                        szBuffer = gDLL->getText("TXT_KEY_MISC_SOMEONE_CREATED_UNIT", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey());
                        GC.getGameINLINE().addReplayMessage(REPLAY_MESSAGE_MAJOR_EVENT, getOwnerINLINE(), szBuffer, getX_INLINE(), getY_INLINE(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"));
                }

                CvEventReporter::getInstance().unitCreated(this);
        }
}


void CvUnit::uninit()
{
}


// FUNCTION: reset()
// Initializes data members that are serialized.
void CvUnit::reset(int iID, UnitTypes eUnit, PlayerTypes eOwner, bool bConstructorCall, bool bIdentityChange)
{
        int iI;

        //--------------------------------
        // Uninit class
        uninit();

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
        // Dale - RB: Field Bombard START
        m_iDCMBombRange = 0;
        m_iDCMBombAccuracy = 0;
        // Dale - RB: Field Bombard END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/
        // < M.A.D. Nukes Start >
        m_bMADEnabled = false;
        m_bForcedMove = false;
        m_iMADTargetPlotX = INVALID_PLOT_COORD;
        m_iMADTargetPlotY = INVALID_PLOT_COORD;
        m_pMADTargetPlotOwner = NO_PLAYER;
        // < M.A.D. Nukes End   >

        m_iID = iID;
        if ( !bIdentityChange )
        {
                m_iGroupID = FFreeList::INVALID_INDEX;
        }
        m_iHotKeyNumber = -1;
        m_iX = INVALID_PLOT_COORD;
        m_iY = INVALID_PLOT_COORD;
        m_iLastMoveTurn = 0;
        m_iReconX = INVALID_PLOT_COORD;
        m_iReconY = INVALID_PLOT_COORD;
        m_iGameTurnCreated = 0;
        m_iDamage = 0;
        m_iMoves = 0;
        m_iExperience = 0;
        m_iLevel = 1;
        m_iCargo = 0;
        m_iAttackPlotX = INVALID_PLOT_COORD;
        m_iAttackPlotY = INVALID_PLOT_COORD;
        m_iCombatTimer = 0;
        m_iCombatFirstStrikes = 0;
        m_iFortifyTurns = 0;
        m_iBlitzCount = 0;
        m_iAmphibCount = 0;
        m_iRiverCount = 0;
        m_iEnemyRouteCount = 0;
        m_iAlwaysHealCount = 0;
        m_iHillsDoubleMoveCount = 0;
        m_iImmuneToFirstStrikesCount = 0;
        m_iIsPirateCount = 0;
        m_iOneUpCount = 0;
        m_iExtraVisibilityRange = 0;
        m_iExtraMoves = 0;
        m_iExtraMoveDiscount = 0;
        m_iExtraAirRange = 0;
        m_iExtraIntercept = 0;
        m_iExtraEvasion = 0;
        m_iExtraFirstStrikes = 0;
        m_iExtraChanceFirstStrikes = 0;
        m_iExtraWithdrawal = 0;
        m_iExtraStrength = 0;
        m_iExtraCollateralDamage = 0;
        m_iExtraBombardRate = 0;
        m_iExtraEnemyHeal = 0;
        m_iExtraNeutralHeal = 0;
        m_iExtraFriendlyHeal = 0;
        m_iSameTileHeal = 0;
        m_iAdjacentTileHeal = 0;
        m_iExtraCombatPercent = 0;
        m_iExtraCityAttackPercent = 0;
        m_iExtraCityDefensePercent = 0;
        m_iExtraHillsAttackPercent = 0;
        m_iExtraHillsDefensePercent = 0;
        m_iRevoltProtection = 0;
        m_iCollateralDamageProtection = 0;
        m_iPillageChange = 0;
        m_iUpgradeDiscount = 0;
        m_iExperiencePercent = 0;
        m_iKamikazePercent = 0;
        m_eFacingDirection = DIRECTION_SOUTH;
        m_iImmobileTimer = 0;
//Team Project (2)
/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 21.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: New Tag Definition                                                               **/
/**  Notes:                                                                                         **/
/*****************************************************************************************************/
        m_bCanRespawn = false;
        m_bSurvivor = false;
/*****************************************************************************************************/
/**  TheLadiesOgre; 21.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/
        m_bMadeAttack = false;
        m_bMadeInterception = false;
        m_bPromotionReady = false;
        m_bDeathDelay = false;
        m_bCombatFocus = false;
        m_bInfoBarDirty = false;
        m_bBlockading = false;
        m_bAirCombat = false;
/************************************************************************************************/
/* Afforess                       Start          02/14/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        m_iCanMovePeaksCount = 0;
        //      Koshling - enhanced mountaineering mode to differentiate between ability to move through
        //      mountains, and ability to lead a stack through mountains
        m_iCanLeadThroughPeaksCount = 0;

        if ( eUnit != NO_UNIT )
        {
                m_movementCharacteristicsHash = GC.getUnitInfo(eUnit).getZobristValue();
        }

        m_iSleepTimer = 0;
        //@MOD Commanders: reset parameters
        m_iOnslaughtCount = 0;
        m_iExtraCommandRange = 0;
        m_iExtraControlPoints = 0;
        m_iControlPointsLeft = 0;
        m_iCommanderID = -1;
        m_iCommanderCacheTurn = -1;
        m_eOriginalOwner = eOwner;
        m_bCommander = false;
        m_iZoneOfControlCount = 0;
        m_bAutoPromoting = false;
        m_bAutoUpgrading = false;
        m_shadowUnit.reset();
        m_eDesiredDiscoveryTech = NO_TECH;
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
        m_eOwner = eOwner;
        m_eCapturingPlayer = NO_PLAYER;
        m_eUnitType = eUnit;
        m_pUnitInfo = (NO_UNIT != m_eUnitType) ? &GC.getUnitInfo(m_eUnitType) : NULL;
        m_iBaseCombat = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCombat() : 0;
        m_eLeaderUnitType = NO_UNIT;
        m_iCargoCapacity = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCargoSpace() : 0;
// Thomas SG - AC: Advanced Cargo START
        m_iTotalCargoCapacity = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getTotalCargoSpace() : 0;
// Thomas SG - AC: Advanced Cargo END
        m_combatUnit.reset();
        m_transportUnit.reset();

        for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
        {
                m_aiExtraDomainModifier[iI] = 0;
        }

        m_szName.clear();
        m_szScriptData ="";

        if (!bConstructorCall)
        {
                FAssertMsg((0 < GC.getNumPromotionInfos()), "GC.getNumPromotionInfos() is not greater than zero but an array is being allocated in CvUnit::reset");
                m_pabHasPromotion = new bool[GC.getNumPromotionInfos()];
                for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
                {
                        m_pabHasPromotion[iI] = false;
                }

                FAssertMsg((0 < GC.getNumTerrainInfos()), "GC.getNumTerrainInfos() is not greater than zero but a float array is being allocated in CvUnit::reset");
                //m_paiTerrainDoubleMoveCount = new int[GC.getNumTerrainInfos()];
                //m_paiExtraTerrainAttackPercent = new int[GC.getNumTerrainInfos()];
                //m_paiExtraTerrainDefensePercent = new int[GC.getNumTerrainInfos()];
/************************************************************************************************/
/* Afforess                       Start          06/14/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                SAFE_DELETE_ARRAY(m_paiTerrainProtected);
                SAFE_DELETE_ARRAY(m_paiTerrainDoubleMoveCount);
                SAFE_DELETE_ARRAY(m_paiExtraTerrainAttackPercent);
                SAFE_DELETE_ARRAY(m_paiExtraTerrainDefensePercent);
                SAFE_DELETE_ARRAY(m_paiFeatureDoubleMoveCount);
                SAFE_DELETE_ARRAY(m_paiExtraFeatureDefensePercent);
                SAFE_DELETE_ARRAY(m_paiExtraFeatureAttackPercent);
                SAFE_DELETE_ARRAY(m_paiExtraUnitCombatModifier);
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                /*
                for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
                {
                        m_paiTerrainDoubleMoveCount[iI] = 0;
                        m_paiExtraTerrainAttackPercent[iI] = 0;
                        m_paiExtraTerrainDefensePercent[iI] = 0;
                }
                */


                /*
                FAssertMsg((0 < GC.getNumFeatureInfos()), "GC.getNumFeatureInfos() is not greater than zero but a float array is being allocated in CvUnit::reset");
                m_paiFeatureDoubleMoveCount = new int[GC.getNumFeatureInfos()];
                m_paiExtraFeatureDefensePercent = new int[GC.getNumFeatureInfos()];
                m_paiExtraFeatureAttackPercent = new int[GC.getNumFeatureInfos()];
                for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
                {
                        m_paiFeatureDoubleMoveCount[iI] = 0;
                        m_paiExtraFeatureAttackPercent[iI] = 0;
                        m_paiExtraFeatureDefensePercent[iI] = 0;
                }
                */

               
                /*
                FAssertMsg((0 < GC.getNumUnitCombatInfos()), "GC.getNumUnitCombatInfos() is not greater than zero but an array is being allocated in CvUnit::reset");
                m_paiExtraUnitCombatModifier = new int[GC.getNumUnitCombatInfos()];
                for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
                {
                        m_paiExtraUnitCombatModifier[iI] = 0;
                }
                */


                m_unitCombatKeyedInfo.clear();

                if ( !bIdentityChange )
                {
                        AI_reset(NO_UNITAI, true);
                }
        }

        m_Properties.clear();
}


//////////////////////////////////////
// graphical only setup
//////////////////////////////////////
void CvUnit::setupGraphical()
{
        PROFILE_FUNC();

        if (!GC.IsGraphicsInitialized())
        {
                return;
        }

        if (!isInViewport())
        {
                return;
        }

        if ( !isUsingDummyEntities() )
        {
                CvDLLEntity::setup();
        }

        if (getGroup()->getActivityType() == ACTIVITY_INTERCEPT)
        {
                airCircle(true);
        }
}


void CvUnit::convert(CvUnit* pUnit)
{
        PROFILE_FUNC();

        CvPlot* pPlot = plot();

        for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
        {
                setHasPromotion(((PromotionTypes)iI), (pUnit->isHasPromotion((PromotionTypes)iI) || m_pUnitInfo->getFreePromotions(iI)));
        }

        setGameTurnCreated(pUnit->getGameTurnCreated());
        setDamage(pUnit->getDamage());
        setMoves(pUnit->getMoves());
/************************************************************************************************/
/* Afforess                       Start          06/06/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        m_eOriginalOwner = pUnit->getOriginalOwner();
        setAutoPromoting(pUnit->isAutoPromoting());
        setAutoUpgrading(pUnit->isAutoUpgrading());
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
        setLevel(pUnit->getLevel());
        int iOldModifier = std::max(1, 100 + GET_PLAYER(pUnit->getOwnerINLINE()).getLevelExperienceModifier());
        int iOurModifier = std::max(1, 100 + GET_PLAYER(getOwnerINLINE()).getLevelExperienceModifier());
        setExperience100(std::max(0, (pUnit->getExperience100() * iOurModifier) / iOldModifier));

        setName(pUnit->getNameNoDesc());
// BUG - Unit Name - start
        if (pUnit->isDescInName() && getBugOptionBOOL("MiscHover__UpdateUnitNameOnUpgrade", true, "BUG_UPDATE_UNIT_NAME_ON_UPGRADE"))
        {
/************************************************************************************************/
/* Afforess                       Start          08/24/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
/*
                CvWString szUnitType(pUnit->m_pUnitInfo->getDescription());

                m_szName.replace(m_szName.find(szUnitType), szUnitType.length(), m_pUnitInfo->getDescription());
*/

                CvWString szUnitType(pUnit->getDescription());

                m_szName.replace(m_szName.find(szUnitType), szUnitType.length(), getDescription());
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

                //szUnitType.Format(L"%s", pUnit->m_pUnitInfo->getDescription());

        }
// BUG - Unit Name - end
        setLeaderUnitType(pUnit->getLeaderUnitType());

        CvUnit* pTransportUnit = pUnit->getTransportUnit();
        if (pTransportUnit != NULL)
        {
                pUnit->setTransportUnit(NULL);
                setTransportUnit(pTransportUnit);
        }

        std::vector<CvUnit*> aCargoUnits;
        pUnit->getCargoUnits(aCargoUnits);
        for (uint i = 0; i < aCargoUnits.size(); ++i)
        {
// Thomas SG - AC: Advanced Cargo START
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       10/30/09                     Mongoose & jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* original BTS code
                aCargoUnits[i]->setTransportUnit(this);
*/

                // From Mongoose SDK
                // Check cargo types and capacity when upgrading transports
                int freeSpace = cargoSpaceAvailable(NO_SPECIALUNIT, aCargoUnits[i]->getDomainType());
                {
                        for (int iK = 0; iK < aCargoUnits[i]->getNumSpecialUnitTypes(); iK++)
                        {
                                freeSpace = std::max(freeSpace,cargoSpaceAvailable(aCargoUnits[i]->getSpecialUnitType(iK), aCargoUnits[i]->getDomainType()));
                        }
                        if (freeSpace > 0)
                        {
                                aCargoUnits[i]->setTransportUnit(this);
                        }
                        else
                        {
                                aCargoUnits[i]->setTransportUnit(NULL);
                                aCargoUnits[i]->jumpToNearestValidPlot();
                        }
                }
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/
// Thomas SG - AC: Advanced Cargo END
        }

        pUnit->getGroup()->AI_setMissionAI(MISSIONAI_DELIBERATE_KILL, NULL, NULL);
        pUnit->kill(true, NO_PLAYER, true);
}


void CvUnit::kill(bool bDelay, PlayerTypes ePlayer, bool bMessaged)
{
        //      If it's already dead (but delayed death in process) don't try to re-kill it
        if ( m_bDeathDelay )
        {
                return;
        }

        killUnconditional(bDelay, ePlayer, bMessaged);
}

void CvUnit::killUnconditional(bool bDelay, PlayerTypes ePlayer, bool bMessaged)
{
        PROFILE_FUNC();

        CLLNode<IDInfo>* pUnitNode;
        CvUnit* pTransportUnit;
        CvUnit* pLoopUnit;
        CvPlot* pPlot;
        CvWString szBuffer;
        PlayerTypes eOwner;
        PlayerTypes eCapturingPlayer;
        UnitTypes eCaptureUnitType;

        pPlot = plot();
        /*FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");*/

        if (m_combatResult.bDeathMessaged)
        {
                bMessaged = true;
        }
        // < M.A.D. Nukes Start >
        if(isMADEnabled())
        {
                setMADEnabled(false);
        }
        // < M.A.D. Nukes End   >

        if (pPlot != NULL)
        {
                std::vector<IDInfo> oldUnits;

                oldUnits.clear();
                pUnitNode = pPlot->headUnitNode();

                while (pUnitNode != NULL)
                {
                        oldUnits.push_back(pUnitNode->m_data);
                        pUnitNode = pPlot->nextUnitNode(pUnitNode);
                }

                for (uint i = 0; i < oldUnits.size(); i++)
                {
                        pLoopUnit = ::getUnit(oldUnits[i]);

                        if (pLoopUnit != NULL)
                        {
                                if (pLoopUnit->getTransportUnit() == this)
                                {
                                        //save old units because kill will clear the static list
                                        std::vector<IDInfo> tempUnits = oldUnits;

                                        if (pPlot->isValidDomainForLocation(*pLoopUnit))
                                        {
                                                pLoopUnit->setCapturingPlayer(NO_PLAYER);
                                        }
        /************************************************************************************************/
        /* Afforess                       Start          09/08/10                                               */
        /*                                                                                              */
        /*                                                                                              */
        /************************************************************************************************/
                                        bool bSurvived = false;
                                        CvPlot* pRescuePlot = NULL;
                                        if (GC.getDefineINT("WAR_PRIZES"))
                                        {
                                                if (pPlot->isWater())
                                                {
                                                        bool bAdjacentLand = false;
                                                        CvPlot* pAdjacentPlot;
                                                        int iI;

                                                        for (iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
                                                        {
                                                                pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));

                                                                if (pAdjacentPlot != NULL)
                                                                {
                                                                        if (!(pAdjacentPlot->isWater()))
                                                                        {
                                                                                if (!pAdjacentPlot->isVisibleEnemyUnit(pLoopUnit))
                                                                                {
                                                                                        if (!pAdjacentPlot->isImpassable(pLoopUnit->getTeam())) //45deg: units cannot be saved from drowning by climbing a mountain if you don't have the right tech or if playing without mountain option
                                                                                        {      
                                                                                                pRescuePlot = pAdjacentPlot;
                                                                                                bAdjacentLand = true;
                                                                                                break;
                                                                                        }      
                                                                                }
                                                                        }
                                                                }
                                                        }
                                                        if (bAdjacentLand)
                                                        {
                                                                if (GC.getGameINLINE().getSorenRandNum(10, "Unit Survives Drowning") <= 2 )
                                                                {
                                                                        bSurvived = true;
                                                                }
                                                        }
                                                }
                                        }
                                        if (bSurvived)
                                        {
                                                FAssertMsg(pRescuePlot != NULL, "pRescuePlot is expected to be a valid plot!");
                                                pLoopUnit->setDamage(GC.getGameINLINE().getSorenRandNum(pLoopUnit->currHitPoints(), "Survival Damage"), NO_PLAYER);
                                                pLoopUnit->move(pRescuePlot, false);

                                                MEMORY_TRACK_EXEMPT();

                                                szBuffer = gDLL->getText("TXT_KEY_MISC_UNIT_SURVIVED_TRANSPORT_SINKING", pLoopUnit->getNameKey(), getNameKey());
                                                AddDLLMessage(pLoopUnit->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, NULL, MESSAGE_TYPE_MINOR_EVENT);
                                        }
                                        else
                                        {
        /************************************************************************************************/
        /* Afforess                          END                                                            */
        /************************************************************************************************/
                                                MEMORY_TRACK_EXEMPT();

                                                szBuffer = gDLL->getText("TXT_KEY_MISC_UNIT_DROWNED", pLoopUnit->getNameKey());
                                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());
                                                bMessaged = true;
                                                pLoopUnit->kill(false, ePlayer, bMessaged);

                                                oldUnits = tempUnits;
                                        }
                                }
                        }
                }

                if (ePlayer != NO_PLAYER)
                {
                        CvEventReporter::getInstance().unitKilled(this, ePlayer);

                        if ( (NO_UNIT != getLeaderUnitType())
                        || (GC.getUnitClassInfo(getUnitClassType()).getMaxGlobalInstances() == 1) )
                        {
                                for (int iI = 0; iI < MAX_PLAYERS; iI++)
                                {
                                        if (GET_PLAYER((PlayerTypes)iI).isAlive() && !bMessaged)
                                        {
                                                MEMORY_TRACK_EXEMPT();

                                                szBuffer = gDLL->getText("TXT_KEY_MISC_GENERAL_KILLED", getNameKey());
                                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_MAJOR_EVENT, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());
                                                bMessaged = true;
                                        }
                                }
                        }
                }
                //This is interrupting other messages and not coming up when it should be anyhow.
                //if (!bMessaged)
                //{
                //      MEMORY_TRACK_EXEMPT();

                //      szBuffer = gDLL->getText("TXT_KEY_MISC_UNIT_DEATH", getNameKey());
                //      AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());
                //      m_combatResult.bDeathMessaged = false;
                //      bMessaged = true;
                //}

                if (bDelay)
                {
                        startDelayedDeath();
                        return;
                }

                if (isMadeAttack() && nukeRange() != -1)
                {
                        CvPlot* pTarget = getAttackPlot();
                        if (pTarget)
                        {
                                pTarget->nukeExplosion(nukeRange(), this);
                                setAttackPlot(NULL, false);
                        }
                }

        //Team Project (2)
        /*****************************************************************************************************/
        /**  Author: TheLadiesOgre                                                                          **/
        /**  Date: 21.09.2009                                                                               **/
        /**  ModComp: TLOTags                                                                               **/
        /**  Reason Added: New Bool Flags                                                                   **/
        /**  Notes:                                                                                         **/
        /*****************************************************************************************************/
                m_bDeathDelay = true;
                if (isCanRespawn())
                {
                        CvCity* pCapitalCity = GET_PLAYER(getOwnerINLINE()).getCapitalCity();
                        if ( pCapitalCity != NULL && pCapitalCity->plot() != plot())
                        {
                                setXY(pCapitalCity->getX_INLINE(), pCapitalCity->getY_INLINE(), false, false, false);
                                setDamage((9*GC.getMAX_HIT_POINTS())/10);
                                changeOneUpCount(-1);
                                CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_BATTLEFIELD_EVAC", getNameKey());
                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_POSITIVE_DINK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE());
                                m_bDeathDelay = false;
                                return;
                        }
                }

                if (isSurvivor())
                {
                        setDamage(GC.getMAX_HIT_POINTS() - std::max(1,(getSurvivorChance() / 1000)));
                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_IS_HARDCORE", getNameKey());
                        AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_POSITIVE_DINK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE());
                        m_bDeathDelay = false;
                        //      Only applies to THIS combat - it might be attacked again the same turn
                        setSurvivor(false);
                        return;
                }
        /*****************************************************************************************************/
        /**  TheLadiesOgre; 21.09.2009; TLOTags                                                             **/
        /*****************************************************************************************************/

                finishMoves();

                if (IsSelected())
                {
                        if (gDLL->getInterfaceIFace()->getLengthSelectionList() == 1)
                        {
                                if (!(gDLL->getInterfaceIFace()->isFocused()) && !(gDLL->getInterfaceIFace()->isCitySelection()) && !(gDLL->getInterfaceIFace()->isDiploOrPopupWaiting()))
                                {
                                        GC.getGameINLINE().updateSelectionList();
                                }

                                if (IsSelected())
                                {
                                        gDLL->getInterfaceIFace()->setCycleSelectionCounter(1);
                                }
                                else
                                {
                                        gDLL->getInterfaceIFace()->setDirty(SelectionCamera_DIRTY_BIT, true);
                                }
                        }
                }

                gDLL->getInterfaceIFace()->removeFromSelectionList(this);

                // XXX this is NOT a hack, without it, the game crashes.
                if ( !isUsingDummyEntities() && isInViewport() )
                {
                        gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
                }

                FAssertMsg(!isCombat(), "isCombat did not return false as expected");

                pTransportUnit = getTransportUnit();

                if (pTransportUnit != NULL)
                {
                        setTransportUnit(NULL);
                }

                setReconPlot(NULL);
                setBlockading(false);

                FAssertMsg(getAttackPlot() == NULL, "The current unit instance's attack plot is expected to be NULL");
                FAssertMsg(getCombatUnit() == NULL, "The current unit instance's combat unit is expected to be NULL");
        }
        GET_TEAM(getTeam()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);
        GET_PLAYER(getOwnerINLINE()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);

        GET_PLAYER(getOwnerINLINE()).changeExtraUnitCost(-(m_pUnitInfo->getExtraCost()));

        if (m_pUnitInfo->getNukeRange() != -1)
        {
                GET_PLAYER(getOwnerINLINE()).changeNumNukeUnits(-1);
        }

        if (m_pUnitInfo->isMilitarySupport())
        {
                GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(-1);
        }

        GET_PLAYER(getOwnerINLINE()).changeAssets(-(m_pUnitInfo->getAssetValue()));

        GET_PLAYER(getOwnerINLINE()).changeUnitPower(-(m_pUnitInfo->getPowerValue()));
/************************************************************************************************/
/* Afforess                       Start          04/16/10                                               */
/*                                                                                              */
/*  Promotions affect iAsset and iPower values, so they must be removed on unit death           */
/************************************************************************************************/
        for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
        {
                setHasPromotion(((PromotionTypes)iI), false);
        }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        if (pPlot != NULL)
        {
                OutputDebugString(CvString::format("Unit %S of player %S killed\n", getName().GetCString(),GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0)).c_str());

                GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), -1);
                AI_killed();    //      Update AI counts for this unit
                setXY(INVALID_PLOT_COORD, INVALID_PLOT_COORD, true);

                joinGroup(NULL, false, false);

                CvEventReporter::getInstance().unitLost(this);

                eOwner = getOwnerINLINE();
                eCapturingPlayer = getCapturingPlayer();
                eCaptureUnitType = ((eCapturingPlayer != NO_PLAYER) ? getCaptureUnitType(GET_PLAYER(eCapturingPlayer).getCivilizationType()) : NO_UNIT);
        // BUG - Unit Captured Event - start
                PlayerTypes eFromPlayer = getOwner();
                UnitTypes eCapturedUnitType = getUnitType();
        // BUG - Unit Captured Event - end

                if ((eCapturingPlayer != NO_PLAYER) && (eCaptureUnitType != NO_UNIT) && !(GET_PLAYER(eCapturingPlayer).isBarbarian()))
                {
                        if (GET_PLAYER(eCapturingPlayer).isHuman() || GET_PLAYER(eCapturingPlayer).AI_captureUnit(eCaptureUnitType, pPlot) || 0 == GC.getDefineINT("AI_CAN_DISBAND_UNITS"))
                        {
                                CvUnit* pkCapturedUnit = GET_PLAYER(eCapturingPlayer).initUnit(eCaptureUnitType, pPlot->getX_INLINE(), pPlot->getY_INLINE(), NO_UNITAI, NO_DIRECTION, GC.getGameINLINE().getSorenRandNum(10000, "AI Unit Birthmark"));

                                if (pkCapturedUnit != NULL)
                                {
        // BUG - Unit Captured Event - start
                                        CvEventReporter::getInstance().unitCaptured(eFromPlayer, eCapturedUnitType, pkCapturedUnit);
        // BUG - Unit Captured Event - end
                                        {
                                                MEMORY_TRACK_EXEMPT();

                                                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_CAPTURED_UNIT", GC.getUnitInfo(eCaptureUnitType).getTextKeyWide());
                                                AddDLLMessage(eCapturingPlayer, true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_UNITCAPTURE", MESSAGE_TYPE_INFO, pkCapturedUnit->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                                        }

                                        // Add a captured mission
                                        if ( !pkCapturedUnit->isUsingDummyEntities() )
                                        {
                                                CvMissionDefinition kMission;
                                                kMission.setMissionTime(GC.getMissionInfo(MISSION_CAPTURED).getTime() * gDLL->getSecsPerTurn());
                                                kMission.setUnit(BATTLE_UNIT_ATTACKER, pkCapturedUnit);
                                                kMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
                                                kMission.setPlot(pPlot);
                                                kMission.setMissionType(MISSION_CAPTURED);
                                                addMission(&kMission);
                                        }

                                        pkCapturedUnit->finishMoves();

                                        if (!GET_PLAYER(eCapturingPlayer).isHuman())
                                        {
                                                CvPlot* pPlot = pkCapturedUnit->plot();
                                                if (pPlot && !pPlot->isCity(false))
                                                {
                                                        if (GET_PLAYER(eCapturingPlayer).AI_getPlotDanger(pPlot) && GC.getDefineINT("AI_CAN_DISBAND_UNITS"))
                                                        {
                                                                pkCapturedUnit->kill(false, NO_PLAYER, true);
                                                        }
                                                }
                                        }
                                }
                        }
                }

                GET_PLAYER(getOwnerINLINE()).deleteUnit(getID());

        }
}


void CvUnit::NotifyEntity(MissionTypes eMission)
{
        if ( !isUsingDummyEntities() && isInViewport() )
        {
                gDLL->getEntityIFace()->NotifyEntity(getUnitEntity(), eMission);
        }
}


void CvUnit::doTurn()
{
        PROFILE("CvUnit::doTurn()")

        FAssertMsg(!isDead(), "isDead did not return false as expected");
        FAssertMsg(getGroup() != NULL, "getGroup() is not expected to be equal with NULL");

        testPromotionReady();
/************************************************************************************************/
/* Afforess                       Start          07/12/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        m_iControlPointsLeft = controlPoints(); //restore control points for commander
        gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
        m_iCommanderID = -1;    //reset used commander for combat units
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
        if (isBlockading())
        {
                collectBlockadeGold();
        }

        if (isSpy() && isIntruding() && !isCargo())
        {
                TeamTypes eTeam = plot()->getTeam();
                if (NO_TEAM != eTeam)
                {
                        if (GET_TEAM(getTeam()).isOpenBorders(eTeam))
                        {
                                testSpyIntercepted(plot()->getOwnerINLINE(), GC.getDefineINT("ESPIONAGE_SPY_NO_INTRUDE_INTERCEPT_MOD"));
                        }
                        else
                        {
                                testSpyIntercepted(plot()->getOwnerINLINE(), GC.getDefineINT("ESPIONAGE_SPY_INTERCEPT_MOD"));
                        }
                }
        }

        if (baseCombatStr() > 0)
        {
#ifdef MULTI_FEATURE_MOD
                for (int i=0; i<plot()->getNumFeatures(); i++)
                {
                        FeatureTypes eFeature = plot()->getFeatureByIndex(i);
                        if (0 != GC.getFeatureInfo(eFeature).getTurnDamage())
                        {
                                changeDamage(GC.getFeatureInfo(eFeature).getTurnDamage(), NO_PLAYER);
                        }
                }
#else
                FeatureTypes eFeature = plot()->getFeatureType();
                if (NO_FEATURE != eFeature)
                {
                        if (0 != GC.getFeatureInfo(eFeature).getTurnDamage())
                        {
                                changeDamage(GC.getFeatureInfo(eFeature).getTurnDamage(), NO_PLAYER);
                        }
                }
#endif
/************************************************************************************************/
/* Afforess                       Start          05/17/10                                                */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                if (plot()->getTerrainTurnDamage(this) != 0)
                {
                        changeDamage(plot()->getTerrainTurnDamage(this), NO_PLAYER);
                }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
        }

        if (hasMoved() && !m_bForcedMove)
        {
                if (isAlwaysHeal())
                {
                        doHeal();
                }
        }
        else
        {
                if (isHurt())
                {
                        doHeal();
                }

                if (!isCargo())
                {
                        changeFortifyTurns(1);
                }
        }

//Team Project (2)
/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 29.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: New Bool Flags                                                                   **/
/**  Notes:                                                                                         **/
/*****************************************************************************************************/
        if (isCanRespawn())
        {
                setCanRespawn(false);
        }

        if (isSurvivor())
        {
                setSurvivor(false);
        }

/*****************************************************************************************************/
/**  TheLadiesOgre; 29.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/
/************************************************************************************************/
/* Afforess                       Start          07/12/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        if (isSpy() && m_iSleepTimer > 0)
        {
                if (getFortifyTurns() == GC.getDefineINT("MAX_FORTIFY_TURNS"))
                {
                        getGroup()->setActivityType(ACTIVITY_AWAKE);
                        m_iSleepTimer = 0;
                }
        }

        if (getDesiredDiscoveryTech() != NO_TECH && canDiscover(NULL))
        {
                if (getDesiredDiscoveryTech() == getDiscoveryTech())
                {
                        getGroup()->setActivityType(ACTIVITY_AWAKE);
                        setDesiredDiscoveryTech(NO_TECH);
                        discover();
                }
        }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
        changeImmobileTimer(-1);

        setMadeAttack(false);
        setMadeInterception(false);

        setReconPlot(NULL);

        m_bForcedMove = false;
        setMoves(0);

        //Afforess earned XP start
        if (canAcquirePromotionAny() && GET_PLAYER(getOwnerINLINE()).getFractionalXPEarnedInCity() > 0)
        {
                CvCity* pCity = plot()->getPlotCity();
                if (pCity != NULL && pCity->getOwnerINLINE() == getOwnerINLINE())
                {
                        float fXP = (float)GET_PLAYER(getOwnerINLINE()).getFractionalXPEarnedInCity();
                        //Normal game speed train percent != 100, try to use it instead of 100 to scale by as the base modifier
                        int iNormal = GC.getInfoTypeForString("GAMESPEED_NORMAL");
                        fXP *= (iNormal == -1 ? 100 : GC.getGameSpeedInfo((GameSpeedTypes)iNormal).getTrainPercent());
                        fXP /= GC.getGameSpeedInfo((GameSpeedTypes)GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
                        setExperience100(getExperience100() + std::max(1, (int)fXP));
                }
        }
        //Afforess earned xp end

        // < M.A.D. Nukes Start >>
    if (getUnitInfo().getUnitAIType(UNITAI_ICBM) && GET_PLAYER(getOwnerINLINE()).isEnabledMAD())
    {
                bool bRetarget = false;
                if ((GC.getGameINLINE().getSorenRandNum(100 , "Retarget Nuke")) < 10) // 45deg: 10% chances to retarget a single nuke
                {
                        bRetarget = true;
                }
                doMADNukes(bRetarget);
        }
    if(isMADEnabled())
        {
                finishMoves();
    }
        // < M.A.D. Nukes End  >>
}


void CvUnit::updateAirStrike(CvPlot* pPlot, bool bQuick, bool bFinish)
{
        bool bVisible = false;

        if (!bFinish)
        {
                if (isFighting())
                {
                        return;
                }

                if (!bQuick)
                {
                        bVisible = isCombatVisible(NULL);
                }

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
                // Dale - NB: A-Bomb START
                if(canNuke(pPlot)){
                        kill(true, NO_PLAYER, true);
                        return;
                }
                // Dale - NB: A-Bomb END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/

                if (!airStrike(pPlot))
                {
                        return;
                }

                if (bVisible)
                {
                        CvAirMissionDefinition kAirMission;
                        kAirMission.setMissionType(MISSION_AIRSTRIKE);
                        kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
                        kAirMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
                        kAirMission.setDamage(BATTLE_UNIT_DEFENDER, 0);
                        kAirMission.setDamage(BATTLE_UNIT_ATTACKER, 0);
                        kAirMission.setPlot(pPlot);
                        setCombatTimer(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime());
                        GC.getGameINLINE().incrementTurnTimer(getCombatTimer());
                        kAirMission.setMissionTime(getCombatTimer() * gDLL->getSecsPerTurn());

                        if (pPlot->isActiveVisible(false))
                        {
                                addMission(&kAirMission);
                        }

                        return;
                }
        }

        CvUnit *pDefender = getCombatUnit();
        if (pDefender != NULL)
        {
                pDefender->setCombatUnit(NULL);
        }
        setCombatUnit(NULL);
        setAttackPlot(NULL, false);

        getGroup()->clearMissionQueue();

        if (isSuicide() && !isDead())
        {
                kill(true);
        }
}

void CvUnit::resolveAirCombat(CvUnit* pInterceptor, CvPlot* pPlot, CvAirMissionDefinition& kBattle)
{
        CvWString szBuffer;

        int iTheirStrength = (DOMAIN_AIR == pInterceptor->getDomainType() ? pInterceptor->airCurrCombatStr(this) : pInterceptor->currCombatStr(NULL, NULL));
        int iOurStrength = (DOMAIN_AIR == getDomainType() ? airCurrCombatStr(pInterceptor) : currCombatStr(NULL, NULL));
        int iTotalStrength = iOurStrength + iTheirStrength;
        if (0 == iTotalStrength)
        {
                FAssert(false);
                return;
        }

/********************************************************************************/
/*      BETTER_BTS_AI_MOD                                               10/19/08        Roland J & jdog5000     */
/*                                                                                                                                                      */
/*      Combat mechanics                                                                                                                */
/********************************************************************************/
        /*
        int iOurOdds = (100 * iOurStrength) / std::max(1, iTotalStrength);

        int iOurRoundDamage = (pInterceptor->currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
        int iTheirRoundDamage = (currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
        if (getDomainType() == DOMAIN_AIR)
        {
                iTheirRoundDamage = std::max(GC.getDefineINT("MIN_INTERCEPTION_DAMAGE"), iTheirRoundDamage);
        }

        //original BTS code
        int iTheirDamage = 0;
        int iOurDamage = 0;

        for (int iRound = 0; iRound < GC.getDefineINT("INTERCEPTION_MAX_ROUNDS"); ++iRound)
        */

        // For air v air, more rounds and factor in strength for per round damage
        int iOurOdds = (100 * iOurStrength) / std::max(1, iTotalStrength);
        int iMaxRounds = 0;
        int iOurRoundDamage = 0;
        int iTheirRoundDamage = 0;

        // Air v air is more like standard combat
        // Round damage in this case will now depend on strength and interception probability
        if( GC.getBBAI_AIR_COMBAT() && (DOMAIN_AIR == pInterceptor->getDomainType() && DOMAIN_AIR == getDomainType()) )
        {
                int iBaseDamage = GC.getDefineINT("AIR_COMBAT_DAMAGE");
                int iOurFirepower = ((airMaxCombatStr(pInterceptor) + iOurStrength + 1) / 2);
                int iTheirFirepower = ((pInterceptor->airMaxCombatStr(this) + iTheirStrength + 1) / 2);

                int iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);

                int iTheirInterception = std::max(pInterceptor->maxInterceptionProbability(),2*GC.getDefineINT("MIN_INTERCEPTION_DAMAGE"));
                int iOurInterception = std::max(maxInterceptionProbability(),2*GC.getDefineINT("MIN_INTERCEPTION_DAMAGE"));

                iOurRoundDamage = std::max(1, ((iBaseDamage * (iTheirFirepower + iStrengthFactor) * iTheirInterception) / ((iOurFirepower + iStrengthFactor) * 100)));
                iTheirRoundDamage = std::max(1, ((iBaseDamage * (iOurFirepower + iStrengthFactor) * iOurInterception) / ((iTheirFirepower + iStrengthFactor) * 100)));

                iMaxRounds = 2*GC.getDefineINT("INTERCEPTION_MAX_ROUNDS") - 1;
        }
        else
        {
                iOurRoundDamage = (pInterceptor->currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
                iTheirRoundDamage = (currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
                if (getDomainType() == DOMAIN_AIR)
                {
                        iTheirRoundDamage = std::max(GC.getDefineINT("MIN_INTERCEPTION_DAMAGE"), iTheirRoundDamage);
                }

                iMaxRounds = GC.getDefineINT("INTERCEPTION_MAX_ROUNDS");
        }

        int iTheirDamage = 0;
        int iOurDamage = 0;

        for (int iRound = 0; iRound < iMaxRounds; ++iRound)
/********************************************************************************/
/*      BETTER_BTS_AI_MOD                                               END                                                             */
/********************************************************************************/
        {
                if (GC.getGameINLINE().getSorenRandNum(100, "Air combat") < iOurOdds)
                {
                        if (DOMAIN_AIR == pInterceptor->getDomainType())
                        {
                                iTheirDamage += iTheirRoundDamage;
                                pInterceptor->changeDamage(iTheirRoundDamage, getOwnerINLINE());
                                if (pInterceptor->isDead())
                                {
                                        break;
                                }
                        }
                }
                else
                {
                        iOurDamage += iOurRoundDamage;
                        changeDamage(iOurRoundDamage, pInterceptor->getOwnerINLINE());
                        if (isDead())
                        {
                                break;
                        }
                }
        }

        if (isDead())
        {
                if (iTheirRoundDamage > 0)
                {
                        int iExperience = attackXPValue();
                        iExperience = (iExperience * iOurStrength) / std::max(1, iTheirStrength);
                        iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
                        pInterceptor->changeExperience(iExperience, maxXPValue(), true, pPlot->getOwnerINLINE() == pInterceptor->getOwnerINLINE(), !isBarbarian());
                }
        }
        else if (pInterceptor->isDead())
        {
                int iExperience = pInterceptor->defenseXPValue();
                iExperience = (iExperience * iTheirStrength) / std::max(1, iOurStrength);
                iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
                changeExperience(iExperience, pInterceptor->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pInterceptor->isBarbarian());
        }
        else if (iOurDamage > 0)
        {
                if (iTheirRoundDamage > 0)
                {
                        pInterceptor->changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), maxXPValue(), true, pPlot->getOwnerINLINE() == pInterceptor->getOwnerINLINE(), !isBarbarian());
                }
        }
        else if (iTheirDamage > 0)
        {
                changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pInterceptor->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pInterceptor->isBarbarian());
        }

        kBattle.setDamage(BATTLE_UNIT_ATTACKER, iOurDamage);
        kBattle.setDamage(BATTLE_UNIT_DEFENDER, iTheirDamage);
}


void CvUnit::updateAirCombat(bool bQuick)
{
        CvUnit* pInterceptor = NULL;
        bool bFinish = false;

        FAssert(getDomainType() == DOMAIN_AIR || getDropRange() > 0);

        if (getCombatTimer() > 0)
        {
                changeCombatTimer(-1);

                if (getCombatTimer() > 0)
                {
                        return;
                }
                else
                {
                        bFinish = true;
                }
        }

        CvPlot* pPlot = getAttackPlot();
        if (pPlot == NULL)
        {
                return;
        }

        if (bFinish)
        {
                pInterceptor = getCombatUnit();
        }
        else
        {
                pInterceptor = bestInterceptor(pPlot);
        }


        if (pInterceptor == NULL)
        {
                setAttackPlot(NULL, false);
                setCombatUnit(NULL);

                getGroup()->clearMissionQueue();

                return;
        }

        //check if quick combat
        bool bVisible = false;
        if (!bQuick)
        {
                bVisible = isCombatVisible(pInterceptor);
        }

        //if not finished and not fighting yet, set up combat damage and mission
        if (!bFinish)
        {
                if (!isFighting())
                {
                        if (plot()->isFighting() || pPlot->isFighting())
                        {
                                return;
                        }

                        setMadeAttack(true);

                        setCombatUnit(pInterceptor, true);
                        pInterceptor->setCombatUnit(this, false);
                }

                FAssertMsg(pInterceptor != NULL, "Defender is not assigned a valid value");

                FAssertMsg(plot()->isFighting(), "Current unit instance plot is not fighting as expected");
                FAssertMsg(pInterceptor->plot()->isFighting(), "pPlot is not fighting as expected");

                CvAirMissionDefinition kAirMission;
                if (DOMAIN_AIR != getDomainType())
                {
                        kAirMission.setMissionType(MISSION_PARADROP);
                }
                else
                {
                        kAirMission.setMissionType(MISSION_AIRSTRIKE);
                }
                kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
                kAirMission.setUnit(BATTLE_UNIT_DEFENDER, pInterceptor);

                resolveAirCombat(pInterceptor, pPlot, kAirMission);

                if (!bVisible)
                {
                        bFinish = true;
                }
                else
                {
                        kAirMission.setPlot(pPlot);
                        kAirMission.setMissionTime(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime() * gDLL->getSecsPerTurn());
                        setCombatTimer(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime());
                        GC.getGameINLINE().incrementTurnTimer(getCombatTimer());

                        if (pPlot->isActiveVisible(false))
                        {
                                addMission(&kAirMission);
                        }
                }

                changeMoves(GC.getMOVE_DENOMINATOR());
                if (DOMAIN_AIR != pInterceptor->getDomainType())
                {
                        pInterceptor->setMadeInterception(true);
                }

                if (isDead())
                {
                        MEMORY_TRACK_EXEMPT();

                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SHOT_DOWN_ENEMY", pInterceptor->getNameKey(), getNameKey(), getVisualCivAdjective(pInterceptor->getTeam()));
                        AddDLLMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_SHOT_DOWN", getNameKey(), pInterceptor->getNameKey());
                        AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                }
                else if (kAirMission.getDamage(BATTLE_UNIT_ATTACKER) > 0)
                {
                        MEMORY_TRACK_EXEMPT();

                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_HURT_ENEMY_AIR", pInterceptor->getNameKey(), getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_ATTACKER)), getVisualCivAdjective(pInterceptor->getTeam()));
                        AddDLLMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_AIR_UNIT_HURT", getNameKey(), pInterceptor->getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_ATTACKER)));
                        AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                }

                if (pInterceptor->isDead())
                {
                        MEMORY_TRACK_EXEMPT();

                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SHOT_DOWN_ENEMY", getNameKey(), pInterceptor->getNameKey(), pInterceptor->getVisualCivAdjective(getTeam()));
                        AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_SHOT_DOWN", pInterceptor->getNameKey(), getNameKey());
                        AddDLLMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                }
                else if (kAirMission.getDamage(BATTLE_UNIT_DEFENDER) > 0)
                {
                        MEMORY_TRACK_EXEMPT();

                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_DAMAGED_ENEMY_AIR", getNameKey(), pInterceptor->getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_DEFENDER)), pInterceptor->getVisualCivAdjective(getTeam()));
                        AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_AIR_UNIT_DAMAGED", pInterceptor->getNameKey(), getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_DEFENDER)));
                        AddDLLMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                }

                if (0 == kAirMission.getDamage(BATTLE_UNIT_ATTACKER) + kAirMission.getDamage(BATTLE_UNIT_DEFENDER))
                {
                        MEMORY_TRACK_EXEMPT();

                        CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ABORTED_ENEMY_AIR", pInterceptor->getNameKey(), getNameKey(), getVisualCivAdjective(getTeam()));
                        AddDLLMessage(pInterceptor->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_AIR_UNIT_ABORTED", getNameKey(), pInterceptor->getNameKey());
                        AddDLLMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                }
        }

        if (bFinish)
        {
                setAttackPlot(NULL, false);
                setCombatUnit(NULL);
                pInterceptor->setCombatUnit(NULL);

                if (!isDead() && isSuicide())
                {
                        kill(true);
                }
        }
}

void CvUnit::resolveCombat(CvUnit* pDefender, CvPlot* pPlot, CvBattleDefinition& kBattle)
{
        PROFILE_FUNC();
        MEMORY_TRACK();

        CombatDetails cdAttackerDetails;
        CombatDetails cdDefenderDetails;

        AI_setPredictedHitPoints(-1);
        pDefender->AI_setPredictedHitPoints(-1);
        int iAttackerStrength = currCombatStr(NULL, NULL, &cdAttackerDetails);
        int iAttackerFirepower = currFirepower(NULL, NULL);
        int iDefenderStrength = 0;
        int iAttackerDamage = 0;
        int iDefenderDamage = 0;
        int iDefenderOdds = 0;
/************************************************************************************************/
/* Afforess                       Start          03/15/10                      Coded By: KillMePlease   */
/*                                                                                              */
/* Occasional Promotions                                                                        */
/************************************************************************************************/
        bool bAttackerWithdrawn = false;
        bool bAttackerHasLostNoHP = true;
        int iAttackerInitialDamage = getDamage();
        int iDefenderInitialDamage = pDefender->getDamage();
        int iInitialDefXP = pDefender->getExperience100();
        int iInitialAttXP = getExperience100();
        int iInitialAttGGXP = GET_PLAYER(getOwnerINLINE()).getCombatExperience();
        int iInitialDefGGXP = GET_PLAYER(pDefender->getOwnerINLINE()).getCombatExperience();
        bool bDynamicXP = GC.getGameINLINE().isModderGameOption(MODDERGAMEOPTION_IMPROVED_XP);
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        getDefenderCombatValues(*pDefender, pPlot, iAttackerStrength, iAttackerFirepower, iDefenderOdds, iDefenderStrength, iAttackerDamage, iDefenderDamage, &cdDefenderDetails, pDefender);
        int iAttackerKillOdds = iDefenderOdds * (100 - withdrawalProbability()) / 100;

        if (isHuman() || pDefender->isHuman())
        {
                //Added ST
                CyArgsList pyArgsCD;
                pyArgsCD.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
                pyArgsCD.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
                pyArgsCD.add(getCombatOdds(this, pDefender));
                CvEventReporter::getInstance().genericEvent("combatLogCalc", pyArgsCD.makeFunctionArgs());
        }

        collateralCombat(pPlot, pDefender);
/************************************************************************************************/
/* Afforess                       Start          02/22/10                Coded by: KillMePlease         */
/*                                                                                              */
/*   Defender Withdraw                                                                          */
/************************************************************************************************/
        int iCloseCombatRoundNum = -1;
        bool bTryMobileWithdraw = false;        //if unit will be trying to withdraw from a plot it occupies
        if (pPlot->getNumDefenders(pDefender->getOwner()) == 1 && pDefender->baseMoves() > baseMoves()) //must be faster than attacker
        {
                bTryMobileWithdraw = true;
        }
        int iWinningOdds = getCombatOdds(this, pDefender);
        bool bDefenderSkirmish = false; //iWinningOdds > 60;
        m_combatResult.bDefenderWithdrawn = false;
        m_combatResult.pPlot = NULL;
        m_combatResult.iAttacksCount++;
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        while (true)
        {
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/21/10                                jdog5000      */
/*                                                                                              */
/* Lead From Behind                                                                             */
/************************************************************************************************/
                // From Lead From Behind by UncutDragon
/* original code
                if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Combat") < iDefenderOdds)
*/
              // modified
                if (GC.getGameINLINE().getSorenRandNum(GC.getCOMBAT_DIE_SIDES(), "Combat") < iDefenderOdds)
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

                {
                        if (getCombatFirstStrikes() == 0)
                        {
                                if (getDamage() + iAttackerDamage >= maxHitPoints() && GC.getGameINLINE().getSorenRandNum(100, "Withdrawal") < withdrawalProbability())
                                {
                                        flankingStrikeCombat(pPlot, iAttackerStrength, iAttackerFirepower, iAttackerKillOdds, iDefenderDamage, pDefender);
/************************************************************************************************/
/* Afforess                       Start          03/15/10                      Coded By: KillMePlease   */
/*                                                                                              */
/* Occasional Promotions                                                                        */
/************************************************************************************************/
                                        bAttackerWithdrawn = true;

/**     Great Generals From Barbarian Combat Start                                                                                                      **/

                                if (!bDynamicXP)
                                        changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), (!pDefender->isBarbarian() || GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_GENERALS)));

/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
// BUG - Combat Events - start
                                        CvEventReporter::getInstance().combatRetreat(this, pDefender);
// BUG - Combat Events - end
                                        break;
                                }

                                changeDamage(iAttackerDamage, pDefender->getOwnerINLINE());
/************************************************************************************************/
/* Afforess                       Start          03/15/10                      Coded By: KillMePlease   */
/*                                                                                              */
/* Occasional Promotions                                                                        */
/************************************************************************************************/
                                bAttackerHasLostNoHP = false;
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                                if (pDefender->getCombatFirstStrikes() > 0 && pDefender->isRanged())
                                {
                                        kBattle.addFirstStrikes(BATTLE_UNIT_DEFENDER, 1);
                                        kBattle.addDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, iAttackerDamage);
                                }

                                cdAttackerDetails.iCurrHitPoints = currHitPoints();

                                if (isHuman() || pDefender->isHuman())
                                {
                                        CyArgsList pyArgs;
                                        pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
                                        pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
                                        pyArgs.add(1);
                                        pyArgs.add(iAttackerDamage);
                                        CvEventReporter::getInstance().genericEvent("combatLogHit", pyArgs.makeFunctionArgs());
                                }
                        }
                }
                else
                {
                        if (pDefender->getCombatFirstStrikes() == 0)
                        {
/************************************************************************************************/
/* Afforess                       Start          02/22/10                        Coded by: KillMePlease */
/*                                                                                              */
/*   Defender Withdraw                                                                          */
/************************************************************************************************/
                                if (GC.getGameINLINE().isModderGameOption(MODDERGAMEOPTION_DEFENDER_WITHDRAW))
                                {
                                        iCloseCombatRoundNum++;
                                }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                                if (std::min(GC.getMAX_HIT_POINTS(), pDefender->getDamage() + iDefenderDamage) > combatLimit())
                                {
                                        if (!bDynamicXP)
                                                changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pDefender->isBarbarian());
                                        pDefender->setDamage(combatLimit(), getOwnerINLINE());
// BUG - Combat Events - start
                                        CvEventReporter::getInstance().combatWithdrawal(this, pDefender);
// BUG - Combat Events - end
                                        break;
                                }

/************************************************************************************************/
/* Afforess                       Start          02/22/10                Coded by: KillMePlease         */
/*                                                                                              */
/* Defender Withdraw                                                                            */
/************************************************************************************************/
                                else if (GC.getGameINLINE().isModderGameOption(MODDERGAMEOPTION_DEFENDER_WITHDRAW) && (
                                (pDefender->getDamage() + iDefenderDamage >= maxHitPoints() || bDefenderSkirmish) &&
                                GC.getGameINLINE().getSorenRandNum(100, "Withdrawal") < pDefender->withdrawalProbability()
                                && !isSuicide() && iCloseCombatRoundNum > 0) )  //can not to escape at close combat round 1
                                {
                                        //attacker got experience
                                        int iExperience = pDefender->attackXPValue();
                                        iExperience = ((iExperience * iDefenderStrength) / iAttackerStrength);
                                        iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
                                        changeExperience(iExperience, pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), (!pDefender->isBarbarian() || GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_GENERALS)));

                                        //if (pPlot->getNumDefenders(pDefender->getOwner()) == 1 && pDefender->baseMoves() > baseMoves())       //must be faster to flee a battle
                                        {
                                                bool bEnemy = true;
                                                for (int iPlot = 0; iPlot < NUM_DIRECTION_TYPES; iPlot++)
                                                {
                                                        CvPlot* pAdjacentPlot = plotDirection(pDefender->plot()->getX_INLINE(), pDefender->plot()->getY_INLINE(), ((DirectionTypes)iPlot));
                                                        if (pAdjacentPlot != NULL)
                                                        {
                                                                if (pDefender->canMoveInto(pAdjacentPlot))
                                                                {
                                                                        //Check that this tile is safe (ie, no attackers next to it)
                                                                        for (int iPlot2 = 0; iPlot2 < NUM_DIRECTION_TYPES; iPlot2++)
                                                                        {
                                                                                CvPlot* pAdjacentPlot2 = plotDirection(pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), ((DirectionTypes)iPlot2));
                                                                                if (pAdjacentPlot2 != NULL)
                                                                                {
                                                                                        CLLNode<IDInfo>* pUnitNode;
                                                                                        pUnitNode = pAdjacentPlot2->headUnitNode();
                                                                                        CvUnit* pLoopUnit;
                                                                                        bEnemy = false;
                                                                                        while (pUnitNode != NULL)
                                                                                        {
                                                                                                pLoopUnit = ::getUnit(pUnitNode->m_data);
                                                                                                pUnitNode = pAdjacentPlot2->nextUnitNode(pUnitNode);
                                                                                                if (GET_TEAM(pLoopUnit->getTeam()).isAtWar(pDefender->getTeam()))
                                                                                                {
                                                                                                        bEnemy = true;
                                                                                                        break;
                                                                                                }
                                                                                        }
                                                                                        if (bEnemy)
                                                                                        {
                                                                                                break;
                                                                                        }
                                                                                }
                                                                        }
                                                                        if (!bEnemy)
                                                                        {
                                                                                m_combatResult.pPlot = pAdjacentPlot;
                                                                                m_combatResult.bDefenderWithdrawn = true;

                                                                                if (!bDynamicXP)
                                                                                        pDefender->changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue(),
                                                                true, pPlot->getOwnerINLINE() == pDefender->getOwnerINLINE(), (!isBarbarian() || GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_GENERALS)));

                                                                                doDynamicXP(pDefender, pPlot, iAttackerInitialDamage, iWinningOdds, iDefenderInitialDamage, iInitialAttXP, iInitialDefXP, iInitialAttGGXP, iInitialDefGGXP, false, false);
                                                                                return;
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                                }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

                                pDefender->changeDamage(iDefenderDamage, getOwnerINLINE());

                                if (getCombatFirstStrikes() > 0 && isRanged())
                                {
                                        kBattle.addFirstStrikes(BATTLE_UNIT_ATTACKER, 1);
                                        kBattle.addDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, iDefenderDamage);
                                }

                                cdDefenderDetails.iCurrHitPoints=pDefender->currHitPoints();

                                if (isHuman() || pDefender->isHuman())
                                {
                                        CyArgsList pyArgs;
                                        pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
                                        pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
                                        pyArgs.add(0);
                                        pyArgs.add(iDefenderDamage);
                                        CvEventReporter::getInstance().genericEvent("combatLogHit", pyArgs.makeFunctionArgs());
                                }
                        }
                }

                if (getCombatFirstStrikes() > 0)
                {
                        changeCombatFirstStrikes(-1);
                }

                if (pDefender->getCombatFirstStrikes() > 0)
                {
                        pDefender->changeCombatFirstStrikes(-1);
                }

                if (isDead() || pDefender->isDead())
                {
                        if (isDead())
                        {
                                int iExperience = defenseXPValue();
                                iExperience = ((iExperience * iAttackerStrength) / iDefenderStrength);
                                iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
/*************************************************************************************************/
/**     Great Generals From Barbarian Combat Start                                                                                                      **/
/**                     Oct 19 2009                                                                                                                                                     **/
/**                                                                                                                                                                                             **/
/*************************************************************************************************/
                                if (!bDynamicXP)
                                        pDefender->changeExperience(iExperience, maxXPValue(), true, pPlot->getOwnerINLINE() == pDefender->getOwnerINLINE(), (!isBarbarian() || GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_GENERALS)));
/*************************************************************************************************/
/**     Great Generals From Barbarian Combat End                                                                                                        **/
/*************************************************************************************************/

                                //      Koshling - add rolling history of combat results to allow the AI to adapt
                                //      to what it sees happening
                                pPlot->area()->recordCombatDeath(getOwnerINLINE(), getUnitType(), pDefender->getUnitType());
                        }
                        else
                        {
                                flankingStrikeCombat(pPlot, iAttackerStrength, iAttackerFirepower, iAttackerKillOdds, iDefenderDamage, pDefender);

                                int iExperience = pDefender->attackXPValue();
                                iExperience = ((iExperience * iDefenderStrength) / iAttackerStrength);
                                iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
/*************************************************************************************************/
/**     Great Generals From Barbarian Combat Start                                                                                                      **/
/**                     Oct 19 2009                                                                                                                                                     **/
/**                                                                                                                                                                                             **/
/*************************************************************************************************/
                                if (!bDynamicXP)
                                {
                                        changeExperience(iExperience, pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), (!pDefender->isBarbarian() || GC.getGameINLINE().isOption(GAMEOPTION_BARBARIAN_GENERALS)));
                                }
/*************************************************************************************************/
/**     Great Generals From Barbarian Combat End                                                                                                        **/
/*************************************************************************************************/

                                //      Koshling - add rolling history of combat results to allow the AI to adapt
                                //      to what it sees happening
                                pPlot->area()->recordCombatDeath(pDefender->getOwnerINLINE(), pDefender->getUnitType(), getUnitType());
                        }
                        break;
                }
        }

/************************************************************************************************/
/* Afforess                       Start          05/6/10                                                */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        bool bPromotion = false;
        bool bDefPromotion = false;
        doBattleFieldPromotions(pDefender, cdDefenderDetails, pPlot, bAttackerHasLostNoHP, bAttackerWithdrawn, iAttackerInitialDamage, iWinningOdds, iInitialAttXP, iInitialAttGGXP, iDefenderInitialDamage, iInitialDefXP, iInitialDefGGXP, bPromotion, bDefPromotion);
        doDynamicXP(pDefender, pPlot, iAttackerInitialDamage, iWinningOdds, iDefenderInitialDamage, iInitialAttXP, iInitialDefXP, iInitialAttGGXP, iInitialDefGGXP, bPromotion, bDefPromotion);

        doCommerceAttacks(pDefender, pPlot);
        doCommerceAttacks(this, pPlot);
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
}


void CvUnit::updateCombat(bool bQuick)
{
        PROFILE_FUNC();

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
        // Dale - SA: Stack Attack START
        if (GC.isDCM_STACK_ATTACK())
        {
                updateStackCombat(bQuick);
                return;
        }
        // Dale - SA: Stack Attack END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/

        CvWString szBuffer;

        bool bFinish = false;
        bool bVisible = false;

        if (getCombatTimer() > 0)
        {
                changeCombatTimer(-1);

                if (getCombatTimer() > 0)
                {
                        return;
                }
                else
                {
                        bFinish = true;
                }
        }

        CvPlot* pPlot = getAttackPlot();

        if (pPlot == NULL)
        {
                return;
        }

        if (getDomainType() == DOMAIN_AIR)
        {
                updateAirStrike(pPlot, bQuick, bFinish);
                return;
        }

        CvUnit* pDefender = NULL;
        if (bFinish)
        {
                pDefender = getCombatUnit();
        }
        else
        {
                pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
        }

        if (pDefender == NULL)
        {
                setAttackPlot(NULL, false);
                setCombatUnit(NULL);

                getGroup()->groupMove(pPlot, true, ((canAdvance(pPlot, 0)) ? this : NULL));

                getGroup()->clearMissionQueue();

                return;
        }

        //check if quick combat
        if (!bQuick)
        {
                bVisible = isCombatVisible(pDefender);
        }
        //FAssertMsg((pPlot == pDefender->plot()), "There is not expected to be a defender or the defender's plot is expected to be pPlot (the attack plot)");

        //if not finished and not fighting yet, set up combat damage and mission
        if (!bFinish)
        {
                if (!isFighting())
                {
                        PROFILE("CvUnit::updateCombat.StartFight");

                        if (plot()->isFighting() || pPlot->isFighting())
                        {
                                return;
                        }

                        setMadeAttack(true);

                        //rotate to face plot
                        DirectionTypes newDirection = estimateDirection(this->plot(), pDefender->plot());
                        if (newDirection != NO_DIRECTION)
                        {
                                setFacingDirection(newDirection);
                        }

                        //rotate enemy to face us
                        newDirection = estimateDirection(pDefender->plot(), this->plot());
                        if (newDirection != NO_DIRECTION)
                        {
                                pDefender->setFacingDirection(newDirection);
                        }

                        setCombatUnit(pDefender, true);
                        pDefender->setCombatUnit(this, false);

                        pDefender->getGroup()->clearMissionQueue();

                        bool bFocused = (bVisible && isCombatFocus() && gDLL->getInterfaceIFace()->isCombatFocus() && plot()->isInViewport() && pDefender->isInViewport());

                        if (bFocused)
                        {
                                DirectionTypes directionType = directionXY(plot(), pPlot);
                                //                                                              N                       NE                              E                               SE                                      S                               SW                                      W                               NW
                                NiPoint2 directions[8] = {NiPoint2(0, 1), NiPoint2(1, 1), NiPoint2(1, 0), NiPoint2(1, -1), NiPoint2(0, -1), NiPoint2(-1, -1), NiPoint2(-1, 0), NiPoint2(-1, 1)};
                                NiPoint3 attackDirection = NiPoint3(directions[directionType].x, directions[directionType].y, 0);
                                float plotSize = GC.getPLOT_SIZE();
                                NiPoint3 lookAtPoint(plot()->getPoint().x + plotSize / 2 * attackDirection.x, plot()->getPoint().y + plotSize / 2 * attackDirection.y, (plot()->getPoint().z + pPlot->getPoint().z) / 2);
                                attackDirection.Unitize();
                                gDLL->getInterfaceIFace()->lookAt(lookAtPoint, (((getOwnerINLINE() != GC.getGameINLINE().getActivePlayer()) || gDLL->getGraphicOption(GRAPHICOPTION_NO_COMBAT_ZOOM)) ? CAMERALOOKAT_BATTLE : CAMERALOOKAT_BATTLE_ZOOM_IN), attackDirection);
                        }
                        else
                        {
                                MEMORY_TRACK_EXEMPT();

                                PlayerTypes eAttacker = getVisualOwner(pDefender->getTeam());
                                CvWString szMessage;
                                if (BARBARIAN_PLAYER != eAttacker)
                                {
                                        szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK", GET_PLAYER(getOwnerINLINE()).getNameKey());
                                }
                                else
                                {
                                        szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK_UNKNOWN");
                                }

                                AddDLLMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szMessage, "AS2D_COMBAT", MESSAGE_TYPE_DISPLAY_ONLY, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true);
                        }
                }

                //OutputDebugString("UI interaction - unit attacked 1\n");
                GET_PLAYER(pDefender->getOwnerINLINE()).setTurnHadUIInteraction(true);

                FAssertMsg(pDefender != NULL, "Defender is not assigned a valid value");

                FAssertMsg(plot()->isFighting(), "Current unit instance plot is not fighting as expected");
                FAssertMsg(pPlot->isFighting(), "pPlot is not fighting as expected");

                if (!pDefender->canDefend())
                {
                        if (!bVisible)
                        {
                                bFinish = true;
                        }
                        else
                        {
                                if ( !pDefender->isUsingDummyEntities() )
                                {
                                        CvMissionDefinition kMission;
                                        kMission.setMissionTime(getCombatTimer() * gDLL->getSecsPerTurn());
                                        kMission.setMissionType(MISSION_SURRENDER);
                                        kMission.setUnit(BATTLE_UNIT_ATTACKER, this);
                                        kMission.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
                                        kMission.setPlot(pPlot);
                                        addMission(&kMission);
                                }

                                // Surrender mission
                                setCombatTimer(GC.getMissionInfo(MISSION_SURRENDER).getTime());

                                GC.getGameINLINE().incrementTurnTimer(getCombatTimer());
                        }

                        // Kill them!
                        pDefender->setDamage(GC.getMAX_HIT_POINTS());
                }
                else
                {
                        PROFILE("CvUnit::updateCombat.CanDefend");

/************************************************************************************************/
/* Afforess                       Start          03/1/10                       Coded By: KillMePlease   */
/*                                                                                              */
/* Great Commanders                                                                             */
/************************************************************************************************/
                        //USE commanders here (so their command points will be decreased) for attacker and defender:
                        this->tryUseCommander();
                        pDefender->tryUseCommander();
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                        CvBattleDefinition kBattle;
                        kBattle.setUnit(BATTLE_UNIT_ATTACKER, this);
                        kBattle.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
                        kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN, getDamage());
                        kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN, pDefender->getDamage());

                        //      Koshling - save pre-combat helath so we can use health loss as
                        //      a basis for more granular war weariness
                        setupPreCombatDamage();
                        pDefender->setupPreCombatDamage();

                        resolveCombat(pDefender, pPlot, kBattle);

                        if (!bVisible)
                        {
                                if ( !isHuman() )
                                {
                                        bFinish = true;
                                }
                                else
                                {
                                        //      Hack to make quick offensive option not switch away from
                                        //      the stack.  It appears to be a bug in the main game engine
                                        //      in that it ALWAYS switches away unles you compleet the combat
                                        //      in a timer update call rather than directly here, so fake up
                                        //      a pseudo-combat round to perform delayed completion (but without
                                        //      animation, so no battle setup) via the unit timer
                                        setCombatTimer(1);

                                        GC.getGameINLINE().incrementTurnTimer(getCombatTimer());
                                }
                        }
                        else
                        {
                                kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_END, getDamage());
                                kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_END, pDefender->getDamage());
                                kBattle.setAdvanceSquare(canAdvance(pPlot, pDefender->isDead() ? 0 : 1));

                                if (isRanged() && pDefender->isRanged())
                                {
                                        kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_END));
                                        kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_END));
                                }
                                else
                                {
                                        kBattle.addDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN));
                                        kBattle.addDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN));
                                }

                                int iTurns = planBattle( kBattle);
                                kBattle.setMissionTime(iTurns * gDLL->getSecsPerTurn());
                                setCombatTimer(iTurns);

                                GC.getGameINLINE().incrementTurnTimer(getCombatTimer());

                                if (pPlot->isActiveVisible(false) && !pDefender->isUsingDummyEntities() )
                                {
                                        ExecuteMove(0.5f, true);
                                        addMission(&kBattle);
                                }
                        }
                }
        }

        if (bFinish)
        {
                PROFILE("CvUnit::updateCombat.Finish");

                if (bVisible)
                {
                        if (isCombatFocus() && gDLL->getInterfaceIFace()->isCombatFocus())
                        {
                                if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
                                {
                                        gDLL->getInterfaceIFace()->releaseLockedCamera();
                                }
                        }
                }

                //end the combat mission if this code executes first
                if ( !isUsingDummyEntities() && isInViewport())
                {
                        gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
                }
                if ( !pDefender->isUsingDummyEntities() && pDefender->isInViewport())
                {
                        gDLL->getEntityIFace()->RemoveUnitFromBattle(pDefender);
                }
                setAttackPlot(NULL, false);
                setCombatUnit(NULL);
                pDefender->setCombatUnit(NULL);
                NotifyEntity(MISSION_DAMAGE);
                pDefender->NotifyEntity(MISSION_DAMAGE);

                if (isDead())
                {
                        if (isBarbarian())
                        {
                                GET_PLAYER(pDefender->getOwnerINLINE()).changeWinsVsBarbs(1);
                        }

                        if ((!m_pUnitInfo->isHiddenNationality() && !pDefender->getUnitInfo().isHiddenNationality()) && !isPirate())
                        {
                                int     attackerPreCombatDamage = getPreCombatDamage();
                                int defenderPreCombatDamage = pDefender->getPreCombatDamage();

                                int     attackerWarWearinessChangeTimes100 = std::max(1, (100*GC.getDefineINT("WW_UNIT_KILLED_ATTACKING")*(maxHitPoints() - attackerPreCombatDamage))/maxHitPoints());
                                GET_TEAM(getTeam()).changeWarWearinessTimes100(pDefender->getTeam(), *pPlot, attackerWarWearinessChangeTimes100);

                                int     defenderWarWearinessChangeTimes100 = (100*GC.getDefineINT("WW_KILLED_UNIT_DEFENDING")*(pDefender->getDamage() - pDefender->getPreCombatDamage()))/pDefender->maxHitPoints();
                                GET_TEAM(pDefender->getTeam()).changeWarWearinessTimes100(getTeam(), *pPlot, defenderWarWearinessChangeTimes100);

                                GET_TEAM(pDefender->getTeam()).AI_changeWarSuccess(getTeam(), GC.getDefineINT("WAR_SUCCESS_DEFENDING"));
                        }

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_DIED_ATTACKING", getNameKey(), pDefender->getNameKey());
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              Start                                                 */
/************************************************************************************************/
                        // ------ BEGIN InfluenceDrivenWar -------------------------------
                        float fInfluenceRatio = 0.0;
                        if (GC.isIDW_ENABLED())
                        {
                                fInfluenceRatio = pDefender->doVictoryInfluence(this, false, false);
                                /*** Dexy - Fixed Borders START ****/
                                if (fInfluenceRatio > 0.0f)
                                /*** Dexy - Fixed Borders  END  ****/
                                {
                                CvWString szTempBuffer;
                                szTempBuffer.Format(L" Influence: -%.1f%%", fInfluenceRatio);
                                szBuffer += szTempBuffer;
                                }
                        }
                        // ------ END InfluenceDrivenWar ---------------------------------
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              End                                                   */
/************************************************************************************************/
                        {
                                MEMORY_TRACK_EXEMPT();
                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }
                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_KILLED_ENEMY_UNIT", pDefender->getNameKey(), getNameKey(), getVisualCivAdjective(pDefender->getTeam()));
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              Start                                                 */
/************************************************************************************************/
                        // ------ BEGIN InfluenceDrivenWar -------------------------------
                        if (GC.isIDW_ENABLED())
                        {
                                /*** Dexy - Fixed Borders START ****/
                                if (fInfluenceRatio > 0.0f)
                                /*** Dexy - Fixed Borders  END  ****/
                                {
                                CvWString szTempBuffer;
                                szTempBuffer.Format(L" Influence: +%.1f%%", fInfluenceRatio);
                                szBuffer += szTempBuffer;
                                }
                        }
                        // ------ END InfluenceDrivenWar ---------------------------------
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              End                                                   */
/************************************************************************************************/
                        {
                                MEMORY_TRACK_EXEMPT();

                                AddDLLMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }

/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 06/27/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
            pDefender->combatWon(this, false);
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
                        // report event to Python, along with some other key state
                        CvEventReporter::getInstance().combatResult(pDefender, this);
                        getUnitInfo().getKillOutcomeList()->execute(*pDefender, getOwnerINLINE(), getUnitType());
                }
                else if (pDefender->isDead())
                {
                        if (pDefender->isBarbarian())
                        {
                                GET_PLAYER(getOwnerINLINE()).changeWinsVsBarbs(1);
                        }

                        if ((!m_pUnitInfo->isHiddenNationality() && !pDefender->getUnitInfo().isHiddenNationality()) && !isPirate())
                        {
                                int     attackerPreCombatDamage = getPreCombatDamage();
                                int defenderPreCombatDamage = pDefender->getPreCombatDamage();

                                int     defenderWarWearinessChangeTimes100 = std::max(1, (100*GC.getDefineINT("WW_UNIT_KILLED_DEFENDING")*(pDefender->maxHitPoints() - defenderPreCombatDamage))/pDefender->maxHitPoints());
                                GET_TEAM(pDefender->getTeam()).changeWarWearinessTimes100(getTeam(), *pPlot, defenderWarWearinessChangeTimes100);

                                int     attackerWarWearinessChangeTimes100 = (100*GC.getDefineINT("WW_KILLED_UNIT_ATTACKING")*(getDamage() - getPreCombatDamage()))/maxHitPoints();
                                GET_TEAM(getTeam()).changeWarWearinessTimes100(pDefender->getTeam(), *pPlot, attackerWarWearinessChangeTimes100);

                                GET_TEAM(getTeam()).AI_changeWarSuccess(pDefender->getTeam(), GC.getDefineINT("WAR_SUCCESS_ATTACKING"));
                        }

                        szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_DESTROYED_ENEMY", getNameKey(), pDefender->getNameKey());

/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              Start                                                 */
/************************************************************************************************/
                        // ------ BEGIN InfluenceDrivenWar -------------------------------
                        float fInfluenceRatio = 0.0;
                        if (GC.isIDW_ENABLED())
                        {
                                fInfluenceRatio = doVictoryInfluence(pDefender, true, false);
                                /*** Dexy - Fixed Borders START ****/
                                if (fInfluenceRatio > 0.0f)
                                /*** Dexy - Fixed Borders  END  ****/
                                {
                                CvWString szTempBuffer;
                                szTempBuffer.Format(L" Influence: +%.1f%%", fInfluenceRatio);
                                szBuffer += szTempBuffer;
                                }
                        }
                        // ------ END InfluenceDrivenWar ---------------------------------
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              End                                                   */
/************************************************************************************************/
                        {
                                MEMORY_TRACK_EXEMPT();

                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }
                        if (getVisualOwner(pDefender->getTeam()) != getOwnerINLINE())
                        {
                                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED_UNKNOWN", pDefender->getNameKey(), getNameKey());
                        }

                        else
                        {
                                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED", pDefender->getNameKey(), getNameKey(), getVisualCivAdjective(pDefender->getTeam()));
                        }
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              Start                                                 */
/************************************************************************************************/
                        // ------ BEGIN InfluenceDrivenWar -------------------------------
                        if (GC.isIDW_ENABLED())
                        {
                                /*** Dexy - Fixed Borders START ****/
                                if (fInfluenceRatio > 0.0f)
                                /*** Dexy - Fixed Borders  END  ****/
                                {
                                        CvWString szTempBuffer;
                                        szTempBuffer.Format(L" Influence: -%.1f%%", fInfluenceRatio);
                                        szBuffer += szTempBuffer;
                                }
                        }
                        // ------ END InfluenceDrivenWar ---------------------------------
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              End                                                   */
/************************************************************************************************/
                        {
                                MEMORY_TRACK_EXEMPT();

                                AddDLLMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer,GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }

/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 06/27/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
            combatWon(pDefender, true);
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
                        // report event to Python, along with some other key state
                        CvEventReporter::getInstance().combatResult(this, pDefender);

                        CvUnitInfo* pDefenderUnitInfo = &(pDefender->getUnitInfo());
                        UnitTypes eDefenderUnitType = pDefender->getUnitType();
                        PlayerTypes eDefenderUnitPlayer = pDefender->getOwnerINLINE();

                        bool bAdvance = false;

                        if (isSuicide())
                        {
                                kill(true);

                                pDefender->kill(false, NO_PLAYER, true);
                                pDefender = NULL;
                        }
                        else
                        {
                                bAdvance = canAdvance(pPlot, ((pDefender->canDefend() && !pDefender->isDead()) ? 1 : 0));

                                if (bAdvance)
                                {
                                        if (!isNoCapture())
                                        {
                                                pDefender->setCapturingPlayer(getOwnerINLINE());
                                        }
                                }

                                pDefender->killUnconditional(false, NO_PLAYER, true);
                                pDefender = NULL;

                                if (!bAdvance)
                                {
                                        changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                                        checkRemoveSelectionAfterAttack();
                                }
                        }

/****************************************************************************************/
/* REVOLUTIONDCM                                09/06/09                                                jdog5000                */
/**                                                                                                                                                                             */
/**                                                                                                                                                                             */
/****************************************************************************************/
                        // Fix rare crash bug
                        if( getGroup() != NULL )
                        {
                                if (pPlot->getNumVisibleEnemyDefenders(this) == 0)
                                {
                                        PROFILE("CvUnit::updateCombat.Advance");

                                        getGroup()->groupMove(pPlot, true, ((bAdvance) ? this : NULL));
                                }

                                // This is is put before the plot advancement, the unit will always try to walk back
                                // to the square that they came from, before advancing.
                                getGroup()->clearMissionQueue();
                        }

                        pDefenderUnitInfo->getKillOutcomeList()->execute(*this, eDefenderUnitPlayer, eDefenderUnitType);

/****************************************************************************************/
/* REVOLUTIONDCM                                END                                                     jdog5000                */
/****************************************************************************************/
                }
/************************************************************************************************/
/* Afforess                       Start          02/22/10                    Coded By: KillMePlease     */
/*                                                                                              */
/*  Defender Withdraw                                                                           */
/************************************************************************************************/
                else if (m_combatResult.bDefenderWithdrawn)
                {
                        {
                                MEMORY_TRACK_EXEMPT();

                                szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_UNIT_WITHDRAW", pDefender->getNameKey(), getNameKey());
                                AddDLLMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WITHDRAW", pDefender->getNameKey(), getNameKey());
                                AddDLLMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }

                        if (pPlot->isCity())
                        {
                                m_combatResult.pPlot = NULL;
                        }

                        if (m_combatResult.pPlot != NULL)
                        {
                                //defender escapes to a safe plot
                                pDefender->move(m_combatResult.pPlot, true);
                                changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                                checkRemoveSelectionAfterAttack();
                                getGroup()->clearMissionQueue();
                        }
                }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                else
                {
                        {
                                MEMORY_TRACK_EXEMPT();

                                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
                                AddMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                                szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
                                AddMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                        }

                        changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                        checkRemoveSelectionAfterAttack();
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              Start                                                 */
/************************************************************************************************/
                                // ------ BEGIN InfluenceDrivenWar -------------------------------
                                if (GC.isIDW_ENABLED())
                                {
                                        if (!canMove() || !isBlitz())
                                        {
                                                if (IsSelected())
                                                {
                                                        if (gDLL->getInterfaceIFace()->getLengthSelectionList() > 1)
                                                        {
                                                                gDLL->getInterfaceIFace()->removeFromSelectionList(this);
                                                        }
                                                }
                                        }
                                }
                        // ------ END InfluenceDrivenWar -------------------------------
/************************************************************************************************/
/* INFLUENCE_DRIVEN_WAR                   04/16/09                                johnysmith    */
/*                                                                                              */
/* Original Author Moctezuma              End                                                   */
/************************************************************************************************/

                        getGroup()->clearMissionQueue();
                }
        }
}

void CvUnit::checkRemoveSelectionAfterAttack()
{
        if (!canMove() || !isBlitz())
        {
                if (IsSelected())
                {
                        if (gDLL->getInterfaceIFace()->getLengthSelectionList() > 1)
                        {
                                gDLL->getInterfaceIFace()->removeFromSelectionList(this);
                        }
                }
        }
}


bool CvUnit::isActionRecommended(int iAction)
{
        CvCity* pWorkingCity;
        CvPlot* pPlot;
        ImprovementTypes eImprovement;
        ImprovementTypes eFinalImprovement;
        BuildTypes eBuild;
        RouteTypes eRoute;
        BonusTypes eBonus;
        int iIndex;

        if (getOwnerINLINE() != GC.getGameINLINE().getActivePlayer())
        {
                return false;
        }

        if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_NO_UNIT_RECOMMENDATIONS))
        {
                return false;
        }

        {
                PYTHON_ACCESS_LOCK_SCOPE

                CyUnit* pyUnit = new CyUnit(this);
                CyArgsList argsList;
                argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit)); // pass in unit class
                argsList.add(iAction);
                long lResult=0;
                PYTHON_CALL_FUNCTION4(__FUNCTION__, PYGameModule, "isActionRecommended", argsList.makeFunctionArgs(), &lResult);
                delete pyUnit;  // python fxn must not hold on to this pointer
                if (lResult == 1)
                {
                        return true;
                }
        }

        pPlot = gDLL->getInterfaceIFace()->getGotoPlot();

        if (pPlot == NULL)
        {
                if (gDLL->shiftKey())
                {
                        pPlot = getGroup()->lastMissionPlot();
                }
        }

        if (pPlot == NULL)
        {
                pPlot = plot();
        }

// BUFFY - Don't Recommend Actions in Fog of War - start
#ifdef _BUFFY
        // from HOF Mod - Denniz
        if (!pPlot->isVisible(GC.getGameINLINE().getActiveTeam(), false))
        {
                return false;
        }
#endif
// BUFFY - Don't Recommend Actions in Fog of War - end

        if (GC.getActionInfo(iAction).getMissionType() == MISSION_FORTIFY)
        {
                if (pPlot->isCity(true, getTeam()))
                {
                        if (canDefend(pPlot))
                        {
                                if (pPlot->getNumDefenders(getOwnerINLINE()) < ((atPlot(pPlot)) ? 2 : 1))
                                {
                                        return true;
                                }
                        }
                }
        }

// BUG - Sentry Actions - start
#ifdef _MOD_SENTRY
        if ((GC.getActionInfo(iAction).getMissionType() == MISSION_HEAL) || (GC.getActionInfo(iAction).getMissionType() == MISSION_SENTRY_WHILE_HEAL))
#else
        if (GC.getActionInfo(iAction).getMissionType() == MISSION_HEAL)
#endif
// BUG - Sentry Actions - end
        {
                if (isHurt())
                {
                        if (!hasMoved())
                        {
                                if ((pPlot->getTeam() == getTeam()) || (healTurns(pPlot) < 4))
                                {
                                        return true;
                                }
                        }
                }
        }

        if (GC.getActionInfo(iAction).getMissionType() == MISSION_FOUND)
        {
                if (canFound(pPlot))
                {
                        if (pPlot->isBestAdjacentFound(getOwnerINLINE()))
                        {
                                return true;
                        }
                }
        }

        if (GC.getActionInfo(iAction).getMissionType() == MISSION_BUILD)
        {
                if (pPlot->getOwnerINLINE() == getOwnerINLINE())
                {
                        eBuild = ((BuildTypes)(GC.getActionInfo(iAction).getMissionData()));
                        FAssert(eBuild != NO_BUILD);
                        FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

                        if (canBuild(pPlot, eBuild))
                        {
                                eImprovement = ((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement()));
                                eRoute = ((RouteTypes)(GC.getBuildInfo(eBuild).getRoute()));
                                eBonus = pPlot->getBonusType(getTeam());
                                pWorkingCity = pPlot->getWorkingCity();

                                if (pPlot->getImprovementType() == NO_IMPROVEMENT)
                                {
                                        if (pWorkingCity != NULL)
                                        {
                                                iIndex = pWorkingCity->getCityPlotIndex(pPlot);

                                                if (iIndex != -1)
                                                {
                                                        if (pWorkingCity->AI_getBestBuild(iIndex) == eBuild)
                                                        {
                                                                return true;
                                                        }
                                                }
                                        }

                                        if (eImprovement != NO_IMPROVEMENT)
                                        {
                                                if (eBonus != NO_BONUS)
                                                {
                                                        if (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eBonus))
                                                        {
                                                                return true;
                                                        }
                                                }

                                                if (pPlot->getImprovementType() == NO_IMPROVEMENT)
                                                {
                                                        if (!(pPlot->isIrrigated()) && pPlot->isIrrigationAvailable(true))
                                                        {
                                                                if (GC.getImprovementInfo(eImprovement).isCarriesIrrigation())
                                                                {
                                                                        return true;
                                                                }
                                                        }

                                                        if (pWorkingCity != NULL)
                                                        {
                                                                if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_FOOD) > 0)
                                                                {
                                                                        return true;
                                                                }

                                                                if (pPlot->isHills())
                                                                {
                                                                        if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_PRODUCTION) > 0)
                                                                        {
                                                                                return true;
                                                                        }
                                                                }
                                                                else
                                                                {
                                                                        if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_COMMERCE) > 0)
                                                                        {
                                                                                return true;
                                                                        }
                                                                }
                                                        }
                                                }
                                        }
                                }

                                if (eRoute != NO_ROUTE)
                                {
                                        if (!(pPlot->isRoute()))
                                        {
                                                if (eBonus != NO_BONUS)
                                                {
                                                        return true;
                                                }

                                                if (pWorkingCity != NULL)
                                                {
                                                        if (pPlot->isRiver())
                                                        {
                                                                return true;
                                                        }
                                                }
                                        }

                                        eFinalImprovement = eImprovement;

                                        if (eFinalImprovement == NO_IMPROVEMENT)
                                        {
                                                eFinalImprovement = pPlot->getImprovementType();
                                        }

                                        if (eFinalImprovement != NO_IMPROVEMENT)
                                        {
                                                if ((GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_FOOD) > 0) ||
                                                        (GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_PRODUCTION) > 0) ||
                                                        (GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_COMMERCE) > 0))
                                                {
                                                        return true;
                                                }
                                        }
                                }
                        }
                }
        }

        if (GC.getActionInfo(iAction).getCommandType() == COMMAND_PROMOTION)
        {
                return true;
        }

        return false;
}


int CvUnit::defenderValue(const CvUnit* pAttacker) const
{
        int iValue = 0;

        TeamTypes eAttackerTeam = NO_TEAM;
        if (NULL != pAttacker)
        {
                eAttackerTeam = pAttacker->getTeam();
        }

        if (canCoexistWithEnemyUnit(eAttackerTeam))
        {
                return 0;
        }

        if (!canDefend())
        {
                return 1;
        }

        if (pAttacker)
        {
                if (isTargetOf(*pAttacker))
                {
                        iValue += 10000;
                }

                if (!pAttacker->canAttack(*this))
                {
                        return 2;
                }
        }

        iValue += currCombatStr(plot(), pAttacker);
        if (::isWorldUnitClass(getUnitClassType()))
        {
                iValue /= 2;
        }

        if (NULL == pAttacker)
        {
                if (collateralDamage() > 0)
                {
                        iValue *= 100;
                        iValue /= (100 + collateralDamage());
                }

                if (currInterceptionProbability() > 0)
                {
                        iValue *= 100;
                        iValue /= (100 + currInterceptionProbability());
                }
        }
        else
        {
                if (!(pAttacker->immuneToFirstStrikes()))
                {
                        // UncutDragon
/* original code
                        iOurDefense *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iValue *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iValue /= 100;
                }

                if (immuneToFirstStrikes())
                {
                        // UncutDragon
/* original code
                        iOurDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iValue *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iValue /= 100;
                }
        }

        int iAssetValue = std::max(1, getUnitInfo().getAssetValue());
        int iCargoAssetValue = 0;
        std::vector<CvUnit*> aCargoUnits;
        getCargoUnits(aCargoUnits);
        for (uint i = 0; i < aCargoUnits.size(); ++i)
        {
                iCargoAssetValue += aCargoUnits[i]->getUnitInfo().getAssetValue();
        }
        iValue = iValue * iAssetValue / std::max(1, iAssetValue + iCargoAssetValue);

        if (NO_UNIT == getLeaderUnitType())
        {
                ++iValue;
        }

        return iValue + 3;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/21/10                                jdog5000      */
/*                                                                                              */
/* Efficiency, Lead From Behind                                                                 */
/************************************************************************************************/
// From Lead From Behind by UncutDragon
/* original code
bool CvUnit::isBetterDefenderThan(const CvUnit* pDefender, const CvUnit* pAttacker) const
*/
// modified (with extra parameter)
bool CvUnit::isBetterDefenderThan(const CvUnit* pDefender, const CvUnit* pAttacker, int* pBestDefenderRank) const
{
        int iOurDefense;
        int iTheirDefense;

        if (pDefender == NULL)
        {
                return true;
        }

        TeamTypes eAttackerTeam = NO_TEAM;
        if (NULL != pAttacker)
        {
                eAttackerTeam = pAttacker->getTeam();
        }

        if (canCoexistWithEnemyUnit(eAttackerTeam))
        {
                return false;
        }

        if (!canDefend())
        {
                return false;
        }

        if (canDefend() && !(pDefender->canDefend()))
        {
                return true;
        }

        if (pAttacker)
        {
                if (isTargetOf(*pAttacker) && !pDefender->isTargetOf(*pAttacker))
                {
                        return true;
                }

                if (!isTargetOf(*pAttacker) && pDefender->isTargetOf(*pAttacker))
                {
                        return false;
                }

                if (pAttacker->canAttack(*pDefender) && !pAttacker->canAttack(*this))
                {
                        return false;
                }

                if (pAttacker->canAttack(*this) && !pAttacker->canAttack(*pDefender))
                {
                        return true;
                }
        }

        // UncutDragon
        // To cut down on changes to existing code, we just short-circuit the method
        // and this point and call our own version instead
        if (GC.getLFBEnable())
                return LFBisBetterDefenderThan(pDefender, pAttacker, pBestDefenderRank);
        // /UncutDragon

        iOurDefense = currCombatStr(plot(), pAttacker);
        if (::isWorldUnitClass(getUnitClassType()))
        {
                iOurDefense /= 2;
        }

        if (NULL == pAttacker)
        {
                if (pDefender->collateralDamage() > 0)
                {
                        iOurDefense *= (100 + pDefender->collateralDamage());
                        iOurDefense /= 100;
                }

                if (pDefender->currInterceptionProbability() > 0)
                {
                        iOurDefense *= (100 + pDefender->currInterceptionProbability());
                        iOurDefense /= 100;
                }
        }
        else
        {
                if (!(pAttacker->immuneToFirstStrikes()))
                {
                        // UncutDragon
/* original code
                        iOurDefense *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iOurDefense *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iOurDefense /= 100;
                }

                if (immuneToFirstStrikes())
                {
                        // UncutDragon
/* original code
                        iOurDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iOurDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iOurDefense /= 100;
                }
        }

        int iAssetValue = std::max(1, getUnitInfo().getAssetValue());
        int iCargoAssetValue = 0;
        std::vector<CvUnit*> aCargoUnits;
        getCargoUnits(aCargoUnits);
        for (uint i = 0; i < aCargoUnits.size(); ++i)
        {
                iCargoAssetValue += aCargoUnits[i]->getUnitInfo().getAssetValue();
        }
        iOurDefense = iOurDefense * iAssetValue / std::max(1, iAssetValue + iCargoAssetValue);

        iTheirDefense = pDefender->currCombatStr(plot(), pAttacker);
        if (::isWorldUnitClass(pDefender->getUnitClassType()))
        {
                iTheirDefense /= 2;
        }

        if (NULL == pAttacker)
        {
                if (collateralDamage() > 0)
                {
                        iTheirDefense *= (100 + collateralDamage());
                        iTheirDefense /= 100;
                }

                if (currInterceptionProbability() > 0)
                {
                        iTheirDefense *= (100 + currInterceptionProbability());
                        iTheirDefense /= 100;
                }
        }
        else
        {
                if (!(pAttacker->immuneToFirstStrikes()))
                {
                        // UncutDragon
/* original code
                        iTheirDefense *= ((((pDefender->firstStrikes() * 2) + pDefender->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iTheirDefense *= ((((pDefender->firstStrikes() * 2) + pDefender->chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iTheirDefense /= 100;
                }

                if (pDefender->immuneToFirstStrikes())
                {
                        // UncutDragon
/* original code
                        iTheirDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
*/
                      // modified
                        iTheirDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getCOMBAT_DAMAGE() * 2) / 5)) + 100);
                        // /UncutDragon
                        iTheirDefense /= 100;
                }
        }

        iAssetValue = std::max(1, pDefender->getUnitInfo().getAssetValue());
        iCargoAssetValue = 0;
        pDefender->getCargoUnits(aCargoUnits);
        for (uint i = 0; i < aCargoUnits.size(); ++i)
        {
                iCargoAssetValue += aCargoUnits[i]->getUnitInfo().getAssetValue();
        }
        iTheirDefense = iTheirDefense * iAssetValue / std::max(1, iAssetValue + iCargoAssetValue);

        if (iOurDefense == iTheirDefense)
        {
                if (NO_UNIT == getLeaderUnitType() && NO_UNIT != pDefender->getLeaderUnitType())
                {
                        ++iOurDefense;
                }
                else if (NO_UNIT != getLeaderUnitType() && NO_UNIT == pDefender->getLeaderUnitType())
                {
                        ++iTheirDefense;
                }
                else if (isBeforeUnitCycle(this, pDefender))
                {
                        ++iOurDefense;
                }
        }

        return (iOurDefense > iTheirDefense);
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


bool CvUnit::canDoCommand(CommandTypes eCommand, int iData1, int iData2, bool bTestVisible, bool bTestBusy)
{
        CvUnit* pUnit;

        if (bTestBusy && getGroup()->isBusy())
        {
                return false;
        }

        switch (eCommand)
        {
        case COMMAND_PROMOTION:
                if (canPromote((PromotionTypes)iData1, iData2))
                {
                        return true;
                }
                break;

        case COMMAND_UPGRADE:
                if (canUpgrade(((UnitTypes)iData1), bTestVisible))
                {
                        return true;
                }
                break;

        case COMMAND_AUTOMATE:
                if (canAutomate((AutomateTypes)iData1))
                {
                        return true;
                }
                break;

        case COMMAND_WAKE:
                if (!isAutomated() && isWaiting())
                {
                        return true;
                }
                break;

        case COMMAND_CANCEL:
        case COMMAND_CANCEL_ALL:
                if (!isAutomated() && (getGroup()->getLengthMissionQueue() > 0))
                {
                        return true;
                }
                // < M.A.D. Nukes Start >
                if(isMADEnabled() && getUnitInfo().getUnitAIType(UNITAI_ICBM))
                {
                        return true;
                }
                // < M.A.D. Nukes End   >

                break;

        case COMMAND_STOP_AUTOMATION:
                if (isAutomated())
                {
                        return true;
                }
                break;

        case COMMAND_DELETE:
                if (canScrap())
                {
                        return true;
                }
                break;

        case COMMAND_GIFT:
                if (canGift(bTestVisible))
                {
                        return true;
                }
                break;

        case COMMAND_LOAD:
                if (canLoad(plot()))
                {
                        return true;
                }
                break;

        case COMMAND_LOAD_UNIT:
                pUnit = ::getUnit(IDInfo(((PlayerTypes)iData1), iData2));
                if (pUnit != NULL)
                {
                        if (canLoadUnit(pUnit, plot()))
                        {
                                return true;
                        }
                }
                break;

        case COMMAND_UNLOAD:
                if (canUnload())
                {
                        return true;
                }
                break;

        case COMMAND_UNLOAD_ALL:
                if (canUnloadAll())
                {
                        return true;
                }
                break;

        case COMMAND_HOTKEY:
                if (isGroupHead())
                {
                        return true;
                }
                break;

/************************************************************************************************/
/* Great Diplomat MOD               START                                                               */
/************************************************************************************************/
        case COMMAND_COLONIZE_BARBARIANS:
                if (canColonizeBarbarians(plot()))
                {
                        return true;
                }
                break;

        case COMMAND_FORCE_PEACE:
                if (canForcePeace())
                {
                        return true;
                }
                break;

        case COMMAND_UPGRADE_IMPROVEMENTS:
                if (canUpgradeImprovements(plot(), eCommand))
                {
                        return true;
                }
                break;
/************************************************************************************************/
/* Great Diplomat MOD               END                                                                 */
/************************************************************************************************/

        default:
                FAssert(false);
                break;
        }

        return false;
}


void CvUnit::doCommand(CommandTypes eCommand, int iData1, int iData2)
{
        CvUnit* pUnit;
        bool bCycle;

        bCycle = false;

        FAssert(getOwnerINLINE() != NO_PLAYER);

        if (canDoCommand(eCommand, iData1, iData2))
        {
                switch (eCommand)
                {
                case COMMAND_PROMOTION:
                        promote((PromotionTypes)iData1, iData2);
                        break;

                case COMMAND_UPGRADE:
                        upgrade((UnitTypes)iData1);
                        bCycle = true;
                        break;

                case COMMAND_AUTOMATE:
                        automate((AutomateTypes)iData1);
                        bCycle = true;
                        break;

                case COMMAND_WAKE:
                        getGroup()->setActivityType(ACTIVITY_AWAKE);
                        break;

                case COMMAND_CANCEL:
                        // < M.A.D. Nukes Start >
                        if(isMADEnabled() && getUnitInfo().getUnitAIType(UNITAI_ICBM))
                        {
                                clearMADTargetPlot();
                                setMoves(0);
                        }
                        getGroup()->popMission();
                        // < M.A.D. Nukes End   >
                        break;

                case COMMAND_CANCEL_ALL:
                        getGroup()->clearMissionQueue();
                        break;

                case COMMAND_STOP_AUTOMATION:
                        getGroup()->setAutomateType(NO_AUTOMATE);
                        break;

                case COMMAND_DELETE:
                        scrap();
                        bCycle = true;
                        break;

                case COMMAND_GIFT:
                        gift();
                        bCycle = true;
                        break;

                case COMMAND_LOAD:
                        load();
                        bCycle = true;
                        break;

                case COMMAND_LOAD_UNIT:
                        pUnit = ::getUnit(IDInfo(((PlayerTypes)iData1), iData2));
                        if (pUnit != NULL)
                        {
                                loadUnit(pUnit);
                                bCycle = true;
                        }
                        break;

                case COMMAND_UNLOAD:
                        unload();
                        bCycle = true;
                        break;

                case COMMAND_UNLOAD_ALL:
                        unloadAll();
                        bCycle = true;
                        break;

                case COMMAND_HOTKEY:
                        setHotKeyNumber(iData1);
                        break;

/************************************************************************************************/
/* Great Diplomat MOD               START                                                               */
/************************************************************************************************/

                case COMMAND_COLONIZE_BARBARIANS:
                        colonizeBarbarians();
                        bCycle = true;
                        break;

                case COMMAND_FORCE_PEACE:
                        //Note: this "command" was implemented incorrectly, should really be a mission
                        //Missions allow dialogue information to be passed correctly, whereas this is
                        //Really just a hack to trick the command into emulating how missions work

                        //This command happens twice. First a human player selects the command from
                        //The main interface and CvGameInterface::handleAction sends -1, -1, false as the data
                        //If iData1 == -1 (it is not set to a value) we just pressed the button and
                        //Want to get the dialogue box to appear. Only the active player (owner of the unit)
                        //should see this dialogue appear.
                        //If iData1 != -1, the active player has already pressed command force peace once
                        //Gotten the popup and selected a player, and intends to force peace
                        if (((PlayerTypes)iData1) == NO_PLAYER)
                        {
                                if (GC.getGameINLINE().getActivePlayer() == getOwnerINLINE())
                                {
                                        tryForcePeace();
                                }
                        }
                        else
                        {
                                applyForcePeace((PlayerTypes)iData1);
                        }
                        bCycle = true;
                        break;

                case COMMAND_UPGRADE_IMPROVEMENTS:
                        upgradeImprovements(plot(), eCommand);
                        bCycle = true;
                        break;
/************************************************************************************************/
/* Great Diplomat MOD               END                                                                 */
/************************************************************************************************/

                default:
                        FAssert(false);
                        break;
                }
        }

        if (bCycle)
        {
                if (IsSelected())
                {
                        gDLL->getInterfaceIFace()->setCycleSelectionCounter(1);
                }
        }

        getGroup()->doDelayedDeath();
}


#ifdef USE_OLD_PATH_GENERATOR
FAStarNode* CvUnit::getPathLastNode() const
{
        return getGroup()->getPathLastNode();
}
int CvUnit::getPathMovementRemaining() const
{
        return getGroup()->movesLeft();
}
#else
int CvUnit::getPathMovementRemaining() const
{
        return getGroup()->getPath().movementRemaining();
}
#endif


CvPlot* CvUnit::getPathEndTurnPlot() const
{
        return getGroup()->getPathEndTurnPlot();
}


bool CvUnit::generatePath(const CvPlot* pToPlot, int iFlags, bool bReuse, int* piPathTurns, int iMaxTurns, int iOptimizationLimit) const
{
        return getGroup()->generatePath(plot(), pToPlot, iFlags, bReuse, piPathTurns, iMaxTurns, iOptimizationLimit);
}


bool CvUnit::canEnterTerritory(TeamTypes eTeam, bool bIgnoreRightOfPassage) const
{
        if (GET_TEAM(getTeam()).isFriendlyTerritory(eTeam))
        {
                return true;
        }

        if (eTeam == NO_TEAM)
        {
                return true;
        }

        if (isEnemy(eTeam))
        {
                return true;
        }

        if (isRivalTerritory())
        {
                return true;
        }

        if (alwaysInvisible())
        {
                return true;
        }

        if (m_pUnitInfo->isHiddenNationality())
        {
                return true;
        }

        if (!bIgnoreRightOfPassage)
        {
                if (GET_TEAM(getTeam()).isOpenBorders(eTeam))
                {
                        return true;
                }
/************************************************************************************************/
/* Afforess                       Start          02/14/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                if (GET_TEAM(getTeam()).isLimitedBorders(eTeam))
                {
                        if (isOnlyDefensive() || !canFight())
                        {
                                return true;
                        }
                }
        }
        if (!GET_TEAM(eTeam).isAlive())
        {
                return true;
        }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        if (isPirate())
        {
                return true;
        }
        return false;
}


bool CvUnit::canEnterArea(TeamTypes eTeam, const CvArea* pArea, bool bIgnoreRightOfPassage) const
{
        if (!canEnterTerritory(eTeam, bIgnoreRightOfPassage))
        {
                return false;
        }

        if (isBarbarian() && DOMAIN_LAND == getDomainType())
        {
                if (eTeam != NO_TEAM && eTeam != getTeam())
                {
                        if (pArea && pArea->isBorderObstacle(eTeam))
                        {
                                return false;
                        }
                }
        }

        return true;
}


// Returns the ID of the team to declare war against
TeamTypes CvUnit::getDeclareWarMove(const CvPlot* pPlot) const
{
        CvUnit* pUnit;
        TeamTypes eRevealedTeam;

        FAssert(isHuman());

        if (getDomainType() != DOMAIN_AIR)
        {
                eRevealedTeam = pPlot->getRevealedTeam(getTeam(), false);

                if (eRevealedTeam != NO_TEAM)
                {
                        if (!canEnterArea(eRevealedTeam, pPlot->area()) || (getDomainType() == DOMAIN_SEA && !canCargoEnterArea(eRevealedTeam, pPlot->area(), false) && getGroup()->isAmphibPlot(pPlot)))
                        {
                                if (GET_TEAM(getTeam()).canDeclareWar(pPlot->getTeam()))
                                {
                                        return eRevealedTeam;
                                }
                        }
                }
                else
                {
                        if (pPlot->isActiveVisible(false))
                        {
                                if (canMoveInto(pPlot, true, true, true))
                                {
                                        pUnit = pPlot->plotCheck(PUF_canDeclareWar, getOwnerINLINE(), isAlwaysHostile(pPlot), NO_PLAYER, NO_TEAM, PUF_isVisible, getOwnerINLINE());

                                        if (pUnit != NULL)
                                        {
                                                return pUnit->getTeam();
                                        }
                                }
                        }
                }
        }

        return NO_TEAM;
}

bool CvUnit::willRevealByMove(const CvPlot* pPlot) const
{
        int iRange = visibilityRange(pPlot) + 1;
        for (int i = -iRange; i <= iRange; ++i)
        {
                for (int j = -iRange; j <= iRange; ++j)
                {
                        CvPlot* pLoopPlot = ::plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), i, j);
                        if (NULL != pLoopPlot)
                        {
                                if (!pLoopPlot->isRevealed(getTeam(), false) && pPlot->canSeePlot(pLoopPlot, getTeam(), visibilityRange(), NO_DIRECTION))
                                {
                                        return true;
                                }
                        }
                }
        }

        return false;
}
/************************************************************************************************/
/* Afforess                       Start          06/17/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
bool CvUnit::canMoveInto(const CvPlot* pPlot, bool bAttack, bool bDeclareWar, bool bIgnoreLoad, bool bIgnoreTileLimit, bool bIgnoreLocation, bool bIgnoreAttack) const
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
{
        bool    bFailWithAttack = false;
        bool    bFailWithoutAttack = false;

        PROFILE_FUNC();

        FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");
/************************************************************************************************/
/* Afforess                       Start          06/22/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        static int iHill = -1;
        static int iPeak = -1;

        if ( iHill == -1 )
        {
                iHill = GC.getInfoTypeForString("TERRAIN_HILL");
        }
        if ( iPeak == -1 )
        {
                iPeak = GC.getInfoTypeForString("TERRAIN_PEAK");
        }

        if (!bIgnoreLocation)
        {
                if (atPlot(pPlot))
                {
                        return false;
                }
        }

        //ls612: This code was sticky tape for the earlier AI shortcomings in this area, It was bad,
        //It wasted a ton of time, It was in the wrong file, and it didn't even do anything!
        //if (!isHuman())
        //{
        //      if (plot()->getTerrainTurnDamage() <= 0)
        //      {
        //              if (getDamage() > 50)
        //              {
        //                      if (pPlot->getTerrainTurnDamage() > 0)
        //                      {
        //                              return false;
        //                      }
        //              }
        //      }
        //}
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/

        // Cannot move around in unrevealed land freely
        if (m_pUnitInfo->isNoRevealMap() && willRevealByMove(pPlot))
        {
                return false;
        }

        if (GC.getUSE_SPIES_NO_ENTER_BORDERS())
        {
                if (isSpy() && NO_PLAYER != pPlot->getOwnerINLINE())
                {
                        if (!GET_PLAYER(getOwnerINLINE()).canSpiesEnterBorders(pPlot->getOwnerINLINE()))
                        {
                                return false;
                        }
                }
        }

        CvArea *pPlotArea = pPlot->area();
        TeamTypes ePlotTeam = pPlot->getTeam();
        bool bCanEnterArea = canEnterArea(ePlotTeam, pPlotArea);
        if (bCanEnterArea)
        {
                if (pPlot->getFeatureType() != NO_FEATURE)
                {
                        if (m_pUnitInfo->getFeatureImpassable(pPlot->getFeatureType()))
                        {
                                TechTypes eTech = (TechTypes)m_pUnitInfo->getFeaturePassableTech(pPlot->getFeatureType());
                                if (NO_TECH == eTech || !GET_TEAM(getTeam()).isHasTech(eTech))
                                {
                                        if (DOMAIN_SEA != getDomainType() || pPlot->getTeam() != getTeam())  // sea units can enter impassable in own cultural borders
                                        {
                                                return false;
                                        }
                                }
                        }
                }
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       09/17/09                         TC01 & jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                                       */
/************************************************************************************************/
/* original bts code
                else
*/

                // always check terrain also
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/
                {
/************************************************************************************************/
/* Afforess                       Start          02/14/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                        bool bPeak = false;
                        bool bHill = false;
                        if (m_pUnitInfo->getTerrainImpassable(iHill))
                                bHill = true;
                        if (m_pUnitInfo->getTerrainImpassable(iPeak))
                                bPeak = true;
                        if (m_pUnitInfo->getTerrainImpassable(pPlot->getTerrainType()) || (pPlot->isPeak() && bPeak) || (pPlot->isHills() && bHill))
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                        {
                                TechTypes eTech = (TechTypes)m_pUnitInfo->getTerrainPassableTech(pPlot->getTerrainType());
                                if (NO_TECH == eTech || !GET_TEAM(getTeam()).isHasTech(eTech))
                                {
                                        if (DOMAIN_SEA != getDomainType() || pPlot->getTeam() != getTeam())  // sea units can enter impassable in own cultural borders
                                        {
                                                if (bIgnoreLoad || !canLoad(pPlot))
                                                {
                                                        return false;
                                                }
                                        }
                                }
                        }
                }
        }

        switch (getDomainType())
        {
        case DOMAIN_SEA:
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 07/07/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                if (!pPlot->isWater() && !canMoveAllTerrain() && !pPlot->isCanMoveSeaUnits())
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
                {
                        if (!pPlot->isFriendlyCity(*this, true) || !pPlot->isCoastalLand())
                        {
                                return false;
                        }
                }
                break;

        case DOMAIN_AIR:
                if (!bAttack)
                {
                        bool bValid = false;

                        if (pPlot->isFriendlyCity(*this, true))
                        {
                                bValid = true;

                                if (m_pUnitInfo->getAirUnitCap() > 0)
                                {
                                        if (pPlot->airUnitSpaceAvailable(getTeam()) <= 0)
                                        {
                                                bValid = false;
                                        }
                                }
                        }

                        if (!bValid)
                        {
                                if (bIgnoreLoad || !canLoad(pPlot))
                                {
                                        if ( !bIgnoreAttack )
                                        {
                                                return false;
                                        }
                                        else
                                        {
                                                bFailWithoutAttack = true;
                                        }
                                }
                        }
/************************************************************************************************/
/* Afforess                       Start          03/7/10                                                */
/*                                                                                              */
/*  Rebase Limit                                                                                */
/************************************************************************************************/
                        if (!bFailWithoutAttack && !GET_TEAM(getTeam()).isRebaseAnywhere())
                        {
                                if ((GC.getGameINLINE().isModderGameOption(MODDERGAMEOPTION_AIRLIFT_RANGE)))
                                {
                                        if (plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), getX_INLINE(), getY_INLINE()) > (GC.getGameINLINE().getModderGameOption(MODDERGAMEOPTION_AIRLIFT_RANGE)))
                                        {
                                                if ( !bIgnoreAttack )
                                                {
                                                        return false;
                                                }
                                                else
                                                {
                                                        bFailWithoutAttack = true;
                                                }
                                        }
                                }
                        }
/************************************************************************************************/
/* Afforess                          END                                                            */
/************************************************************************************************/
                }

                break;

        case DOMAIN_LAND:
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 07/07/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
                if (pPlot->isWater() && !canMoveAllTerrain() && !pPlot->isCanMoveLandUnits())
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
                {
                        if (!pPlot->isCity() || 0 == GC.getLAND_UNITS_CAN_ATTACK_WATER_CITIES())
                        {
                                if (bIgnoreLoad || !isHuman() || plot()->isWater() || !canLoad(pPlot))
                                {
                                        return false;
                                }
                        }
                }
                break;

        case DOMAIN_IMMOBILE:
                return false;
                break;

        default:
                FAssert(false);
                break;
        }

/************************************************************************************************/
/* Afforess   Route Restricter   Start       08/03/09                                                */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
        if (m_pUnitInfo->getPassableRouteNeeded(0) || m_pUnitInfo->getPassableRouteNeeded(1))
        {
                if (!(m_pUnitInfo->getPassableRouteNeeded(pPlot->getRouteType()) && pPlot->isRoute()))
                {
                        return false;
                }
        }
/************************************************************************************************/
/* Afforess   Route Restricter End               END                                            */
/************************************************************************************************/

        //ls612: For units that can't enter non-Owned Cities
        if (m_pUnitInfo->isNoNonOwnedEntry() && pPlot->isCity() && (pPlot->getOwnerINLINE() != getOwnerINLINE()))
        {
                return false;
        }

        if (isAnimal())
        {
                if (pPlot->isOwned() && pPlot->getOwnerINLINE() != BARBARIAN_PLAYER)
                {
                        return false;
                }

                if (!bAttack && !bFailWithoutAttack)
                {
                        if (pPlot->getBonusType() != NO_BONUS)
                        {
                                if ( !bIgnoreAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithoutAttack = true;
                                }
                        }

                        if (pPlot->getImprovementType() != NO_IMPROVEMENT)
                        {
                                if ( !bIgnoreAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithoutAttack = true;
                                }
                        }

                        if (pPlot->getNumUnits() > 0)
                        {
                                if ( !bIgnoreAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithoutAttack = true;
                                }
                        }
                }
        }

        if (!bAttack && !bFailWithoutAttack)
        {
                if (isNoCapture())
                {
                        if (pPlot->isEnemyCity(*this))
                        {
                                if ( !bIgnoreAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithoutAttack = true;
                                }
                        }
                }
        }

/************************************************************************************************/
/* UNOFFICIAL_PATCH                       07/23/09                                jdog5000      */
/*                                                                                              */
/* Consistency                                                                                  */
/************************************************************************************************/
/* original bts code
        if (bAttack)
        {
                if (isMadeAttack() && !isBlitz())
                {
                        return false;
                }
        }
*/

        // The following change makes capturing an undefended city like a attack action, it
        // cannot be done after another attack or a paradrop
        /*
        if (bAttack || (pPlot->isEnemyCity(*this) && !canCoexistWithEnemyUnit(NO_TEAM)) )
        {
                if (isMadeAttack() && !isBlitz())
                {
                        return false;
                }
        }
        */


        // The following change makes it possible to capture defenseless units after having
        // made a previous attack or paradrop
        if( bAttack )
        {
                if (isMadeAttack() && !isBlitz() && (pPlot->getNumVisibleEnemyDefenders(this) > 0))
                {
                        if ( !bIgnoreAttack || bFailWithoutAttack )
                        {
                                return false;
                        }
                        else
                        {
                                bFailWithAttack = true;
                        }
                }
        }
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/

        if (getDomainType() == DOMAIN_AIR)
        {
                if (bAttack && !bFailWithAttack)
                {
                        if (!canAirStrike(pPlot))
                        {
                                if ( !bIgnoreAttack || bFailWithoutAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithAttack = true;
                                }
                        }
                }
        }
        else
        {
                if (canAttack())
                {
                        if (!isHuman() || (pPlot->isVisible(getTeam(), false)))
                        {
                                if ( bIgnoreAttack )
                                {
                                        if ( !bFailWithoutAttack )
                                        {
                                                if (!canCoexistWithEnemyUnit(NO_TEAM))
                                                {
                                                        if (pPlot->isVisibleEnemyUnit(this))
                                                        {
                                                                //FAssertMsg(isHuman() || (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack)), "hopefully not an issue, but tracking how often this is the case when we dont want to really declare war");
                                                                if (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE())))
                                                                {
                                                                        if ( bFailWithAttack )
                                                                        {
                                                                                return false;
                                                                        }

                                                                        bFailWithoutAttack = true;
                                                                }
                                                        }
                                                }
                                        }
                                        if ( !bFailWithAttack )
                                        {
                                                if (!pPlot->isVisibleEnemyUnit(this))
                                                {
                                                        //FAssertMsg(isHuman() || (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack)), "hopefully not an issue, but tracking how often this is the case when we dont want to really declare war");
                                                        if (!bDeclareWar || (!pPlot->isVisibleOtherUnit(getOwnerINLINE()) && !(pPlot->getPlotCity() && !isNoCapture())))
                                                        {
                                                                if ( bFailWithoutAttack )
                                                                {
                                                                        return false;
                                                                }

                                                                bFailWithAttack = true;
                                                        }
                                                }
                                        }
                                }
                                else if (bAttack || !canCoexistWithEnemyUnit(NO_TEAM))
                                {
                                        if (pPlot->isVisibleEnemyUnit(this) != bAttack)
                                        //if ((pPlot->isVisibleEnemyUnit(this) || pPlot->isEnemyCity(*this)) != bAttack)
                                        {
                                                //FAssertMsg(isHuman() || (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack)), "hopefully not an issue, but tracking how often this is the case when we dont want to really declare war");
                                                if (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack && !(bAttack && pPlot->getPlotCity() && !isNoCapture())))
                                                {
                                                        return false;
                                                }
                                        }
                                }
                        }

                        if (bAttack && !bFailWithAttack)
                        {
                                CvUnit* pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
                                if (NULL != pDefender)
                                {
                                        if (!canAttack(*pDefender))
                                        {
                                                if ( !bIgnoreAttack || bFailWithoutAttack )
                                                {
                                                        return false;
                                                }
                                                else
                                                {
                                                        bFailWithAttack = true;
                                                }
                                        }
                                }
                        }
                }
                else
                {
                        if (bAttack && !bFailWithAttack)
                        {
                                if ( !bIgnoreAttack || bFailWithoutAttack )
                                {
                                        return false;
                                }
                                else
                                {
                                        bFailWithAttack = true;
                                }
                        }

                        if (!canCoexistWithEnemyUnit(NO_TEAM))
                        {
                                if (!isHuman() || pPlot->isVisible(getTeam(), false))
                                {
                                        if (pPlot->isEnemyCity(*this))
                                        {