Das ist die Situation, schon seit einigen Klicks:
Stack:
Code:
> CvGameCoreDLL.dll!CvUnitAI::AI_doAttackRangedMove() Zeile 21214 C++
CvGameCoreDLL.dll!CvUnitAI::AI_attackRangedMove() Zeile 8535 + 0x8 Bytes C++
CvGameCoreDLL.dll!CvUnitAI::AI_update() Zeile 408 C++
CvGameCoreDLL.dll!CvSelectionGroupAI::AI_update() Zeile 275 + 0x13 Bytes C++
CvGameCoreDLL.dll!CvPlayerAI::AI_unitUpdate() Zeile 1478 + 0xd Bytes C++
CvGameCoreDLL.dll!CvGame::updateMoves() Zeile 6677 + 0x13 Bytes C++
CvGameCoreDLL.dll!CvGame::update() Zeile 2093 C++
Civ4BeyondSword.exe!00415321()
[Unten angegebene Rahmen sind möglicherweise nicht korrekt und/oder fehlen, keine Symbole geladen für Civ4BeyondSword.exe]
KernelBase.dll!7605af2b()
Civ4BeyondSword.exe!004d6f46()
Civ4BeyondSword.exe!008f497f()
kernel32.dll!76b5338a()
ntdll.dll!77229f72()
ntdll.dll!77229f45()
Civ4BeyondSword.exe!00790074()
Civ4BeyondSword.exe!00790074()
Civ4BeyondSword.exe!0078006f()
Civ4BeyondSword.exe!0078006f()
Civ4BeyondSword.exe!0078006f()
Civ4BeyondSword.exe!0078006f()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0069006c()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0064005f()
Civ4BeyondSword.exe!0064005f()
Civ4BeyondSword.exe!0075006c()
Civ4BeyondSword.exe!0075006c()
Civ4BeyondSword.exe!0075006c()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0073005f()
Civ4BeyondSword.exe!0073005f()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064002e()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0064006e()
Civ4BeyondSword.exe!0064006e()
Code:
bool CvUnitAI::AI_doAttackRangedMove()
{
PROFILE_FUNC();
CvUnit* pDefender;
CvPlot* pLoopPlot;
CvPlot* pBestPlot;
int iDamage;
int iValue;
int iBestValue;
int iDX, iDY;
// Only search around base
int iSearchRange = m_pUnitInfo->getAirRange();
iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (15 * m_pUnitInfo->getProductionCost()) : 0;
pBestPlot = NULL;
for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
{
for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if ( canRangeStrikeAt( plot() ,iDX,iDY) )//Wird mehrfach pro Unit geprüft, genau genommen: 9 x
{
if (pLoopPlot != NULL)
{
iValue = 0;
pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
if(pDefender != NULL)
{
FAssert(pDefender->canDefend());
iDamage = airCombatDamage(pDefender);//Wird nie aufgerufen, vermutlich, da keine Ziele in Reichweise sind
iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));
iValue += ((iDamage * collateralDamage()) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / (2*100);
// Weight towards stronger units
iValue *= (pDefender->currCombatStr(NULL,NULL,NULL) + 2000);
iValue /= 2000;
if( plot()->area() == pLoopPlot->area() )
{
iValue *= 5;
iValue /= 3;
}
// Weight towards adjacent stacks
if( plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) == 1 )
{
iValue *= 5;
iValue /= 4;
}
if (iValue > iBestValue)
{
iBestValue = iValue;
pBestPlot = pLoopPlot;
FAssert(!atPlot(pBestPlot));
}
}
}
}
}
}
if (pBestPlot != NULL)
{
FAssert(!atPlot(pBestPlot));
getGroup()->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());//Wird auch nicht aufgerufen
return true;
}
return false;//Kommt wie erwartet regelmäßig, da die Einheit keine Ziele erhält.
}
Code:
void CvUnitAI::AI_attackRangedMove()
{
PROFILE_FUNC();
/********************************************************************************/
/* BETTER_BTS_AI_MOD 10/21/08 Solver & jdog5000 */
/* */
/* Air AI */
/********************************************************************************/
// Check for direct threat to current base
// if (plot()->isCity(true))
if( getDamage() < 40 )
{
// Attack the invaders!
if (AI_doAttackRangedMove())
{
return;
}
}
getGroup()->pushMission(MISSION_SKIP);//Wird natürlich auch jedes mal aufgerufen
return;
}
Code:
bool CvUnitAI::AI_update()
{
PROFILE_FUNC();
CvUnit* pTransportUnit;
FAssertMsg(canMove(), "canMove is expected to be true");
FAssertMsg(isGroupHead(), "isGroupHead is expected to be true"); // XXX is this a good idea???
// allow python to handle it
CyUnit* pyUnit = new CyUnit(this);
CyArgsList argsList;
argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit)); // pass in unit class
long lResult=0;
gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_unitUpdate", argsList.makeFunctionArgs(), &lResult);
delete pyUnit; // python fxn must not hold on to this pointer
if (lResult == 1)
{
return false;
}
if (getDomainType() == DOMAIN_LAND)
{
if (plot()->isWater() && !canMoveAllTerrain())
{
getGroup()->pushMission(MISSION_SKIP);
return false;
}
else
{
pTransportUnit = getTransportUnit();
if (pTransportUnit != NULL)
{
if (pTransportUnit->getGroup()->hasMoved() || (pTransportUnit->getGroup()->headMissionQueueNode() != NULL))
{
getGroup()->pushMission(MISSION_SKIP);
return false;
}
}
}
}
if (AI_afterAttack())
{
return false;
}
if (getGroup()->isAutomated())
{
switch (getGroup()->getAutomateType())
{
case AUTOMATE_BUILD:
if (AI_getUnitAIType() == UNITAI_WORKER)
{
AI_workerMove();
}
else if (AI_getUnitAIType() == UNITAI_WORKER_SEA)
{
AI_workerSeaMove();
}
else
{
FAssert(false);
}
break;
case AUTOMATE_NETWORK:
AI_networkAutomated();
// XXX else wake up???
break;
case AUTOMATE_CITY:
AI_cityAutomated();
// XXX else wake up???
break;
case AUTOMATE_EXPLORE:
switch (getDomainType())
{
case DOMAIN_SEA:
AI_exploreSeaMove();
break;
case DOMAIN_AIR:
// if we are cargo (on a carrier), hold if the carrier is not done moving yet
pTransportUnit = getTransportUnit();
if (pTransportUnit != NULL)
{
if (pTransportUnit->isAutomated() && pTransportUnit->canMove() && pTransportUnit->getGroup()->getActivityType() != ACTIVITY_HOLD)
{
getGroup()->pushMission(MISSION_SKIP);
break;
}
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD 01/12/09 jdog5000 */
/* */
/* Player Interface */
/************************************************************************************************/
// Have air units explore like AI units do
AI_exploreAirMove();
/************************************************************************************************/
/* BETTER_BTS_AI_MOD END */
/************************************************************************************************/
break;
case DOMAIN_LAND:
AI_exploreMove();
break;
default:
FAssert(false);
break;
}
// if we have air cargo (we are a carrier), and we done moving, explore with the aircraft as well
if (hasCargo() && domainCargo() == DOMAIN_AIR && (!canMove() || getGroup()->getActivityType() == ACTIVITY_HOLD))
{
std::vector<CvUnit*> aCargoUnits;
getCargoUnits(aCargoUnits);
for (uint i = 0; i < aCargoUnits.size() && isAutomated(); ++i)
{
CvUnit* pCargoUnit = aCargoUnits[i];
if (pCargoUnit->getDomainType() == DOMAIN_AIR)
{
if (pCargoUnit->canMove())
{
pCargoUnit->getGroup()->setAutomateType(AUTOMATE_EXPLORE);
pCargoUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
}
}
}
}
break;
case AUTOMATE_RELIGION:
if (AI_getUnitAIType() == UNITAI_MISSIONARY)
{
AI_missionaryMove();
}
break;
/************************************************************************************************/
/* Afforess/RevDCM Start 09/16/10 */
/* */
/* Advanced Automations */
/************************************************************************************************/
case AUTOMATE_ESPIONAGE:
AI_autoEspionage();
break;
/************************************************************************************************/
/* Afforess/RevDCM END */
/************************************************************************************************/
default:
FAssert(false);
break;
}
// if no longer automated, then we want to bail
return !getGroup()->isAutomated();
}
else
{
switch (AI_getUnitAIType())
{
case UNITAI_UNKNOWN:
getGroup()->pushMission(MISSION_SKIP);
break;
case UNITAI_ANIMAL:
AI_animalMove();
break;
case UNITAI_SETTLE:
AI_settleMove();
break;
case UNITAI_WORKER:
AI_workerMove();
break;
case UNITAI_ATTACK:
if (isBarbarian())
{
AI_barbAttackMove();
}
else
{
AI_attackMove();
}
break;
case UNITAI_ATTACK_CITY:
AI_attackCityMove();
break;
case UNITAI_COLLATERAL:
AI_collateralMove();
break;
case UNITAI_PILLAGE:
AI_pillageMove();
break;
case UNITAI_RESERVE:
AI_reserveMove();
break;
case UNITAI_COUNTER:
AI_counterMove();
break;
case UNITAI_PARADROP:
AI_paratrooperMove();
break;
case UNITAI_CITY_DEFENSE:
AI_cityDefenseMove();
break;
case UNITAI_CITY_COUNTER:
case UNITAI_CITY_SPECIAL:
AI_cityDefenseExtraMove();
break;
case UNITAI_EXPLORE:
AI_exploreMove();
break;
case UNITAI_MISSIONARY:
AI_missionaryMove();
break;
case UNITAI_PROPHET:
AI_prophetMove();
break;
case UNITAI_ARTIST:
AI_artistMove();
break;
case UNITAI_SCIENTIST:
AI_scientistMove();
break;
case UNITAI_GENERAL:
AI_generalMove();
break;
case UNITAI_MERCHANT:
AI_merchantMove();
break;
case UNITAI_ENGINEER:
AI_engineerMove();
break;
case UNITAI_SPY:
AI_spyMove();
break;
case UNITAI_ICBM:
AI_ICBMMove();
break;
case UNITAI_WORKER_SEA:
AI_workerSeaMove();
break;
case UNITAI_ATTACK_SEA:
if (isBarbarian())
{
AI_barbAttackSeaMove();
}
else
{
AI_attackSeaMove();
}
break;
case UNITAI_RESERVE_SEA:
AI_reserveSeaMove();
break;
case UNITAI_ESCORT_SEA:
AI_escortSeaMove();
break;
case UNITAI_EXPLORE_SEA:
AI_exploreSeaMove();
break;
case UNITAI_ASSAULT_SEA:
AI_assaultSeaMove();
break;
case UNITAI_SETTLER_SEA:
AI_settlerSeaMove();
break;
case UNITAI_MISSIONARY_SEA:
AI_missionarySeaMove();
break;
case UNITAI_SPY_SEA:
AI_spySeaMove();
break;
case UNITAI_CARRIER_SEA:
AI_carrierSeaMove();
break;
case UNITAI_MISSILE_CARRIER_SEA:
AI_missileCarrierSeaMove();
break;
case UNITAI_PIRATE_SEA:
AI_pirateSeaMove();
break;
case UNITAI_ATTACK_AIR:
AI_attackAirMove();
break;
case UNITAI_RANGED_ATTACK:
AI_attackRangedMove();//Damit wird das ganze da oben ausgelöst
break;
case UNITAI_DEFENSE_AIR:
AI_defenseAirMove();
break;
case UNITAI_CARRIER_AIR:
AI_carrierAirMove();
break;
case UNITAI_MISSILE_AIR:
AI_missileAirMove();
break;
case UNITAI_ATTACK_CITY_LEMMING:
AI_attackCityLemmingMove();
break;
default:
FAssert(false);
break;
}
}
return false;
}
Zeile 4:
Code:
bool CvSelectionGroupAI::AI_update()
{
CLLNode<IDInfo>* pEntityNode;
CvUnit* pLoopUnit;
bool bDead;
bool bFollow;
PROFILE("CvSelectionGroupAI::AI_update");
FAssert(getOwnerINLINE() != NO_PLAYER);
if (!AI_isControlled())
{
return false;
}
if (getNumUnits() == 0)
{
return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD 04/28/10 jdog5000 */
/* */
/* Unit AI */
/************************************************************************************************/
if( !(isHuman()) && !(getHeadUnit()->isCargo()) && getActivityType() == ACTIVITY_SLEEP )
{
setForceUpdate(true);
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD END */
/************************************************************************************************/
if (isForceUpdate())
{
clearMissionQueue(); // XXX ???
setActivityType(ACTIVITY_AWAKE);
setForceUpdate(false);
// if we are in the middle of attacking with a stack, cancel it
AI_cancelGroupAttack();
}
FAssert(!(GET_PLAYER(getOwnerINLINE()).isAutoMoves()));
int iTempHack = 0; // XXX
bDead = false;
bool bFailedAlreadyFighting = false;
while ((m_bGroupAttack && !bFailedAlreadyFighting) || readyToMove())
{
iTempHack++;
if (iTempHack > 100)
{
FAssert(false);
CvUnit* pHeadUnit = getHeadUnit();
if (NULL != pHeadUnit)
{
if (GC.getLogging())
{
TCHAR szOut[1024];
CvWString szTempString;
getUnitAIString(szTempString, pHeadUnit->AI_getUnitAIType());
sprintf(szOut, "Unit stuck in loop: %S(%S)[%d, %d] (%S)\n", pHeadUnit->getName().GetCString(), GET_PLAYER(pHeadUnit->getOwnerINLINE()).getName(),
pHeadUnit->getX_INLINE(), pHeadUnit->getY_INLINE(), szTempString.GetCString());
gDLL->messageControlLog(szOut);
}
pHeadUnit->finishMoves();
}
break;
}
// if we want to force the group to attack, force another attack
if (m_bGroupAttack)
{
m_bGroupAttack = false;
groupAttack(m_iGroupAttackX, m_iGroupAttackY, MOVE_DIRECT_ATTACK, bFailedAlreadyFighting);
}
// else pick AI action
else
{
CvUnit* pHeadUnit = getHeadUnit();
if (pHeadUnit == NULL || pHeadUnit->isDelayedDeath())
{
break;
}
resetPath();
if (pHeadUnit->AI_update())// Darüber scheinen wir nicht hinaus zu kommen
{
// AI_update returns true when we should abort the loop and wait until next slice
break;
}
}
if (doDelayedDeath())
{
bDead = true;
break;
}
// if no longer group attacking, and force separate is true, then bail, decide what to do after group is split up
// (UnitAI of head unit may have changed)
if (!m_bGroupAttack && AI_isForceSeparate())
{
AI_separate(); // pointers could become invalid...
return true;
}
}
Code:
void CvPlayerAI::AI_unitUpdate()
{
PROFILE_FUNC();
CLLNode<int>* pCurrUnitNode;
CvSelectionGroup* pLoopSelectionGroup;
CLinkList<int> tempGroupCycle;
CLinkList<int> finalGroupCycle;
int iValue;
if (!hasBusyUnit())
{
pCurrUnitNode = headGroupCycleNode();
while (pCurrUnitNode != NULL)
{
pLoopSelectionGroup = getSelectionGroup(pCurrUnitNode->m_data);
pCurrUnitNode = nextGroupCycleNode(pCurrUnitNode);
if (pLoopSelectionGroup->AI_isForceSeparate())
{
// do not split groups that are in the midst of attacking
if (pLoopSelectionGroup->isForceUpdate() || !pLoopSelectionGroup->AI_isGroupAttack())
{
pLoopSelectionGroup->AI_separate(); // pointers could become invalid...
}
}
}
if (isHuman())
{
pCurrUnitNode = headGroupCycleNode();
while (pCurrUnitNode != NULL)
{
pLoopSelectionGroup = getSelectionGroup(pCurrUnitNode->m_data);
pCurrUnitNode = nextGroupCycleNode(pCurrUnitNode);
if (pLoopSelectionGroup->AI_update())
{
break; // pointers could become invalid...
}
}
}
else
{
tempGroupCycle.clear();
finalGroupCycle.clear();
pCurrUnitNode = headGroupCycleNode();
while (pCurrUnitNode != NULL)
{
tempGroupCycle.insertAtEnd(pCurrUnitNode->m_data);
pCurrUnitNode = nextGroupCycleNode(pCurrUnitNode);
}
iValue = 0;
while (tempGroupCycle.getLength() > 0)
{
pCurrUnitNode = tempGroupCycle.head();
while (pCurrUnitNode != NULL)
{
pLoopSelectionGroup = getSelectionGroup(pCurrUnitNode->m_data);
FAssertMsg(pLoopSelectionGroup != NULL, "selection group node with NULL selection group");
if (AI_movementPriority(pLoopSelectionGroup) <= iValue)
{
finalGroupCycle.insertAtEnd(pCurrUnitNode->m_data);
pCurrUnitNode = tempGroupCycle.deleteNode(pCurrUnitNode);
}
else
{
pCurrUnitNode = tempGroupCycle.next(pCurrUnitNode);
}
}
iValue++;
}
pCurrUnitNode = finalGroupCycle.head();
while (pCurrUnitNode != NULL)
{
pLoopSelectionGroup = getSelectionGroup(pCurrUnitNode->m_data);
if (NULL != pLoopSelectionGroup) // group might have been killed by a previous group update
{
if (pLoopSelectionGroup->AI_update())
{
break; // pointers could become invalid... // neuste Erkenntnis: Dieser Punkt wird nie erreicht! Ist das gut oder schlecht?
}
}
pCurrUnitNode = finalGroupCycle.next(pCurrUnitNode);
}
}
}
}